xref: /linux/drivers/scsi/libiscsi.c (revision f474a37bc48667595b5653a983b635c95ed82a3b)
17996a778SMike Christie /*
27996a778SMike Christie  * iSCSI lib functions
37996a778SMike Christie  *
47996a778SMike Christie  * Copyright (C) 2006 Red Hat, Inc.  All rights reserved.
57996a778SMike Christie  * Copyright (C) 2004 - 2006 Mike Christie
67996a778SMike Christie  * Copyright (C) 2004 - 2005 Dmitry Yusupov
77996a778SMike Christie  * Copyright (C) 2004 - 2005 Alex Aizman
87996a778SMike Christie  * maintained by open-iscsi@googlegroups.com
97996a778SMike Christie  *
107996a778SMike Christie  * This program is free software; you can redistribute it and/or modify
117996a778SMike Christie  * it under the terms of the GNU General Public License as published by
127996a778SMike Christie  * the Free Software Foundation; either version 2 of the License, or
137996a778SMike Christie  * (at your option) any later version.
147996a778SMike Christie  *
157996a778SMike Christie  * This program is distributed in the hope that it will be useful,
167996a778SMike Christie  * but WITHOUT ANY WARRANTY; without even the implied warranty of
177996a778SMike Christie  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
187996a778SMike Christie  * GNU General Public License for more details.
197996a778SMike Christie  *
207996a778SMike Christie  * You should have received a copy of the GNU General Public License
217996a778SMike Christie  * along with this program; if not, write to the Free Software
227996a778SMike Christie  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
237996a778SMike Christie  */
247996a778SMike Christie #include <linux/types.h>
257996a778SMike Christie #include <linux/kfifo.h>
267996a778SMike Christie #include <linux/delay.h>
2711836572Svignesh babu #include <linux/log2.h>
288eb00539SMike Christie #include <asm/unaligned.h>
297996a778SMike Christie #include <net/tcp.h>
307996a778SMike Christie #include <scsi/scsi_cmnd.h>
317996a778SMike Christie #include <scsi/scsi_device.h>
327996a778SMike Christie #include <scsi/scsi_eh.h>
337996a778SMike Christie #include <scsi/scsi_tcq.h>
347996a778SMike Christie #include <scsi/scsi_host.h>
357996a778SMike Christie #include <scsi/scsi.h>
367996a778SMike Christie #include <scsi/iscsi_proto.h>
377996a778SMike Christie #include <scsi/scsi_transport.h>
387996a778SMike Christie #include <scsi/scsi_transport_iscsi.h>
397996a778SMike Christie #include <scsi/libiscsi.h>
407996a778SMike Christie 
4177a23c21SMike Christie /* Serial Number Arithmetic, 32 bits, less than, RFC1982 */
4277a23c21SMike Christie #define SNA32_CHECK 2147483648UL
437996a778SMike Christie 
4477a23c21SMike Christie static int iscsi_sna_lt(u32 n1, u32 n2)
4577a23c21SMike Christie {
4677a23c21SMike Christie 	return n1 != n2 && ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) ||
4777a23c21SMike Christie 			    (n1 > n2 && (n2 - n1 < SNA32_CHECK)));
4877a23c21SMike Christie }
4977a23c21SMike Christie 
5077a23c21SMike Christie /* Serial Number Arithmetic, 32 bits, less than, RFC1982 */
5177a23c21SMike Christie static int iscsi_sna_lte(u32 n1, u32 n2)
5277a23c21SMike Christie {
5377a23c21SMike Christie 	return n1 == n2 || ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) ||
5477a23c21SMike Christie 			    (n1 > n2 && (n2 - n1 < SNA32_CHECK)));
5577a23c21SMike Christie }
5677a23c21SMike Christie 
5777a23c21SMike Christie void
5877a23c21SMike Christie iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
597996a778SMike Christie {
607996a778SMike Christie 	uint32_t max_cmdsn = be32_to_cpu(hdr->max_cmdsn);
617996a778SMike Christie 	uint32_t exp_cmdsn = be32_to_cpu(hdr->exp_cmdsn);
627996a778SMike Christie 
6377a23c21SMike Christie 	/*
6477a23c21SMike Christie 	 * standard specifies this check for when to update expected and
6577a23c21SMike Christie 	 * max sequence numbers
6677a23c21SMike Christie 	 */
6777a23c21SMike Christie 	if (iscsi_sna_lt(max_cmdsn, exp_cmdsn - 1))
6877a23c21SMike Christie 		return;
6977a23c21SMike Christie 
7077a23c21SMike Christie 	if (exp_cmdsn != session->exp_cmdsn &&
7177a23c21SMike Christie 	    !iscsi_sna_lt(exp_cmdsn, session->exp_cmdsn))
727996a778SMike Christie 		session->exp_cmdsn = exp_cmdsn;
737996a778SMike Christie 
7477a23c21SMike Christie 	if (max_cmdsn != session->max_cmdsn &&
7577a23c21SMike Christie 	    !iscsi_sna_lt(max_cmdsn, session->max_cmdsn)) {
7677a23c21SMike Christie 		session->max_cmdsn = max_cmdsn;
7777a23c21SMike Christie 		/*
7877a23c21SMike Christie 		 * if the window closed with IO queued, then kick the
7977a23c21SMike Christie 		 * xmit thread
8077a23c21SMike Christie 		 */
8177a23c21SMike Christie 		if (!list_empty(&session->leadconn->xmitqueue) ||
82052d0144SMike Christie 		    !list_empty(&session->leadconn->mgmtqueue)) {
83052d0144SMike Christie 			if (!(session->tt->caps & CAP_DATA_PATH_OFFLOAD))
8477a23c21SMike Christie 				scsi_queue_work(session->host,
8577a23c21SMike Christie 						&session->leadconn->xmitwork);
867996a778SMike Christie 		}
8777a23c21SMike Christie 	}
88052d0144SMike Christie }
8977a23c21SMike Christie EXPORT_SYMBOL_GPL(iscsi_update_cmdsn);
907996a778SMike Christie 
91577577daSMike Christie /**
92577577daSMike Christie  * iscsi_prep_data_out_pdu - initialize Data-Out
93577577daSMike Christie  * @task: scsi command task
94577577daSMike Christie  * @r2t: R2T info
95577577daSMike Christie  * @hdr: iscsi data in pdu
96577577daSMike Christie  *
97577577daSMike Christie  * Notes:
98577577daSMike Christie  *	Initialize Data-Out within this R2T sequence and finds
99577577daSMike Christie  *	proper data_offset within this SCSI command.
100577577daSMike Christie  *
101577577daSMike Christie  *	This function is called with connection lock taken.
102577577daSMike Christie  **/
103577577daSMike Christie void iscsi_prep_data_out_pdu(struct iscsi_task *task, struct iscsi_r2t_info *r2t,
104ffd0436eSMike Christie 			   struct iscsi_data *hdr)
1057996a778SMike Christie {
1069c19a7d0SMike Christie 	struct iscsi_conn *conn = task->conn;
107577577daSMike Christie 	unsigned int left = r2t->data_length - r2t->sent;
108577577daSMike Christie 
109577577daSMike Christie 	task->hdr_len = sizeof(struct iscsi_data);
1107996a778SMike Christie 
1117996a778SMike Christie 	memset(hdr, 0, sizeof(struct iscsi_data));
112577577daSMike Christie 	hdr->ttt = r2t->ttt;
113577577daSMike Christie 	hdr->datasn = cpu_to_be32(r2t->datasn);
114577577daSMike Christie 	r2t->datasn++;
1157996a778SMike Christie 	hdr->opcode = ISCSI_OP_SCSI_DATA_OUT;
116577577daSMike Christie 	memcpy(hdr->lun, task->lun, sizeof(hdr->lun));
117577577daSMike Christie 	hdr->itt = task->hdr_itt;
118577577daSMike Christie 	hdr->exp_statsn = r2t->exp_statsn;
119577577daSMike Christie 	hdr->offset = cpu_to_be32(r2t->data_offset + r2t->sent);
120577577daSMike Christie 	if (left > conn->max_xmit_dlength) {
1217996a778SMike Christie 		hton24(hdr->dlength, conn->max_xmit_dlength);
122577577daSMike Christie 		r2t->data_count = conn->max_xmit_dlength;
1237996a778SMike Christie 		hdr->flags = 0;
1247996a778SMike Christie 	} else {
125577577daSMike Christie 		hton24(hdr->dlength, left);
126577577daSMike Christie 		r2t->data_count = left;
1277996a778SMike Christie 		hdr->flags = ISCSI_FLAG_CMD_FINAL;
1287996a778SMike Christie 	}
129577577daSMike Christie 	conn->dataout_pdus_cnt++;
1307996a778SMike Christie }
131577577daSMike Christie EXPORT_SYMBOL_GPL(iscsi_prep_data_out_pdu);
1327996a778SMike Christie 
1339c19a7d0SMike Christie static int iscsi_add_hdr(struct iscsi_task *task, unsigned len)
134004d6530SBoaz Harrosh {
1359c19a7d0SMike Christie 	unsigned exp_len = task->hdr_len + len;
136004d6530SBoaz Harrosh 
1379c19a7d0SMike Christie 	if (exp_len > task->hdr_max) {
138004d6530SBoaz Harrosh 		WARN_ON(1);
139004d6530SBoaz Harrosh 		return -EINVAL;
140004d6530SBoaz Harrosh 	}
141004d6530SBoaz Harrosh 
142004d6530SBoaz Harrosh 	WARN_ON(len & (ISCSI_PAD_LEN - 1)); /* caller must pad the AHS */
1439c19a7d0SMike Christie 	task->hdr_len = exp_len;
144004d6530SBoaz Harrosh 	return 0;
145004d6530SBoaz Harrosh }
146004d6530SBoaz Harrosh 
14738d1c069SBoaz Harrosh /*
14838d1c069SBoaz Harrosh  * make an extended cdb AHS
14938d1c069SBoaz Harrosh  */
1509c19a7d0SMike Christie static int iscsi_prep_ecdb_ahs(struct iscsi_task *task)
15138d1c069SBoaz Harrosh {
1529c19a7d0SMike Christie 	struct scsi_cmnd *cmd = task->sc;
15338d1c069SBoaz Harrosh 	unsigned rlen, pad_len;
15438d1c069SBoaz Harrosh 	unsigned short ahslength;
15538d1c069SBoaz Harrosh 	struct iscsi_ecdb_ahdr *ecdb_ahdr;
15638d1c069SBoaz Harrosh 	int rc;
15738d1c069SBoaz Harrosh 
1589c19a7d0SMike Christie 	ecdb_ahdr = iscsi_next_hdr(task);
15938d1c069SBoaz Harrosh 	rlen = cmd->cmd_len - ISCSI_CDB_SIZE;
16038d1c069SBoaz Harrosh 
16138d1c069SBoaz Harrosh 	BUG_ON(rlen > sizeof(ecdb_ahdr->ecdb));
16238d1c069SBoaz Harrosh 	ahslength = rlen + sizeof(ecdb_ahdr->reserved);
16338d1c069SBoaz Harrosh 
16438d1c069SBoaz Harrosh 	pad_len = iscsi_padding(rlen);
16538d1c069SBoaz Harrosh 
1669c19a7d0SMike Christie 	rc = iscsi_add_hdr(task, sizeof(ecdb_ahdr->ahslength) +
16738d1c069SBoaz Harrosh 	                   sizeof(ecdb_ahdr->ahstype) + ahslength + pad_len);
16838d1c069SBoaz Harrosh 	if (rc)
16938d1c069SBoaz Harrosh 		return rc;
17038d1c069SBoaz Harrosh 
17138d1c069SBoaz Harrosh 	if (pad_len)
17238d1c069SBoaz Harrosh 		memset(&ecdb_ahdr->ecdb[rlen], 0, pad_len);
17338d1c069SBoaz Harrosh 
17438d1c069SBoaz Harrosh 	ecdb_ahdr->ahslength = cpu_to_be16(ahslength);
17538d1c069SBoaz Harrosh 	ecdb_ahdr->ahstype = ISCSI_AHSTYPE_CDB;
17638d1c069SBoaz Harrosh 	ecdb_ahdr->reserved = 0;
17738d1c069SBoaz Harrosh 	memcpy(ecdb_ahdr->ecdb, cmd->cmnd + ISCSI_CDB_SIZE, rlen);
17838d1c069SBoaz Harrosh 
17938d1c069SBoaz Harrosh 	debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d "
18038d1c069SBoaz Harrosh 		   "rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n",
1819c19a7d0SMike Christie 		   cmd->cmd_len, rlen, pad_len, ahslength, task->hdr_len);
18238d1c069SBoaz Harrosh 
18338d1c069SBoaz Harrosh 	return 0;
18438d1c069SBoaz Harrosh }
18538d1c069SBoaz Harrosh 
1869c19a7d0SMike Christie static int iscsi_prep_bidi_ahs(struct iscsi_task *task)
187c07d4444SBoaz Harrosh {
1889c19a7d0SMike Christie 	struct scsi_cmnd *sc = task->sc;
189c07d4444SBoaz Harrosh 	struct iscsi_rlength_ahdr *rlen_ahdr;
190c07d4444SBoaz Harrosh 	int rc;
191c07d4444SBoaz Harrosh 
1929c19a7d0SMike Christie 	rlen_ahdr = iscsi_next_hdr(task);
1939c19a7d0SMike Christie 	rc = iscsi_add_hdr(task, sizeof(*rlen_ahdr));
194c07d4444SBoaz Harrosh 	if (rc)
195c07d4444SBoaz Harrosh 		return rc;
196c07d4444SBoaz Harrosh 
197c07d4444SBoaz Harrosh 	rlen_ahdr->ahslength =
198c07d4444SBoaz Harrosh 		cpu_to_be16(sizeof(rlen_ahdr->read_length) +
199c07d4444SBoaz Harrosh 						  sizeof(rlen_ahdr->reserved));
200c07d4444SBoaz Harrosh 	rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
201c07d4444SBoaz Harrosh 	rlen_ahdr->reserved = 0;
202c07d4444SBoaz Harrosh 	rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
203c07d4444SBoaz Harrosh 
204c07d4444SBoaz Harrosh 	debug_scsi("bidi-in rlen_ahdr->read_length(%d) "
205c07d4444SBoaz Harrosh 		   "rlen_ahdr->ahslength(%d)\n",
206c07d4444SBoaz Harrosh 		   be32_to_cpu(rlen_ahdr->read_length),
207c07d4444SBoaz Harrosh 		   be16_to_cpu(rlen_ahdr->ahslength));
208c07d4444SBoaz Harrosh 	return 0;
209c07d4444SBoaz Harrosh }
210c07d4444SBoaz Harrosh 
2117996a778SMike Christie /**
2127996a778SMike Christie  * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
2139c19a7d0SMike Christie  * @task: iscsi task
2147996a778SMike Christie  *
2157996a778SMike Christie  * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set
2167996a778SMike Christie  * fields like dlength or final based on how much data it sends
2177996a778SMike Christie  */
2189c19a7d0SMike Christie static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
2197996a778SMike Christie {
2209c19a7d0SMike Christie 	struct iscsi_conn *conn = task->conn;
2217996a778SMike Christie 	struct iscsi_session *session = conn->session;
2229c19a7d0SMike Christie 	struct scsi_cmnd *sc = task->sc;
223577577daSMike Christie 	struct iscsi_cmd *hdr;
22438d1c069SBoaz Harrosh 	unsigned hdrlength, cmd_len;
225262ef636SMike Christie 	itt_t itt;
226004d6530SBoaz Harrosh 	int rc;
2277996a778SMike Christie 
2282ff79d52SMike Christie 	rc = conn->session->tt->alloc_pdu(task, ISCSI_OP_SCSI_CMD);
229577577daSMike Christie 	if (rc)
230577577daSMike Christie 		return rc;
231577577daSMike Christie 	hdr = (struct iscsi_cmd *) task->hdr;
232262ef636SMike Christie 	itt = hdr->itt;
233577577daSMike Christie 	memset(hdr, 0, sizeof(*hdr));
234577577daSMike Christie 
2352ff79d52SMike Christie 	if (session->tt->parse_pdu_itt)
2362ff79d52SMike Christie 		hdr->itt = task->hdr_itt = itt;
2372ff79d52SMike Christie 	else
2382ff79d52SMike Christie 		hdr->itt = task->hdr_itt = build_itt(task->itt,
2392ff79d52SMike Christie 						     task->conn->session->age);
2409c19a7d0SMike Christie 	task->hdr_len = 0;
2419c19a7d0SMike Christie 	rc = iscsi_add_hdr(task, sizeof(*hdr));
242004d6530SBoaz Harrosh 	if (rc)
243004d6530SBoaz Harrosh 		return rc;
2447996a778SMike Christie 	hdr->opcode = ISCSI_OP_SCSI_CMD;
2457996a778SMike Christie 	hdr->flags = ISCSI_ATTR_SIMPLE;
2467996a778SMike Christie 	int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
247577577daSMike Christie 	memcpy(task->lun, hdr->lun, sizeof(task->lun));
248577577daSMike Christie 	hdr->cmdsn = task->cmdsn = cpu_to_be32(session->cmdsn);
2497996a778SMike Christie 	session->cmdsn++;
2507996a778SMike Christie 	hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
25138d1c069SBoaz Harrosh 	cmd_len = sc->cmd_len;
25238d1c069SBoaz Harrosh 	if (cmd_len < ISCSI_CDB_SIZE)
25338d1c069SBoaz Harrosh 		memset(&hdr->cdb[cmd_len], 0, ISCSI_CDB_SIZE - cmd_len);
25438d1c069SBoaz Harrosh 	else if (cmd_len > ISCSI_CDB_SIZE) {
2559c19a7d0SMike Christie 		rc = iscsi_prep_ecdb_ahs(task);
25638d1c069SBoaz Harrosh 		if (rc)
25738d1c069SBoaz Harrosh 			return rc;
25838d1c069SBoaz Harrosh 		cmd_len = ISCSI_CDB_SIZE;
25938d1c069SBoaz Harrosh 	}
26038d1c069SBoaz Harrosh 	memcpy(hdr->cdb, sc->cmnd, cmd_len);
2617996a778SMike Christie 
2629c19a7d0SMike Christie 	task->imm_count = 0;
263c07d4444SBoaz Harrosh 	if (scsi_bidi_cmnd(sc)) {
264c07d4444SBoaz Harrosh 		hdr->flags |= ISCSI_FLAG_CMD_READ;
2659c19a7d0SMike Christie 		rc = iscsi_prep_bidi_ahs(task);
266c07d4444SBoaz Harrosh 		if (rc)
267c07d4444SBoaz Harrosh 			return rc;
268c07d4444SBoaz Harrosh 	}
2697996a778SMike Christie 	if (sc->sc_data_direction == DMA_TO_DEVICE) {
270c07d4444SBoaz Harrosh 		unsigned out_len = scsi_out(sc)->length;
271577577daSMike Christie 		struct iscsi_r2t_info *r2t = &task->unsol_r2t;
272577577daSMike Christie 
273c07d4444SBoaz Harrosh 		hdr->data_length = cpu_to_be32(out_len);
2747996a778SMike Christie 		hdr->flags |= ISCSI_FLAG_CMD_WRITE;
2757996a778SMike Christie 		/*
2767996a778SMike Christie 		 * Write counters:
2777996a778SMike Christie 		 *
2787996a778SMike Christie 		 *	imm_count	bytes to be sent right after
2797996a778SMike Christie 		 *			SCSI PDU Header
2807996a778SMike Christie 		 *
2817996a778SMike Christie 		 *	unsol_count	bytes(as Data-Out) to be sent
2827996a778SMike Christie 		 *			without	R2T ack right after
2837996a778SMike Christie 		 *			immediate data
2847996a778SMike Christie 		 *
285577577daSMike Christie 		 *	r2t data_length bytes to be sent via R2T ack's
2867996a778SMike Christie 		 *
2877996a778SMike Christie 		 *      pad_count       bytes to be sent as zero-padding
2887996a778SMike Christie 		 */
289577577daSMike Christie 		memset(r2t, 0, sizeof(*r2t));
2907996a778SMike Christie 
2917996a778SMike Christie 		if (session->imm_data_en) {
292c07d4444SBoaz Harrosh 			if (out_len >= session->first_burst)
2939c19a7d0SMike Christie 				task->imm_count = min(session->first_burst,
2947996a778SMike Christie 							conn->max_xmit_dlength);
2957996a778SMike Christie 			else
2969c19a7d0SMike Christie 				task->imm_count = min(out_len,
2977996a778SMike Christie 							conn->max_xmit_dlength);
2989c19a7d0SMike Christie 			hton24(hdr->dlength, task->imm_count);
2997996a778SMike Christie 		} else
300a8ac6311SOlaf Kirch 			zero_data(hdr->dlength);
3017996a778SMike Christie 
302ffd0436eSMike Christie 		if (!session->initial_r2t_en) {
303577577daSMike Christie 			r2t->data_length = min(session->first_burst, out_len) -
304577577daSMike Christie 					       task->imm_count;
305577577daSMike Christie 			r2t->data_offset = task->imm_count;
306577577daSMike Christie 			r2t->ttt = cpu_to_be32(ISCSI_RESERVED_TAG);
307577577daSMike Christie 			r2t->exp_statsn = cpu_to_be32(conn->exp_statsn);
308ffd0436eSMike Christie 		}
309ffd0436eSMike Christie 
310577577daSMike Christie 		if (!task->unsol_r2t.data_length)
3117996a778SMike Christie 			/* No unsolicit Data-Out's */
312a8ac6311SOlaf Kirch 			hdr->flags |= ISCSI_FLAG_CMD_FINAL;
3137996a778SMike Christie 	} else {
3147996a778SMike Christie 		hdr->flags |= ISCSI_FLAG_CMD_FINAL;
3157996a778SMike Christie 		zero_data(hdr->dlength);
316c07d4444SBoaz Harrosh 		hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
3177996a778SMike Christie 
3187996a778SMike Christie 		if (sc->sc_data_direction == DMA_FROM_DEVICE)
3197996a778SMike Christie 			hdr->flags |= ISCSI_FLAG_CMD_READ;
3207996a778SMike Christie 	}
3217996a778SMike Christie 
322004d6530SBoaz Harrosh 	/* calculate size of additional header segments (AHSs) */
3239c19a7d0SMike Christie 	hdrlength = task->hdr_len - sizeof(*hdr);
324004d6530SBoaz Harrosh 
325004d6530SBoaz Harrosh 	WARN_ON(hdrlength & (ISCSI_PAD_LEN-1));
326004d6530SBoaz Harrosh 	hdrlength /= ISCSI_PAD_LEN;
327004d6530SBoaz Harrosh 
328004d6530SBoaz Harrosh 	WARN_ON(hdrlength >= 256);
329004d6530SBoaz Harrosh 	hdr->hlength = hdrlength & 0xFF;
330004d6530SBoaz Harrosh 
331577577daSMike Christie 	if (session->tt->init_task && session->tt->init_task(task))
332052d0144SMike Christie 		return -EIO;
333052d0144SMike Christie 
3349c19a7d0SMike Christie 	task->state = ISCSI_TASK_RUNNING;
3359c19a7d0SMike Christie 	list_move_tail(&task->running, &conn->run_list);
33677a23c21SMike Christie 
337a8ac6311SOlaf Kirch 	conn->scsicmd_pdus_cnt++;
3383e5c28adSMike Christie 	debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
3393e5c28adSMike Christie 		   "bidi_len %d cmdsn %d win %d]\n", scsi_bidi_cmnd(sc) ?
3403e5c28adSMike Christie 		   "bidirectional" : sc->sc_data_direction == DMA_TO_DEVICE ?
3419c19a7d0SMike Christie 		   "write" : "read", conn->id, sc, sc->cmnd[0], task->itt,
3423e5c28adSMike Christie 		   scsi_bufflen(sc),
3433e5c28adSMike Christie 		   scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
34477a23c21SMike Christie 		   session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
345004d6530SBoaz Harrosh 	return 0;
3467996a778SMike Christie }
3477996a778SMike Christie 
3487996a778SMike Christie /**
3493e5c28adSMike Christie  * iscsi_complete_command - finish a task
3509c19a7d0SMike Christie  * @task: iscsi cmd task
3517996a778SMike Christie  *
3527996a778SMike Christie  * Must be called with session lock.
3533e5c28adSMike Christie  * This function returns the scsi command to scsi-ml or cleans
3543e5c28adSMike Christie  * up mgmt tasks then returns the task to the pool.
3557996a778SMike Christie  */
3569c19a7d0SMike Christie static void iscsi_complete_command(struct iscsi_task *task)
3577996a778SMike Christie {
3589c19a7d0SMike Christie 	struct iscsi_conn *conn = task->conn;
359c1635cb7SMike Christie 	struct iscsi_session *session = conn->session;
3609c19a7d0SMike Christie 	struct scsi_cmnd *sc = task->sc;
3617996a778SMike Christie 
362577577daSMike Christie 	session->tt->cleanup_task(task);
3639c19a7d0SMike Christie 	list_del_init(&task->running);
3649c19a7d0SMike Christie 	task->state = ISCSI_TASK_COMPLETED;
3659c19a7d0SMike Christie 	task->sc = NULL;
3663e5c28adSMike Christie 
3679c19a7d0SMike Christie 	if (conn->task == task)
3689c19a7d0SMike Christie 		conn->task = NULL;
3693e5c28adSMike Christie 	/*
3709c19a7d0SMike Christie 	 * login task is preallocated so do not free
3713e5c28adSMike Christie 	 */
3729c19a7d0SMike Christie 	if (conn->login_task == task)
3733e5c28adSMike Christie 		return;
3743e5c28adSMike Christie 
3759c19a7d0SMike Christie 	__kfifo_put(session->cmdpool.queue, (void*)&task, sizeof(void*));
3763e5c28adSMike Christie 
3779c19a7d0SMike Christie 	if (conn->ping_task == task)
3789c19a7d0SMike Christie 		conn->ping_task = NULL;
3793e5c28adSMike Christie 
3803e5c28adSMike Christie 	if (sc) {
3819c19a7d0SMike Christie 		task->sc = NULL;
382f47f2cf5SMike Christie 		/* SCSI eh reuses commands to verify us */
383f47f2cf5SMike Christie 		sc->SCp.ptr = NULL;
3843e5c28adSMike Christie 		/*
3853e5c28adSMike Christie 		 * queue command may call this to free the task, but
3863e5c28adSMike Christie 		 * not have setup the sc callback
3873e5c28adSMike Christie 		 */
388052d0144SMike Christie 		if (sc->scsi_done)
3897996a778SMike Christie 			sc->scsi_done(sc);
3907996a778SMike Christie 	}
3913e5c28adSMike Christie }
3927996a778SMike Christie 
393913e5bf4SMike Christie void __iscsi_get_task(struct iscsi_task *task)
39460ecebf5SMike Christie {
3959c19a7d0SMike Christie 	atomic_inc(&task->refcount);
39660ecebf5SMike Christie }
397913e5bf4SMike Christie EXPORT_SYMBOL_GPL(__iscsi_get_task);
39860ecebf5SMike Christie 
3999c19a7d0SMike Christie static void __iscsi_put_task(struct iscsi_task *task)
40060ecebf5SMike Christie {
4019c19a7d0SMike Christie 	if (atomic_dec_and_test(&task->refcount))
4029c19a7d0SMike Christie 		iscsi_complete_command(task);
40360ecebf5SMike Christie }
40460ecebf5SMike Christie 
4059c19a7d0SMike Christie void iscsi_put_task(struct iscsi_task *task)
4063e5c28adSMike Christie {
4079c19a7d0SMike Christie 	struct iscsi_session *session = task->conn->session;
4083e5c28adSMike Christie 
4093e5c28adSMike Christie 	spin_lock_bh(&session->lock);
4109c19a7d0SMike Christie 	__iscsi_put_task(task);
4113e5c28adSMike Christie 	spin_unlock_bh(&session->lock);
4123e5c28adSMike Christie }
4139c19a7d0SMike Christie EXPORT_SYMBOL_GPL(iscsi_put_task);
4143e5c28adSMike Christie 
415b3a7ea8dSMike Christie /*
416b3a7ea8dSMike Christie  * session lock must be held
417b3a7ea8dSMike Christie  */
4189c19a7d0SMike Christie static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task,
419b3a7ea8dSMike Christie 			 int err)
420b3a7ea8dSMike Christie {
421b3a7ea8dSMike Christie 	struct scsi_cmnd *sc;
422b3a7ea8dSMike Christie 
4239c19a7d0SMike Christie 	sc = task->sc;
424b3a7ea8dSMike Christie 	if (!sc)
425b3a7ea8dSMike Christie 		return;
426b3a7ea8dSMike Christie 
4279c19a7d0SMike Christie 	if (task->state == ISCSI_TASK_PENDING)
428b3a7ea8dSMike Christie 		/*
429b3a7ea8dSMike Christie 		 * cmd never made it to the xmit thread, so we should not count
430b3a7ea8dSMike Christie 		 * the cmd in the sequencing
431b3a7ea8dSMike Christie 		 */
432b3a7ea8dSMike Christie 		conn->session->queued_cmdsn--;
433b3a7ea8dSMike Christie 
434b3a7ea8dSMike Christie 	sc->result = err;
435c07d4444SBoaz Harrosh 	if (!scsi_bidi_cmnd(sc))
436b3a7ea8dSMike Christie 		scsi_set_resid(sc, scsi_bufflen(sc));
437c07d4444SBoaz Harrosh 	else {
438c07d4444SBoaz Harrosh 		scsi_out(sc)->resid = scsi_out(sc)->length;
439c07d4444SBoaz Harrosh 		scsi_in(sc)->resid = scsi_in(sc)->length;
440c07d4444SBoaz Harrosh 	}
4413e5c28adSMike Christie 
4429c19a7d0SMike Christie 	if (conn->task == task)
4439c19a7d0SMike Christie 		conn->task = NULL;
444b3a7ea8dSMike Christie 	/* release ref from queuecommand */
4459c19a7d0SMike Christie 	__iscsi_put_task(task);
446b3a7ea8dSMike Christie }
447b3a7ea8dSMike Christie 
4483e5c28adSMike Christie static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
4499c19a7d0SMike Christie 				struct iscsi_task *task)
450052d0144SMike Christie {
451052d0144SMike Christie 	struct iscsi_session *session = conn->session;
452577577daSMike Christie 	struct iscsi_hdr *hdr = task->hdr;
453052d0144SMike Christie 	struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr;
454052d0144SMike Christie 
455052d0144SMike Christie 	if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
456052d0144SMike Christie 		return -ENOTCONN;
457052d0144SMike Christie 
458052d0144SMike Christie 	if (hdr->opcode != (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) &&
459052d0144SMike Christie 	    hdr->opcode != (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
460052d0144SMike Christie 		nop->exp_statsn = cpu_to_be32(conn->exp_statsn);
461052d0144SMike Christie 	/*
462052d0144SMike Christie 	 * pre-format CmdSN for outgoing PDU.
463052d0144SMike Christie 	 */
464052d0144SMike Christie 	nop->cmdsn = cpu_to_be32(session->cmdsn);
465052d0144SMike Christie 	if (hdr->itt != RESERVED_ITT) {
466052d0144SMike Christie 		/*
467052d0144SMike Christie 		 * TODO: We always use immediate, so we never hit this.
468052d0144SMike Christie 		 * If we start to send tmfs or nops as non-immediate then
469052d0144SMike Christie 		 * we should start checking the cmdsn numbers for mgmt tasks.
470052d0144SMike Christie 		 */
471052d0144SMike Christie 		if (conn->c_stage == ISCSI_CONN_STARTED &&
472052d0144SMike Christie 		    !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
473052d0144SMike Christie 			session->queued_cmdsn++;
474052d0144SMike Christie 			session->cmdsn++;
475052d0144SMike Christie 		}
476052d0144SMike Christie 	}
477052d0144SMike Christie 
478ae15f801SMike Christie 	if (session->tt->init_task && session->tt->init_task(task))
479ae15f801SMike Christie 		return -EIO;
480052d0144SMike Christie 
481052d0144SMike Christie 	if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT)
482052d0144SMike Christie 		session->state = ISCSI_STATE_LOGGING_OUT;
483052d0144SMike Christie 
484577577daSMike Christie 	task->state = ISCSI_TASK_RUNNING;
4859c19a7d0SMike Christie 	list_move_tail(&task->running, &conn->mgmt_run_list);
486052d0144SMike Christie 	debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n",
487052d0144SMike Christie 		   hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt,
4889c19a7d0SMike Christie 		   task->data_count);
489052d0144SMike Christie 	return 0;
490052d0144SMike Christie }
491052d0144SMike Christie 
4929c19a7d0SMike Christie static struct iscsi_task *
493f6d5180cSMike Christie __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
494f6d5180cSMike Christie 		      char *data, uint32_t data_size)
495f6d5180cSMike Christie {
496f6d5180cSMike Christie 	struct iscsi_session *session = conn->session;
4979c19a7d0SMike Christie 	struct iscsi_task *task;
498262ef636SMike Christie 	itt_t itt;
499f6d5180cSMike Christie 
500f6d5180cSMike Christie 	if (session->state == ISCSI_STATE_TERMINATE)
501f6d5180cSMike Christie 		return NULL;
502f6d5180cSMike Christie 
503f6d5180cSMike Christie 	if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) ||
504f6d5180cSMike Christie 	    hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
505f6d5180cSMike Christie 		/*
506f6d5180cSMike Christie 		 * Login and Text are sent serially, in
507f6d5180cSMike Christie 		 * request-followed-by-response sequence.
5083e5c28adSMike Christie 		 * Same task can be used. Same ITT must be used.
5093e5c28adSMike Christie 		 * Note that login_task is preallocated at conn_create().
510f6d5180cSMike Christie 		 */
5119c19a7d0SMike Christie 		task = conn->login_task;
512f6d5180cSMike Christie 	else {
513f6d5180cSMike Christie 		BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
514f6d5180cSMike Christie 		BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
515f6d5180cSMike Christie 
5163e5c28adSMike Christie 		if (!__kfifo_get(session->cmdpool.queue,
5179c19a7d0SMike Christie 				 (void*)&task, sizeof(void*)))
518f6d5180cSMike Christie 			return NULL;
519f6d5180cSMike Christie 	}
5203e5c28adSMike Christie 	/*
5213e5c28adSMike Christie 	 * released in complete pdu for task we expect a response for, and
5223e5c28adSMike Christie 	 * released by the lld when it has transmitted the task for
5233e5c28adSMike Christie 	 * pdus we do not expect a response for.
5243e5c28adSMike Christie 	 */
5259c19a7d0SMike Christie 	atomic_set(&task->refcount, 1);
5269c19a7d0SMike Christie 	task->conn = conn;
5279c19a7d0SMike Christie 	task->sc = NULL;
528f6d5180cSMike Christie 
529f6d5180cSMike Christie 	if (data_size) {
5309c19a7d0SMike Christie 		memcpy(task->data, data, data_size);
5319c19a7d0SMike Christie 		task->data_count = data_size;
532f6d5180cSMike Christie 	} else
5339c19a7d0SMike Christie 		task->data_count = 0;
534f6d5180cSMike Christie 
5352ff79d52SMike Christie 	if (conn->session->tt->alloc_pdu(task, hdr->opcode)) {
536577577daSMike Christie 		iscsi_conn_printk(KERN_ERR, conn, "Could not allocate "
537577577daSMike Christie 				 "pdu for mgmt task.\n");
538577577daSMike Christie 		goto requeue_task;
539577577daSMike Christie 	}
540262ef636SMike Christie 	itt = task->hdr->itt;
541577577daSMike Christie 	task->hdr_len = sizeof(struct iscsi_hdr);
5429c19a7d0SMike Christie 	memcpy(task->hdr, hdr, sizeof(struct iscsi_hdr));
543262ef636SMike Christie 
544262ef636SMike Christie 	if (hdr->itt != RESERVED_ITT) {
545262ef636SMike Christie 		if (session->tt->parse_pdu_itt)
546262ef636SMike Christie 			task->hdr->itt = itt;
547262ef636SMike Christie 		else
548262ef636SMike Christie 			task->hdr->itt = build_itt(task->itt,
549262ef636SMike Christie 						   task->conn->session->age);
550262ef636SMike Christie 	}
551262ef636SMike Christie 
5529c19a7d0SMike Christie 	INIT_LIST_HEAD(&task->running);
5539c19a7d0SMike Christie 	list_add_tail(&task->running, &conn->mgmtqueue);
554052d0144SMike Christie 
555052d0144SMike Christie 	if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) {
556577577daSMike Christie 		if (iscsi_prep_mgmt_task(conn, task))
557577577daSMike Christie 			goto free_task;
558052d0144SMike Christie 
5599c19a7d0SMike Christie 		if (session->tt->xmit_task(task))
560577577daSMike Christie 			goto free_task;
561052d0144SMike Christie 
562052d0144SMike Christie 	} else
563052d0144SMike Christie 		scsi_queue_work(conn->session->host, &conn->xmitwork);
564052d0144SMike Christie 
5659c19a7d0SMike Christie 	return task;
566577577daSMike Christie 
567577577daSMike Christie free_task:
568577577daSMike Christie 	__iscsi_put_task(task);
569577577daSMike Christie 	return NULL;
570577577daSMike Christie 
571577577daSMike Christie requeue_task:
572577577daSMike Christie 	if (task != conn->login_task)
573577577daSMike Christie 		__kfifo_put(session->cmdpool.queue, (void*)&task,
574577577daSMike Christie 			    sizeof(void*));
575577577daSMike Christie 	return NULL;
576f6d5180cSMike Christie }
577f6d5180cSMike Christie 
578f6d5180cSMike Christie int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
579f6d5180cSMike Christie 			char *data, uint32_t data_size)
580f6d5180cSMike Christie {
581f6d5180cSMike Christie 	struct iscsi_conn *conn = cls_conn->dd_data;
582f6d5180cSMike Christie 	struct iscsi_session *session = conn->session;
583f6d5180cSMike Christie 	int err = 0;
584f6d5180cSMike Christie 
585f6d5180cSMike Christie 	spin_lock_bh(&session->lock);
586f6d5180cSMike Christie 	if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
587f6d5180cSMike Christie 		err = -EPERM;
588f6d5180cSMike Christie 	spin_unlock_bh(&session->lock);
589f6d5180cSMike Christie 	return err;
590f6d5180cSMike Christie }
591f6d5180cSMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
592f6d5180cSMike Christie 
5937996a778SMike Christie /**
5947996a778SMike Christie  * iscsi_cmd_rsp - SCSI Command Response processing
5957996a778SMike Christie  * @conn: iscsi connection
5967996a778SMike Christie  * @hdr: iscsi header
5979c19a7d0SMike Christie  * @task: scsi command task
5987996a778SMike Christie  * @data: cmd data buffer
5997996a778SMike Christie  * @datalen: len of buffer
6007996a778SMike Christie  *
6017996a778SMike Christie  * iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and
6029c19a7d0SMike Christie  * then completes the command and task.
6037996a778SMike Christie  **/
60477a23c21SMike Christie static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
6059c19a7d0SMike Christie 			       struct iscsi_task *task, char *data,
6067996a778SMike Christie 			       int datalen)
6077996a778SMike Christie {
6087996a778SMike Christie 	struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr;
6097996a778SMike Christie 	struct iscsi_session *session = conn->session;
6109c19a7d0SMike Christie 	struct scsi_cmnd *sc = task->sc;
6117996a778SMike Christie 
61277a23c21SMike Christie 	iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
6137996a778SMike Christie 	conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
6147996a778SMike Christie 
6157996a778SMike Christie 	sc->result = (DID_OK << 16) | rhdr->cmd_status;
6167996a778SMike Christie 
6177996a778SMike Christie 	if (rhdr->response != ISCSI_STATUS_CMD_COMPLETED) {
6187996a778SMike Christie 		sc->result = DID_ERROR << 16;
6197996a778SMike Christie 		goto out;
6207996a778SMike Christie 	}
6217996a778SMike Christie 
6227996a778SMike Christie 	if (rhdr->cmd_status == SAM_STAT_CHECK_CONDITION) {
6239b80cb4bSMike Christie 		uint16_t senselen;
6247996a778SMike Christie 
6257996a778SMike Christie 		if (datalen < 2) {
6267996a778SMike Christie invalid_datalen:
627322d739dSMike Christie 			iscsi_conn_printk(KERN_ERR,  conn,
628322d739dSMike Christie 					 "Got CHECK_CONDITION but invalid data "
629322d739dSMike Christie 					 "buffer size of %d\n", datalen);
6307996a778SMike Christie 			sc->result = DID_BAD_TARGET << 16;
6317996a778SMike Christie 			goto out;
6327996a778SMike Christie 		}
6337996a778SMike Christie 
6348f333991SHarvey Harrison 		senselen = get_unaligned_be16(data);
6357996a778SMike Christie 		if (datalen < senselen)
6367996a778SMike Christie 			goto invalid_datalen;
6377996a778SMike Christie 
6387996a778SMike Christie 		memcpy(sc->sense_buffer, data + 2,
6399b80cb4bSMike Christie 		       min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
6407996a778SMike Christie 		debug_scsi("copied %d bytes of sense\n",
6418eb00539SMike Christie 			   min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
6427996a778SMike Christie 	}
6437996a778SMike Christie 
644c07d4444SBoaz Harrosh 	if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
645c07d4444SBoaz Harrosh 			   ISCSI_FLAG_CMD_BIDI_OVERFLOW)) {
646c07d4444SBoaz Harrosh 		int res_count = be32_to_cpu(rhdr->bi_residual_count);
647c07d4444SBoaz Harrosh 
648c07d4444SBoaz Harrosh 		if (scsi_bidi_cmnd(sc) && res_count > 0 &&
649c07d4444SBoaz Harrosh 				(rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW ||
650c07d4444SBoaz Harrosh 				 res_count <= scsi_in(sc)->length))
651c07d4444SBoaz Harrosh 			scsi_in(sc)->resid = res_count;
652c07d4444SBoaz Harrosh 		else
653c07d4444SBoaz Harrosh 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
654c07d4444SBoaz Harrosh 	}
655c07d4444SBoaz Harrosh 
6567207fea4SBoaz Harrosh 	if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW |
6577207fea4SBoaz Harrosh 	                   ISCSI_FLAG_CMD_OVERFLOW)) {
6587996a778SMike Christie 		int res_count = be32_to_cpu(rhdr->residual_count);
6597996a778SMike Christie 
6607207fea4SBoaz Harrosh 		if (res_count > 0 &&
6617207fea4SBoaz Harrosh 		    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
6627207fea4SBoaz Harrosh 		     res_count <= scsi_bufflen(sc)))
663c07d4444SBoaz Harrosh 			/* write side for bidi or uni-io set_resid */
6641c138991SFUJITA Tomonori 			scsi_set_resid(sc, res_count);
6657996a778SMike Christie 		else
6667996a778SMike Christie 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
667c07d4444SBoaz Harrosh 	}
6687996a778SMike Christie out:
6697996a778SMike Christie 	debug_scsi("done [sc %lx res %d itt 0x%x]\n",
6709c19a7d0SMike Christie 		   (long)sc, sc->result, task->itt);
6717996a778SMike Christie 	conn->scsirsp_pdus_cnt++;
6727996a778SMike Christie 
6739c19a7d0SMike Christie 	__iscsi_put_task(task);
6747996a778SMike Christie }
6757996a778SMike Christie 
6761d9edf02SMike Christie /**
6771d9edf02SMike Christie  * iscsi_data_in_rsp - SCSI Data-In Response processing
6781d9edf02SMike Christie  * @conn: iscsi connection
6791d9edf02SMike Christie  * @hdr:  iscsi pdu
6801d9edf02SMike Christie  * @task: scsi command task
6811d9edf02SMike Christie  **/
6821d9edf02SMike Christie static void
6831d9edf02SMike Christie iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
6841d9edf02SMike Christie 		  struct iscsi_task *task)
6851d9edf02SMike Christie {
6861d9edf02SMike Christie 	struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)hdr;
6871d9edf02SMike Christie 	struct scsi_cmnd *sc = task->sc;
6881d9edf02SMike Christie 
6891d9edf02SMike Christie 	if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS))
6901d9edf02SMike Christie 		return;
6911d9edf02SMike Christie 
6921d9edf02SMike Christie 	sc->result = (DID_OK << 16) | rhdr->cmd_status;
6931d9edf02SMike Christie 	conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
6941d9edf02SMike Christie 	if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW |
6951d9edf02SMike Christie 	                   ISCSI_FLAG_DATA_OVERFLOW)) {
6961d9edf02SMike Christie 		int res_count = be32_to_cpu(rhdr->residual_count);
6971d9edf02SMike Christie 
6981d9edf02SMike Christie 		if (res_count > 0 &&
6991d9edf02SMike Christie 		    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
7001d9edf02SMike Christie 		     res_count <= scsi_in(sc)->length))
7011d9edf02SMike Christie 			scsi_in(sc)->resid = res_count;
7021d9edf02SMike Christie 		else
7031d9edf02SMike Christie 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
7041d9edf02SMike Christie 	}
7051d9edf02SMike Christie 
7061d9edf02SMike Christie 	conn->scsirsp_pdus_cnt++;
7071d9edf02SMike Christie 	__iscsi_put_task(task);
7081d9edf02SMike Christie }
7091d9edf02SMike Christie 
7107ea8b828SMike Christie static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
7117ea8b828SMike Christie {
7127ea8b828SMike Christie 	struct iscsi_tm_rsp *tmf = (struct iscsi_tm_rsp *)hdr;
7137ea8b828SMike Christie 
7147ea8b828SMike Christie 	conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
7157ea8b828SMike Christie 	conn->tmfrsp_pdus_cnt++;
7167ea8b828SMike Christie 
717843c0a8aSMike Christie 	if (conn->tmf_state != TMF_QUEUED)
7187ea8b828SMike Christie 		return;
7197ea8b828SMike Christie 
7207ea8b828SMike Christie 	if (tmf->response == ISCSI_TMF_RSP_COMPLETE)
721843c0a8aSMike Christie 		conn->tmf_state = TMF_SUCCESS;
7227ea8b828SMike Christie 	else if (tmf->response == ISCSI_TMF_RSP_NO_TASK)
723843c0a8aSMike Christie 		conn->tmf_state = TMF_NOT_FOUND;
7247ea8b828SMike Christie 	else
725843c0a8aSMike Christie 		conn->tmf_state = TMF_FAILED;
7267ea8b828SMike Christie 	wake_up(&conn->ehwait);
7277ea8b828SMike Christie }
7287ea8b828SMike Christie 
729f6d5180cSMike Christie static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
730f6d5180cSMike Christie {
731f6d5180cSMike Christie         struct iscsi_nopout hdr;
7329c19a7d0SMike Christie 	struct iscsi_task *task;
733f6d5180cSMike Christie 
7349c19a7d0SMike Christie 	if (!rhdr && conn->ping_task)
735f6d5180cSMike Christie 		return;
736f6d5180cSMike Christie 
737f6d5180cSMike Christie 	memset(&hdr, 0, sizeof(struct iscsi_nopout));
738f6d5180cSMike Christie 	hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
739f6d5180cSMike Christie 	hdr.flags = ISCSI_FLAG_CMD_FINAL;
740f6d5180cSMike Christie 
741f6d5180cSMike Christie 	if (rhdr) {
742f6d5180cSMike Christie 		memcpy(hdr.lun, rhdr->lun, 8);
743f6d5180cSMike Christie 		hdr.ttt = rhdr->ttt;
744f6d5180cSMike Christie 		hdr.itt = RESERVED_ITT;
745f6d5180cSMike Christie 	} else
746f6d5180cSMike Christie 		hdr.ttt = RESERVED_ITT;
747f6d5180cSMike Christie 
7489c19a7d0SMike Christie 	task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
7499c19a7d0SMike Christie 	if (!task)
750322d739dSMike Christie 		iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n");
751d3acf022SMike Christie 	else if (!rhdr) {
752d3acf022SMike Christie 		/* only track our nops */
753d3acf022SMike Christie 		conn->ping_task = task;
754d3acf022SMike Christie 		conn->last_ping = jiffies;
755d3acf022SMike Christie 	}
756f6d5180cSMike Christie }
757f6d5180cSMike Christie 
75862f38300SMike Christie static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
75962f38300SMike Christie 			       char *data, int datalen)
76062f38300SMike Christie {
76162f38300SMike Christie 	struct iscsi_reject *reject = (struct iscsi_reject *)hdr;
76262f38300SMike Christie 	struct iscsi_hdr rejected_pdu;
76362f38300SMike Christie 
76462f38300SMike Christie 	conn->exp_statsn = be32_to_cpu(reject->statsn) + 1;
76562f38300SMike Christie 
76662f38300SMike Christie 	if (reject->reason == ISCSI_REASON_DATA_DIGEST_ERROR) {
76762f38300SMike Christie 		if (ntoh24(reject->dlength) > datalen)
76862f38300SMike Christie 			return ISCSI_ERR_PROTO;
76962f38300SMike Christie 
77062f38300SMike Christie 		if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) {
77162f38300SMike Christie 			memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
772322d739dSMike Christie 			iscsi_conn_printk(KERN_ERR, conn,
773262ef636SMike Christie 					  "pdu (op 0x%x) rejected "
774262ef636SMike Christie 					  "due to DataDigest error.\n",
77562f38300SMike Christie 					  rejected_pdu.opcode);
77662f38300SMike Christie 		}
77762f38300SMike Christie 	}
77862f38300SMike Christie 	return 0;
77962f38300SMike Christie }
78062f38300SMike Christie 
7817996a778SMike Christie /**
782913e5bf4SMike Christie  * iscsi_itt_to_task - look up task by itt
783913e5bf4SMike Christie  * @conn: iscsi connection
784913e5bf4SMike Christie  * @itt: itt
785913e5bf4SMike Christie  *
786913e5bf4SMike Christie  * This should be used for mgmt tasks like login and nops, or if
787913e5bf4SMike Christie  * the LDD's itt space does not include the session age.
788913e5bf4SMike Christie  *
789913e5bf4SMike Christie  * The session lock must be held.
790913e5bf4SMike Christie  */
791913e5bf4SMike Christie static struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
792913e5bf4SMike Christie {
793913e5bf4SMike Christie 	struct iscsi_session *session = conn->session;
794262ef636SMike Christie 	int i;
795913e5bf4SMike Christie 
796913e5bf4SMike Christie 	if (itt == RESERVED_ITT)
797913e5bf4SMike Christie 		return NULL;
798913e5bf4SMike Christie 
799262ef636SMike Christie 	if (session->tt->parse_pdu_itt)
800262ef636SMike Christie 		session->tt->parse_pdu_itt(conn, itt, &i, NULL);
801262ef636SMike Christie 	else
802913e5bf4SMike Christie 		i = get_itt(itt);
803913e5bf4SMike Christie 	if (i >= session->cmds_max)
804913e5bf4SMike Christie 		return NULL;
805913e5bf4SMike Christie 
806913e5bf4SMike Christie 	return session->cmds[i];
807913e5bf4SMike Christie }
808913e5bf4SMike Christie 
809913e5bf4SMike Christie /**
8107996a778SMike Christie  * __iscsi_complete_pdu - complete pdu
8117996a778SMike Christie  * @conn: iscsi conn
8127996a778SMike Christie  * @hdr: iscsi header
8137996a778SMike Christie  * @data: data buffer
8147996a778SMike Christie  * @datalen: len of data buffer
8157996a778SMike Christie  *
8167996a778SMike Christie  * Completes pdu processing by freeing any resources allocated at
8177996a778SMike Christie  * queuecommand or send generic. session lock must be held and verify
8187996a778SMike Christie  * itt must have been called.
8197996a778SMike Christie  */
820913e5bf4SMike Christie int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
8217996a778SMike Christie 			 char *data, int datalen)
8227996a778SMike Christie {
8237996a778SMike Christie 	struct iscsi_session *session = conn->session;
8247996a778SMike Christie 	int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0;
8259c19a7d0SMike Christie 	struct iscsi_task *task;
8267996a778SMike Christie 	uint32_t itt;
8277996a778SMike Christie 
828f6d5180cSMike Christie 	conn->last_recv = jiffies;
8290af967f5SMike Christie 	rc = iscsi_verify_itt(conn, hdr->itt);
8300af967f5SMike Christie 	if (rc)
8310af967f5SMike Christie 		return rc;
8320af967f5SMike Christie 
833b4377356SAl Viro 	if (hdr->itt != RESERVED_ITT)
834b4377356SAl Viro 		itt = get_itt(hdr->itt);
8357996a778SMike Christie 	else
836b4377356SAl Viro 		itt = ~0U;
8377996a778SMike Christie 
8383e5c28adSMike Christie 	debug_scsi("[op 0x%x cid %d itt 0x%x len %d]\n",
8393e5c28adSMike Christie 		   opcode, conn->id, itt, datalen);
8407996a778SMike Christie 
8413e5c28adSMike Christie 	if (itt == ~0U) {
84277a23c21SMike Christie 		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
84362f38300SMike Christie 
8447996a778SMike Christie 		switch(opcode) {
8457996a778SMike Christie 		case ISCSI_OP_NOOP_IN:
84640527afeSMike Christie 			if (datalen) {
84740527afeSMike Christie 				rc = ISCSI_ERR_PROTO;
84840527afeSMike Christie 				break;
84940527afeSMike Christie 			}
85040527afeSMike Christie 
851b4377356SAl Viro 			if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG))
85240527afeSMike Christie 				break;
85340527afeSMike Christie 
854f6d5180cSMike Christie 			iscsi_send_nopout(conn, (struct iscsi_nopin*)hdr);
8557996a778SMike Christie 			break;
8567996a778SMike Christie 		case ISCSI_OP_REJECT:
85762f38300SMike Christie 			rc = iscsi_handle_reject(conn, hdr, data, datalen);
85862f38300SMike Christie 			break;
8597996a778SMike Christie 		case ISCSI_OP_ASYNC_EVENT:
8608d2860b3SMike Christie 			conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
8615831c737SMike Christie 			if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
8625831c737SMike Christie 				rc = ISCSI_ERR_CONN_FAILED;
8637996a778SMike Christie 			break;
8647996a778SMike Christie 		default:
8657996a778SMike Christie 			rc = ISCSI_ERR_BAD_OPCODE;
8667996a778SMike Christie 			break;
8677996a778SMike Christie 		}
8683e5c28adSMike Christie 		goto out;
8693e5c28adSMike Christie 	}
8707996a778SMike Christie 
8713e5c28adSMike Christie 	switch(opcode) {
8723e5c28adSMike Christie 	case ISCSI_OP_SCSI_CMD_RSP:
873913e5bf4SMike Christie 	case ISCSI_OP_SCSI_DATA_IN:
874913e5bf4SMike Christie 		task = iscsi_itt_to_ctask(conn, hdr->itt);
875913e5bf4SMike Christie 		if (!task)
876913e5bf4SMike Christie 			return ISCSI_ERR_BAD_ITT;
8773e5c28adSMike Christie 		break;
878913e5bf4SMike Christie 	case ISCSI_OP_R2T:
879913e5bf4SMike Christie 		/*
880913e5bf4SMike Christie 		 * LLD handles R2Ts if they need to.
881913e5bf4SMike Christie 		 */
882913e5bf4SMike Christie 		return 0;
883913e5bf4SMike Christie 	case ISCSI_OP_LOGOUT_RSP:
884913e5bf4SMike Christie 	case ISCSI_OP_LOGIN_RSP:
885913e5bf4SMike Christie 	case ISCSI_OP_TEXT_RSP:
886913e5bf4SMike Christie 	case ISCSI_OP_SCSI_TMFUNC_RSP:
887913e5bf4SMike Christie 	case ISCSI_OP_NOOP_IN:
888913e5bf4SMike Christie 		task = iscsi_itt_to_task(conn, hdr->itt);
889913e5bf4SMike Christie 		if (!task)
890913e5bf4SMike Christie 			return ISCSI_ERR_BAD_ITT;
891913e5bf4SMike Christie 		break;
892913e5bf4SMike Christie 	default:
893913e5bf4SMike Christie 		return ISCSI_ERR_BAD_OPCODE;
8943e5c28adSMike Christie 	}
895913e5bf4SMike Christie 
896913e5bf4SMike Christie 	switch(opcode) {
897913e5bf4SMike Christie 	case ISCSI_OP_SCSI_CMD_RSP:
8989c19a7d0SMike Christie 		iscsi_scsi_cmd_rsp(conn, hdr, task, data, datalen);
8993e5c28adSMike Christie 		break;
9003e5c28adSMike Christie 	case ISCSI_OP_SCSI_DATA_IN:
9011d9edf02SMike Christie 		iscsi_data_in_rsp(conn, hdr, task);
9023e5c28adSMike Christie 		break;
9033e5c28adSMike Christie 	case ISCSI_OP_LOGOUT_RSP:
9043e5c28adSMike Christie 		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
9053e5c28adSMike Christie 		if (datalen) {
9063e5c28adSMike Christie 			rc = ISCSI_ERR_PROTO;
9073e5c28adSMike Christie 			break;
9083e5c28adSMike Christie 		}
9093e5c28adSMike Christie 		conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
9103e5c28adSMike Christie 		goto recv_pdu;
9113e5c28adSMike Christie 	case ISCSI_OP_LOGIN_RSP:
9123e5c28adSMike Christie 	case ISCSI_OP_TEXT_RSP:
9133e5c28adSMike Christie 		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
9143e5c28adSMike Christie 		/*
9153e5c28adSMike Christie 		 * login related PDU's exp_statsn is handled in
9163e5c28adSMike Christie 		 * userspace
9173e5c28adSMike Christie 		 */
9183e5c28adSMike Christie 		goto recv_pdu;
9193e5c28adSMike Christie 	case ISCSI_OP_SCSI_TMFUNC_RSP:
9203e5c28adSMike Christie 		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
9213e5c28adSMike Christie 		if (datalen) {
9223e5c28adSMike Christie 			rc = ISCSI_ERR_PROTO;
9233e5c28adSMike Christie 			break;
9243e5c28adSMike Christie 		}
9253e5c28adSMike Christie 
9263e5c28adSMike Christie 		iscsi_tmf_rsp(conn, hdr);
9279c19a7d0SMike Christie 		__iscsi_put_task(task);
9283e5c28adSMike Christie 		break;
9293e5c28adSMike Christie 	case ISCSI_OP_NOOP_IN:
9303e5c28adSMike Christie 		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
9313e5c28adSMike Christie 		if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) {
9323e5c28adSMike Christie 			rc = ISCSI_ERR_PROTO;
9333e5c28adSMike Christie 			break;
9343e5c28adSMike Christie 		}
9353e5c28adSMike Christie 		conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
9363e5c28adSMike Christie 
9379c19a7d0SMike Christie 		if (conn->ping_task != task)
9383e5c28adSMike Christie 			/*
9393e5c28adSMike Christie 			 * If this is not in response to one of our
9403e5c28adSMike Christie 			 * nops then it must be from userspace.
9413e5c28adSMike Christie 			 */
9423e5c28adSMike Christie 			goto recv_pdu;
9439c19a7d0SMike Christie 
9449c19a7d0SMike Christie 		mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout);
9459c19a7d0SMike Christie 		__iscsi_put_task(task);
9463e5c28adSMike Christie 		break;
9473e5c28adSMike Christie 	default:
9483e5c28adSMike Christie 		rc = ISCSI_ERR_BAD_OPCODE;
9493e5c28adSMike Christie 		break;
9503e5c28adSMike Christie 	}
9513e5c28adSMike Christie 
9523e5c28adSMike Christie out:
9533e5c28adSMike Christie 	return rc;
9543e5c28adSMike Christie recv_pdu:
9553e5c28adSMike Christie 	if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
9563e5c28adSMike Christie 		rc = ISCSI_ERR_CONN_FAILED;
9579c19a7d0SMike Christie 	__iscsi_put_task(task);
9587996a778SMike Christie 	return rc;
9597996a778SMike Christie }
960913e5bf4SMike Christie EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
9617996a778SMike Christie 
9627996a778SMike Christie int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
9637996a778SMike Christie 		       char *data, int datalen)
9647996a778SMike Christie {
9657996a778SMike Christie 	int rc;
9667996a778SMike Christie 
9677996a778SMike Christie 	spin_lock(&conn->session->lock);
9687996a778SMike Christie 	rc = __iscsi_complete_pdu(conn, hdr, data, datalen);
9697996a778SMike Christie 	spin_unlock(&conn->session->lock);
9707996a778SMike Christie 	return rc;
9717996a778SMike Christie }
9727996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_complete_pdu);
9737996a778SMike Christie 
9740af967f5SMike Christie int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt)
9757996a778SMike Christie {
9767996a778SMike Christie 	struct iscsi_session *session = conn->session;
977262ef636SMike Christie 	int age = 0, i = 0;
9787996a778SMike Christie 
9790af967f5SMike Christie 	if (itt == RESERVED_ITT)
9800af967f5SMike Christie 		return 0;
9810af967f5SMike Christie 
982262ef636SMike Christie 	if (session->tt->parse_pdu_itt)
983262ef636SMike Christie 		session->tt->parse_pdu_itt(conn, itt, &i, &age);
984262ef636SMike Christie 	else {
985262ef636SMike Christie 		i = get_itt(itt);
986262ef636SMike Christie 		age = ((__force u32)itt >> ISCSI_AGE_SHIFT) & ISCSI_AGE_MASK;
987262ef636SMike Christie 	}
988262ef636SMike Christie 
989262ef636SMike Christie 	if (age != session->age) {
990322d739dSMike Christie 		iscsi_conn_printk(KERN_ERR, conn,
9910af967f5SMike Christie 				  "received itt %x expected session age (%x)\n",
992913e5bf4SMike Christie 				  (__force u32)itt, session->age);
9937996a778SMike Christie 		return ISCSI_ERR_BAD_ITT;
9947996a778SMike Christie 	}
9957996a778SMike Christie 
9963e5c28adSMike Christie 	if (i >= session->cmds_max) {
9973e5c28adSMike Christie 		iscsi_conn_printk(KERN_ERR, conn,
9983e5c28adSMike Christie 				  "received invalid itt index %u (max cmds "
9993e5c28adSMike Christie 				   "%u.\n", i, session->cmds_max);
10003e5c28adSMike Christie 		return ISCSI_ERR_BAD_ITT;
10017996a778SMike Christie 	}
10027996a778SMike Christie 	return 0;
10037996a778SMike Christie }
10047996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_verify_itt);
10057996a778SMike Christie 
1006913e5bf4SMike Christie /**
1007913e5bf4SMike Christie  * iscsi_itt_to_ctask - look up ctask by itt
1008913e5bf4SMike Christie  * @conn: iscsi connection
1009913e5bf4SMike Christie  * @itt: itt
1010913e5bf4SMike Christie  *
1011913e5bf4SMike Christie  * This should be used for cmd tasks.
1012913e5bf4SMike Christie  *
1013913e5bf4SMike Christie  * The session lock must be held.
1014913e5bf4SMike Christie  */
1015913e5bf4SMike Christie struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt)
10160af967f5SMike Christie {
10179c19a7d0SMike Christie 	struct iscsi_task *task;
10180af967f5SMike Christie 
10190af967f5SMike Christie 	if (iscsi_verify_itt(conn, itt))
10200af967f5SMike Christie 		return NULL;
10210af967f5SMike Christie 
1022913e5bf4SMike Christie 	task = iscsi_itt_to_task(conn, itt);
1023913e5bf4SMike Christie 	if (!task || !task->sc)
10240af967f5SMike Christie 		return NULL;
10250af967f5SMike Christie 
1026913e5bf4SMike Christie 	if (task->sc->SCp.phase != conn->session->age) {
1027913e5bf4SMike Christie 		iscsi_session_printk(KERN_ERR, conn->session,
1028913e5bf4SMike Christie 				  "task's session age %d, expected %d\n",
1029913e5bf4SMike Christie 				  task->sc->SCp.phase, conn->session->age);
10300af967f5SMike Christie 		return NULL;
1031913e5bf4SMike Christie 	}
10320af967f5SMike Christie 
10339c19a7d0SMike Christie 	return task;
10340af967f5SMike Christie }
10350af967f5SMike Christie EXPORT_SYMBOL_GPL(iscsi_itt_to_ctask);
10360af967f5SMike Christie 
1037e5bd7b54SMike Christie void iscsi_session_failure(struct iscsi_cls_session *cls_session,
1038e5bd7b54SMike Christie 			   enum iscsi_err err)
1039e5bd7b54SMike Christie {
1040e5bd7b54SMike Christie 	struct iscsi_session *session = cls_session->dd_data;
1041e5bd7b54SMike Christie 	struct iscsi_conn *conn;
1042e5bd7b54SMike Christie 	struct device *dev;
1043e5bd7b54SMike Christie 	unsigned long flags;
1044e5bd7b54SMike Christie 
1045e5bd7b54SMike Christie 	spin_lock_irqsave(&session->lock, flags);
1046e5bd7b54SMike Christie 	conn = session->leadconn;
1047e5bd7b54SMike Christie 	if (session->state == ISCSI_STATE_TERMINATE || !conn) {
1048e5bd7b54SMike Christie 		spin_unlock_irqrestore(&session->lock, flags);
1049e5bd7b54SMike Christie 		return;
1050e5bd7b54SMike Christie 	}
1051e5bd7b54SMike Christie 
1052e5bd7b54SMike Christie 	dev = get_device(&conn->cls_conn->dev);
1053e5bd7b54SMike Christie 	spin_unlock_irqrestore(&session->lock, flags);
1054e5bd7b54SMike Christie 	if (!dev)
1055e5bd7b54SMike Christie 	        return;
1056e5bd7b54SMike Christie 	/*
1057e5bd7b54SMike Christie 	 * if the host is being removed bypass the connection
1058e5bd7b54SMike Christie 	 * recovery initialization because we are going to kill
1059e5bd7b54SMike Christie 	 * the session.
1060e5bd7b54SMike Christie 	 */
1061e5bd7b54SMike Christie 	if (err == ISCSI_ERR_INVALID_HOST)
1062e5bd7b54SMike Christie 		iscsi_conn_error_event(conn->cls_conn, err);
1063e5bd7b54SMike Christie 	else
1064e5bd7b54SMike Christie 		iscsi_conn_failure(conn, err);
1065e5bd7b54SMike Christie 	put_device(dev);
1066e5bd7b54SMike Christie }
1067e5bd7b54SMike Christie EXPORT_SYMBOL_GPL(iscsi_session_failure);
1068e5bd7b54SMike Christie 
10697996a778SMike Christie void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
10707996a778SMike Christie {
10717996a778SMike Christie 	struct iscsi_session *session = conn->session;
10727996a778SMike Christie 	unsigned long flags;
10737996a778SMike Christie 
10747996a778SMike Christie 	spin_lock_irqsave(&session->lock, flags);
1075656cffc9SMike Christie 	if (session->state == ISCSI_STATE_FAILED) {
1076656cffc9SMike Christie 		spin_unlock_irqrestore(&session->lock, flags);
1077656cffc9SMike Christie 		return;
1078656cffc9SMike Christie 	}
1079656cffc9SMike Christie 
108067a61114SMike Christie 	if (conn->stop_stage == 0)
10817996a778SMike Christie 		session->state = ISCSI_STATE_FAILED;
10827996a778SMike Christie 	spin_unlock_irqrestore(&session->lock, flags);
1083e5bd7b54SMike Christie 
10847996a778SMike Christie 	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
10857996a778SMike Christie 	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
1086e5bd7b54SMike Christie 	iscsi_conn_error_event(conn->cls_conn, err);
10877996a778SMike Christie }
10887996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_failure);
10897996a778SMike Christie 
109077a23c21SMike Christie static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn)
109177a23c21SMike Christie {
109277a23c21SMike Christie 	struct iscsi_session *session = conn->session;
109377a23c21SMike Christie 
109477a23c21SMike Christie 	/*
109577a23c21SMike Christie 	 * Check for iSCSI window and take care of CmdSN wrap-around
109677a23c21SMike Christie 	 */
1097e0726407SMike Christie 	if (!iscsi_sna_lte(session->queued_cmdsn, session->max_cmdsn)) {
1098e0726407SMike Christie 		debug_scsi("iSCSI CmdSN closed. ExpCmdSn %u MaxCmdSN %u "
1099e0726407SMike Christie 			   "CmdSN %u/%u\n", session->exp_cmdsn,
1100e0726407SMike Christie 			   session->max_cmdsn, session->cmdsn,
1101e0726407SMike Christie 			   session->queued_cmdsn);
110277a23c21SMike Christie 		return -ENOSPC;
110377a23c21SMike Christie 	}
110477a23c21SMike Christie 	return 0;
110577a23c21SMike Christie }
110677a23c21SMike Christie 
11079c19a7d0SMike Christie static int iscsi_xmit_task(struct iscsi_conn *conn)
110877a23c21SMike Christie {
11099c19a7d0SMike Christie 	struct iscsi_task *task = conn->task;
1110843c0a8aSMike Christie 	int rc;
111177a23c21SMike Christie 
11129c19a7d0SMike Christie 	__iscsi_get_task(task);
111377a23c21SMike Christie 	spin_unlock_bh(&conn->session->lock);
11149c19a7d0SMike Christie 	rc = conn->session->tt->xmit_task(task);
111577a23c21SMike Christie 	spin_lock_bh(&conn->session->lock);
11169c19a7d0SMike Christie 	__iscsi_put_task(task);
111777a23c21SMike Christie 	if (!rc)
11189c19a7d0SMike Christie 		/* done with this task */
11199c19a7d0SMike Christie 		conn->task = NULL;
112077a23c21SMike Christie 	return rc;
112177a23c21SMike Christie }
112277a23c21SMike Christie 
11237996a778SMike Christie /**
11249c19a7d0SMike Christie  * iscsi_requeue_task - requeue task to run from session workqueue
11259c19a7d0SMike Christie  * @task: task to requeue
1126843c0a8aSMike Christie  *
11279c19a7d0SMike Christie  * LLDs that need to run a task from the session workqueue should call
1128052d0144SMike Christie  * this. The session lock must be held. This should only be called
1129052d0144SMike Christie  * by software drivers.
1130843c0a8aSMike Christie  */
11319c19a7d0SMike Christie void iscsi_requeue_task(struct iscsi_task *task)
1132843c0a8aSMike Christie {
11339c19a7d0SMike Christie 	struct iscsi_conn *conn = task->conn;
1134843c0a8aSMike Christie 
11359c19a7d0SMike Christie 	list_move_tail(&task->running, &conn->requeue);
1136843c0a8aSMike Christie 	scsi_queue_work(conn->session->host, &conn->xmitwork);
1137843c0a8aSMike Christie }
11389c19a7d0SMike Christie EXPORT_SYMBOL_GPL(iscsi_requeue_task);
1139843c0a8aSMike Christie 
1140843c0a8aSMike Christie /**
11417996a778SMike Christie  * iscsi_data_xmit - xmit any command into the scheduled connection
11427996a778SMike Christie  * @conn: iscsi connection
11437996a778SMike Christie  *
11447996a778SMike Christie  * Notes:
11457996a778SMike Christie  *	The function can return -EAGAIN in which case the caller must
11467996a778SMike Christie  *	re-schedule it again later or recover. '0' return code means
11477996a778SMike Christie  *	successful xmit.
11487996a778SMike Christie  **/
11497996a778SMike Christie static int iscsi_data_xmit(struct iscsi_conn *conn)
11507996a778SMike Christie {
11513219e529SMike Christie 	int rc = 0;
11527996a778SMike Christie 
115377a23c21SMike Christie 	spin_lock_bh(&conn->session->lock);
11547996a778SMike Christie 	if (unlikely(conn->suspend_tx)) {
11557996a778SMike Christie 		debug_scsi("conn %d Tx suspended!\n", conn->id);
115677a23c21SMike Christie 		spin_unlock_bh(&conn->session->lock);
11573219e529SMike Christie 		return -ENODATA;
11587996a778SMike Christie 	}
11597996a778SMike Christie 
11609c19a7d0SMike Christie 	if (conn->task) {
11619c19a7d0SMike Christie 		rc = iscsi_xmit_task(conn);
11623219e529SMike Christie 	        if (rc)
11637996a778SMike Christie 		        goto again;
11647996a778SMike Christie 	}
116577a23c21SMike Christie 
116677a23c21SMike Christie 	/*
116777a23c21SMike Christie 	 * process mgmt pdus like nops before commands since we should
116877a23c21SMike Christie 	 * only have one nop-out as a ping from us and targets should not
116977a23c21SMike Christie 	 * overflow us with nop-ins
117077a23c21SMike Christie 	 */
117177a23c21SMike Christie check_mgmt:
1172843c0a8aSMike Christie 	while (!list_empty(&conn->mgmtqueue)) {
11739c19a7d0SMike Christie 		conn->task = list_entry(conn->mgmtqueue.next,
11749c19a7d0SMike Christie 					 struct iscsi_task, running);
11759c19a7d0SMike Christie 		if (iscsi_prep_mgmt_task(conn, conn->task)) {
11769c19a7d0SMike Christie 			__iscsi_put_task(conn->task);
11779c19a7d0SMike Christie 			conn->task = NULL;
1178b3a7ea8dSMike Christie 			continue;
1179b3a7ea8dSMike Christie 		}
11809c19a7d0SMike Christie 		rc = iscsi_xmit_task(conn);
11813219e529SMike Christie 		if (rc)
11827996a778SMike Christie 			goto again;
11837996a778SMike Christie 	}
11847996a778SMike Christie 
1185843c0a8aSMike Christie 	/* process pending command queue */
1186b6c395edSMike Christie 	while (!list_empty(&conn->xmitqueue)) {
1187843c0a8aSMike Christie 		if (conn->tmf_state == TMF_QUEUED)
1188843c0a8aSMike Christie 			break;
1189843c0a8aSMike Christie 
11909c19a7d0SMike Christie 		conn->task = list_entry(conn->xmitqueue.next,
11919c19a7d0SMike Christie 					 struct iscsi_task, running);
1192b3a7ea8dSMike Christie 		if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
11939c19a7d0SMike Christie 			fail_command(conn, conn->task, DID_IMM_RETRY << 16);
1194b3a7ea8dSMike Christie 			continue;
1195b3a7ea8dSMike Christie 		}
1196577577daSMike Christie 		rc = iscsi_prep_scsi_cmd_pdu(conn->task);
1197577577daSMike Christie 		if (rc) {
1198577577daSMike Christie 			if (rc == -ENOMEM) {
1199577577daSMike Christie 				conn->task = NULL;
1200577577daSMike Christie 				goto again;
1201577577daSMike Christie 			} else
12029c19a7d0SMike Christie 				fail_command(conn, conn->task, DID_ABORT << 16);
1203004d6530SBoaz Harrosh 			continue;
1204004d6530SBoaz Harrosh 		}
12059c19a7d0SMike Christie 		rc = iscsi_xmit_task(conn);
12063219e529SMike Christie 		if (rc)
12077996a778SMike Christie 			goto again;
120877a23c21SMike Christie 		/*
12099c19a7d0SMike Christie 		 * we could continuously get new task requests so
121077a23c21SMike Christie 		 * we need to check the mgmt queue for nops that need to
121177a23c21SMike Christie 		 * be sent to aviod starvation
121277a23c21SMike Christie 		 */
1213843c0a8aSMike Christie 		if (!list_empty(&conn->mgmtqueue))
1214843c0a8aSMike Christie 			goto check_mgmt;
1215843c0a8aSMike Christie 	}
1216843c0a8aSMike Christie 
1217843c0a8aSMike Christie 	while (!list_empty(&conn->requeue)) {
1218843c0a8aSMike Christie 		if (conn->session->fast_abort && conn->tmf_state != TMF_INITIAL)
1219843c0a8aSMike Christie 			break;
1220843c0a8aSMike Christie 
1221b3a7ea8dSMike Christie 		/*
1222b3a7ea8dSMike Christie 		 * we always do fastlogout - conn stop code will clean up.
1223b3a7ea8dSMike Christie 		 */
1224b3a7ea8dSMike Christie 		if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
1225b3a7ea8dSMike Christie 			break;
1226b3a7ea8dSMike Christie 
12279c19a7d0SMike Christie 		conn->task = list_entry(conn->requeue.next,
12289c19a7d0SMike Christie 					 struct iscsi_task, running);
12299c19a7d0SMike Christie 		conn->task->state = ISCSI_TASK_RUNNING;
1230843c0a8aSMike Christie 		list_move_tail(conn->requeue.next, &conn->run_list);
12319c19a7d0SMike Christie 		rc = iscsi_xmit_task(conn);
1232843c0a8aSMike Christie 		if (rc)
1233843c0a8aSMike Christie 			goto again;
1234843c0a8aSMike Christie 		if (!list_empty(&conn->mgmtqueue))
123577a23c21SMike Christie 			goto check_mgmt;
12367996a778SMike Christie 	}
123777a23c21SMike Christie 	spin_unlock_bh(&conn->session->lock);
12383219e529SMike Christie 	return -ENODATA;
12397996a778SMike Christie 
12407996a778SMike Christie again:
12417996a778SMike Christie 	if (unlikely(conn->suspend_tx))
124277a23c21SMike Christie 		rc = -ENODATA;
124377a23c21SMike Christie 	spin_unlock_bh(&conn->session->lock);
12443219e529SMike Christie 	return rc;
12457996a778SMike Christie }
12467996a778SMike Christie 
1247c4028958SDavid Howells static void iscsi_xmitworker(struct work_struct *work)
12487996a778SMike Christie {
1249c4028958SDavid Howells 	struct iscsi_conn *conn =
1250c4028958SDavid Howells 		container_of(work, struct iscsi_conn, xmitwork);
12513219e529SMike Christie 	int rc;
12527996a778SMike Christie 	/*
12537996a778SMike Christie 	 * serialize Xmit worker on a per-connection basis.
12547996a778SMike Christie 	 */
12553219e529SMike Christie 	do {
12563219e529SMike Christie 		rc = iscsi_data_xmit(conn);
12573219e529SMike Christie 	} while (rc >= 0 || rc == -EAGAIN);
12587996a778SMike Christie }
12597996a778SMike Christie 
1260577577daSMike Christie static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn,
1261577577daSMike Christie 						  struct scsi_cmnd *sc)
1262577577daSMike Christie {
1263577577daSMike Christie 	struct iscsi_task *task;
1264577577daSMike Christie 
1265577577daSMike Christie 	if (!__kfifo_get(conn->session->cmdpool.queue,
1266577577daSMike Christie 			 (void *) &task, sizeof(void *)))
1267577577daSMike Christie 		return NULL;
1268577577daSMike Christie 
1269577577daSMike Christie 	sc->SCp.phase = conn->session->age;
1270577577daSMike Christie 	sc->SCp.ptr = (char *) task;
1271577577daSMike Christie 
1272577577daSMike Christie 	atomic_set(&task->refcount, 1);
1273577577daSMike Christie 	task->state = ISCSI_TASK_PENDING;
1274577577daSMike Christie 	task->conn = conn;
1275577577daSMike Christie 	task->sc = sc;
1276577577daSMike Christie 	INIT_LIST_HEAD(&task->running);
1277577577daSMike Christie 	return task;
1278577577daSMike Christie }
1279577577daSMike Christie 
12807996a778SMike Christie enum {
12817996a778SMike Christie 	FAILURE_BAD_HOST = 1,
12827996a778SMike Christie 	FAILURE_SESSION_FAILED,
12837996a778SMike Christie 	FAILURE_SESSION_FREED,
12847996a778SMike Christie 	FAILURE_WINDOW_CLOSED,
128560ecebf5SMike Christie 	FAILURE_OOM,
12867996a778SMike Christie 	FAILURE_SESSION_TERMINATE,
1287656cffc9SMike Christie 	FAILURE_SESSION_IN_RECOVERY,
12887996a778SMike Christie 	FAILURE_SESSION_RECOVERY_TIMEOUT,
1289b3a7ea8dSMike Christie 	FAILURE_SESSION_LOGGING_OUT,
12906eabafbeSMike Christie 	FAILURE_SESSION_NOT_READY,
12917996a778SMike Christie };
12927996a778SMike Christie 
12937996a778SMike Christie int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
12947996a778SMike Christie {
129575613521SMike Christie 	struct iscsi_cls_session *cls_session;
12967996a778SMike Christie 	struct Scsi_Host *host;
12977996a778SMike Christie 	int reason = 0;
12987996a778SMike Christie 	struct iscsi_session *session;
12997996a778SMike Christie 	struct iscsi_conn *conn;
13009c19a7d0SMike Christie 	struct iscsi_task *task = NULL;
13017996a778SMike Christie 
13027996a778SMike Christie 	sc->scsi_done = done;
13037996a778SMike Christie 	sc->result = 0;
1304f47f2cf5SMike Christie 	sc->SCp.ptr = NULL;
13057996a778SMike Christie 
13067996a778SMike Christie 	host = sc->device->host;
13071040c99dSMike Christie 	spin_unlock(host->host_lock);
13087996a778SMike Christie 
130975613521SMike Christie 	cls_session = starget_to_session(scsi_target(sc->device));
131075613521SMike Christie 	session = cls_session->dd_data;
13117996a778SMike Christie 	spin_lock(&session->lock);
13127996a778SMike Christie 
131375613521SMike Christie 	reason = iscsi_session_chkready(cls_session);
13146eabafbeSMike Christie 	if (reason) {
13156eabafbeSMike Christie 		sc->result = reason;
13166eabafbeSMike Christie 		goto fault;
13176eabafbeSMike Christie 	}
13186eabafbeSMike Christie 
1319656cffc9SMike Christie 	/*
1320656cffc9SMike Christie 	 * ISCSI_STATE_FAILED is a temp. state. The recovery
1321656cffc9SMike Christie 	 * code will decide what is best to do with command queued
1322656cffc9SMike Christie 	 * during this time
1323656cffc9SMike Christie 	 */
1324656cffc9SMike Christie 	if (session->state != ISCSI_STATE_LOGGED_IN &&
1325656cffc9SMike Christie 	    session->state != ISCSI_STATE_FAILED) {
1326656cffc9SMike Christie 		/*
1327656cffc9SMike Christie 		 * to handle the race between when we set the recovery state
1328656cffc9SMike Christie 		 * and block the session we requeue here (commands could
1329656cffc9SMike Christie 		 * be entering our queuecommand while a block is starting
1330656cffc9SMike Christie 		 * up because the block code is not locked)
1331656cffc9SMike Christie 		 */
13329000bcd6SMike Christie 		switch (session->state) {
13339000bcd6SMike Christie 		case ISCSI_STATE_IN_RECOVERY:
1334656cffc9SMike Christie 			reason = FAILURE_SESSION_IN_RECOVERY;
1335d6d13ee1SMike Christie 			goto reject;
13369000bcd6SMike Christie 		case ISCSI_STATE_LOGGING_OUT:
13379000bcd6SMike Christie 			reason = FAILURE_SESSION_LOGGING_OUT;
1338d6d13ee1SMike Christie 			goto reject;
1339b3a7ea8dSMike Christie 		case ISCSI_STATE_RECOVERY_FAILED:
1340656cffc9SMike Christie 			reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
134156d7fcfaSMike Christie 			sc->result = DID_TRANSPORT_FAILFAST << 16;
1342b3a7ea8dSMike Christie 			break;
1343b3a7ea8dSMike Christie 		case ISCSI_STATE_TERMINATE:
1344656cffc9SMike Christie 			reason = FAILURE_SESSION_TERMINATE;
13456eabafbeSMike Christie 			sc->result = DID_NO_CONNECT << 16;
1346b3a7ea8dSMike Christie 			break;
1347b3a7ea8dSMike Christie 		default:
13487996a778SMike Christie 			reason = FAILURE_SESSION_FREED;
13496eabafbeSMike Christie 			sc->result = DID_NO_CONNECT << 16;
1350b3a7ea8dSMike Christie 		}
13517996a778SMike Christie 		goto fault;
13527996a778SMike Christie 	}
13537996a778SMike Christie 
13547996a778SMike Christie 	conn = session->leadconn;
135598644047SMike Christie 	if (!conn) {
135698644047SMike Christie 		reason = FAILURE_SESSION_FREED;
13576eabafbeSMike Christie 		sc->result = DID_NO_CONNECT << 16;
135898644047SMike Christie 		goto fault;
135998644047SMike Christie 	}
13607996a778SMike Christie 
136177a23c21SMike Christie 	if (iscsi_check_cmdsn_window_closed(conn)) {
136277a23c21SMike Christie 		reason = FAILURE_WINDOW_CLOSED;
136377a23c21SMike Christie 		goto reject;
136477a23c21SMike Christie 	}
136577a23c21SMike Christie 
1366577577daSMike Christie 	task = iscsi_alloc_task(conn, sc);
1367577577daSMike Christie 	if (!task) {
136860ecebf5SMike Christie 		reason = FAILURE_OOM;
136960ecebf5SMike Christie 		goto reject;
137060ecebf5SMike Christie 	}
13719c19a7d0SMike Christie 	list_add_tail(&task->running, &conn->xmitqueue);
13727996a778SMike Christie 
1373052d0144SMike Christie 	if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) {
1374577577daSMike Christie 		reason = iscsi_prep_scsi_cmd_pdu(task);
1375577577daSMike Christie 		if (reason) {
1376577577daSMike Christie 			if (reason == -ENOMEM) {
1377577577daSMike Christie 				reason = FAILURE_OOM;
1378577577daSMike Christie 				goto prepd_reject;
1379577577daSMike Christie 			} else {
1380052d0144SMike Christie 				sc->result = DID_ABORT << 16;
1381577577daSMike Christie 				goto prepd_fault;
1382577577daSMike Christie 			}
1383052d0144SMike Christie 		}
13849c19a7d0SMike Christie 		if (session->tt->xmit_task(task)) {
1385052d0144SMike Christie 			reason = FAILURE_SESSION_NOT_READY;
1386577577daSMike Christie 			goto prepd_reject;
1387052d0144SMike Christie 		}
1388052d0144SMike Christie 	} else
1389052d0144SMike Christie 		scsi_queue_work(session->host, &conn->xmitwork);
1390052d0144SMike Christie 
1391052d0144SMike Christie 	session->queued_cmdsn++;
1392052d0144SMike Christie 	spin_unlock(&session->lock);
13931040c99dSMike Christie 	spin_lock(host->host_lock);
13947996a778SMike Christie 	return 0;
13957996a778SMike Christie 
1396577577daSMike Christie prepd_reject:
1397577577daSMike Christie 	sc->scsi_done = NULL;
1398577577daSMike Christie 	iscsi_complete_command(task);
13997996a778SMike Christie reject:
14007996a778SMike Christie 	spin_unlock(&session->lock);
14017996a778SMike Christie 	debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason);
14021040c99dSMike Christie 	spin_lock(host->host_lock);
1403d6d13ee1SMike Christie 	return SCSI_MLQUEUE_TARGET_BUSY;
14047996a778SMike Christie 
1405577577daSMike Christie prepd_fault:
1406577577daSMike Christie 	sc->scsi_done = NULL;
1407577577daSMike Christie 	iscsi_complete_command(task);
14087996a778SMike Christie fault:
14097996a778SMike Christie 	spin_unlock(&session->lock);
14106eabafbeSMike Christie 	debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason);
1411c07d4444SBoaz Harrosh 	if (!scsi_bidi_cmnd(sc))
14121c138991SFUJITA Tomonori 		scsi_set_resid(sc, scsi_bufflen(sc));
1413c07d4444SBoaz Harrosh 	else {
1414c07d4444SBoaz Harrosh 		scsi_out(sc)->resid = scsi_out(sc)->length;
1415c07d4444SBoaz Harrosh 		scsi_in(sc)->resid = scsi_in(sc)->length;
1416c07d4444SBoaz Harrosh 	}
1417052d0144SMike Christie 	done(sc);
14181040c99dSMike Christie 	spin_lock(host->host_lock);
14197996a778SMike Christie 	return 0;
14207996a778SMike Christie }
14217996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_queuecommand);
14227996a778SMike Christie 
14237996a778SMike Christie int iscsi_change_queue_depth(struct scsi_device *sdev, int depth)
14247996a778SMike Christie {
14257996a778SMike Christie 	if (depth > ISCSI_MAX_CMD_PER_LUN)
14267996a778SMike Christie 		depth = ISCSI_MAX_CMD_PER_LUN;
14277996a778SMike Christie 	scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
14287996a778SMike Christie 	return sdev->queue_depth;
14297996a778SMike Christie }
14307996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
14317996a778SMike Christie 
14327996a778SMike Christie void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
14337996a778SMike Christie {
143475613521SMike Christie 	struct iscsi_session *session = cls_session->dd_data;
14357996a778SMike Christie 
14367996a778SMike Christie 	spin_lock_bh(&session->lock);
14377996a778SMike Christie 	if (session->state != ISCSI_STATE_LOGGED_IN) {
1438656cffc9SMike Christie 		session->state = ISCSI_STATE_RECOVERY_FAILED;
1439843c0a8aSMike Christie 		if (session->leadconn)
1440843c0a8aSMike Christie 			wake_up(&session->leadconn->ehwait);
14417996a778SMike Christie 	}
14427996a778SMike Christie 	spin_unlock_bh(&session->lock);
14437996a778SMike Christie }
14447996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout);
14457996a778SMike Christie 
14468e124525SMike Christie int iscsi_eh_target_reset(struct scsi_cmnd *sc)
14477996a778SMike Christie {
144875613521SMike Christie 	struct iscsi_cls_session *cls_session;
144975613521SMike Christie 	struct iscsi_session *session;
145075613521SMike Christie 	struct iscsi_conn *conn;
145175613521SMike Christie 
145275613521SMike Christie 	cls_session = starget_to_session(scsi_target(sc->device));
145375613521SMike Christie 	session = cls_session->dd_data;
145475613521SMike Christie 	conn = session->leadconn;
14557996a778SMike Christie 
1456bc436b27SMike Christie 	mutex_lock(&session->eh_mutex);
14577996a778SMike Christie 	spin_lock_bh(&session->lock);
14587996a778SMike Christie 	if (session->state == ISCSI_STATE_TERMINATE) {
14597996a778SMike Christie failed:
14608e124525SMike Christie 		debug_scsi("failing target reset: session terminated "
1461d6e24d1cSPete Wyckoff 			   "[CID %d age %d]\n", conn->id, session->age);
14627996a778SMike Christie 		spin_unlock_bh(&session->lock);
1463bc436b27SMike Christie 		mutex_unlock(&session->eh_mutex);
14647996a778SMike Christie 		return FAILED;
14657996a778SMike Christie 	}
14667996a778SMike Christie 
14677996a778SMike Christie 	spin_unlock_bh(&session->lock);
1468bc436b27SMike Christie 	mutex_unlock(&session->eh_mutex);
14697996a778SMike Christie 	/*
14707996a778SMike Christie 	 * we drop the lock here but the leadconn cannot be destoyed while
14717996a778SMike Christie 	 * we are in the scsi eh
14727996a778SMike Christie 	 */
14737996a778SMike Christie 	iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
14747996a778SMike Christie 
14758e124525SMike Christie 	debug_scsi("iscsi_eh_target_reset wait for relogin\n");
14767996a778SMike Christie 	wait_event_interruptible(conn->ehwait,
14777996a778SMike Christie 				 session->state == ISCSI_STATE_TERMINATE ||
14787996a778SMike Christie 				 session->state == ISCSI_STATE_LOGGED_IN ||
1479656cffc9SMike Christie 				 session->state == ISCSI_STATE_RECOVERY_FAILED);
14807996a778SMike Christie 	if (signal_pending(current))
14817996a778SMike Christie 		flush_signals(current);
14827996a778SMike Christie 
1483bc436b27SMike Christie 	mutex_lock(&session->eh_mutex);
14847996a778SMike Christie 	spin_lock_bh(&session->lock);
14857996a778SMike Christie 	if (session->state == ISCSI_STATE_LOGGED_IN)
1486322d739dSMike Christie 		iscsi_session_printk(KERN_INFO, session,
14878e124525SMike Christie 				     "target reset succeeded\n");
14887996a778SMike Christie 	else
14897996a778SMike Christie 		goto failed;
14907996a778SMike Christie 	spin_unlock_bh(&session->lock);
1491bc436b27SMike Christie 	mutex_unlock(&session->eh_mutex);
14927996a778SMike Christie 	return SUCCESS;
14937996a778SMike Christie }
14948e124525SMike Christie EXPORT_SYMBOL_GPL(iscsi_eh_target_reset);
14957996a778SMike Christie 
1496843c0a8aSMike Christie static void iscsi_tmf_timedout(unsigned long data)
14977996a778SMike Christie {
1498843c0a8aSMike Christie 	struct iscsi_conn *conn = (struct iscsi_conn *)data;
14997996a778SMike Christie 	struct iscsi_session *session = conn->session;
15007996a778SMike Christie 
15017996a778SMike Christie 	spin_lock(&session->lock);
1502843c0a8aSMike Christie 	if (conn->tmf_state == TMF_QUEUED) {
1503843c0a8aSMike Christie 		conn->tmf_state = TMF_TIMEDOUT;
1504843c0a8aSMike Christie 		debug_scsi("tmf timedout\n");
15057996a778SMike Christie 		/* unblock eh_abort() */
15067996a778SMike Christie 		wake_up(&conn->ehwait);
15077996a778SMike Christie 	}
15087996a778SMike Christie 	spin_unlock(&session->lock);
15097996a778SMike Christie }
15107996a778SMike Christie 
15119c19a7d0SMike Christie static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
1512f6d5180cSMike Christie 				   struct iscsi_tm *hdr, int age,
1513f6d5180cSMike Christie 				   int timeout)
15147996a778SMike Christie {
15157996a778SMike Christie 	struct iscsi_session *session = conn->session;
15169c19a7d0SMike Christie 	struct iscsi_task *task;
15177996a778SMike Christie 
15189c19a7d0SMike Christie 	task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
15197996a778SMike Christie 				      NULL, 0);
15209c19a7d0SMike Christie 	if (!task) {
15216724add1SMike Christie 		spin_unlock_bh(&session->lock);
15227996a778SMike Christie 		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
1523843c0a8aSMike Christie 		spin_lock_bh(&session->lock);
1524843c0a8aSMike Christie 		debug_scsi("tmf exec failure\n");
152577a23c21SMike Christie 		return -EPERM;
15267996a778SMike Christie 	}
15277996a778SMike Christie 	conn->tmfcmd_pdus_cnt++;
1528f6d5180cSMike Christie 	conn->tmf_timer.expires = timeout * HZ + jiffies;
1529843c0a8aSMike Christie 	conn->tmf_timer.function = iscsi_tmf_timedout;
1530843c0a8aSMike Christie 	conn->tmf_timer.data = (unsigned long)conn;
1531843c0a8aSMike Christie 	add_timer(&conn->tmf_timer);
1532843c0a8aSMike Christie 	debug_scsi("tmf set timeout\n");
1533843c0a8aSMike Christie 
15347996a778SMike Christie 	spin_unlock_bh(&session->lock);
15356724add1SMike Christie 	mutex_unlock(&session->eh_mutex);
15367996a778SMike Christie 
15377996a778SMike Christie 	/*
15387996a778SMike Christie 	 * block eh thread until:
15397996a778SMike Christie 	 *
1540843c0a8aSMike Christie 	 * 1) tmf response
1541843c0a8aSMike Christie 	 * 2) tmf timeout
15427996a778SMike Christie 	 * 3) session is terminated or restarted or userspace has
15437996a778SMike Christie 	 * given up on recovery
15447996a778SMike Christie 	 */
1545843c0a8aSMike Christie 	wait_event_interruptible(conn->ehwait, age != session->age ||
15467996a778SMike Christie 				 session->state != ISCSI_STATE_LOGGED_IN ||
1547843c0a8aSMike Christie 				 conn->tmf_state != TMF_QUEUED);
15487996a778SMike Christie 	if (signal_pending(current))
15497996a778SMike Christie 		flush_signals(current);
1550843c0a8aSMike Christie 	del_timer_sync(&conn->tmf_timer);
1551843c0a8aSMike Christie 
15526724add1SMike Christie 	mutex_lock(&session->eh_mutex);
155377a23c21SMike Christie 	spin_lock_bh(&session->lock);
15549c19a7d0SMike Christie 	/* if the session drops it will clean up the task */
1555843c0a8aSMike Christie 	if (age != session->age ||
1556843c0a8aSMike Christie 	    session->state != ISCSI_STATE_LOGGED_IN)
1557843c0a8aSMike Christie 		return -ENOTCONN;
15587996a778SMike Christie 	return 0;
15597996a778SMike Christie }
15607996a778SMike Christie 
15617996a778SMike Christie /*
1562843c0a8aSMike Christie  * Fail commands. session lock held and recv side suspended and xmit
1563843c0a8aSMike Christie  * thread flushed
1564843c0a8aSMike Christie  */
15656eabafbeSMike Christie static void fail_all_commands(struct iscsi_conn *conn, unsigned lun,
15666eabafbeSMike Christie 			      int error)
1567843c0a8aSMike Christie {
15689c19a7d0SMike Christie 	struct iscsi_task *task, *tmp;
1569843c0a8aSMike Christie 
15709c19a7d0SMike Christie 	if (conn->task && (conn->task->sc->device->lun == lun || lun == -1))
15719c19a7d0SMike Christie 		conn->task = NULL;
1572843c0a8aSMike Christie 
1573843c0a8aSMike Christie 	/* flush pending */
15749c19a7d0SMike Christie 	list_for_each_entry_safe(task, tmp, &conn->xmitqueue, running) {
15759c19a7d0SMike Christie 		if (lun == task->sc->device->lun || lun == -1) {
1576843c0a8aSMike Christie 			debug_scsi("failing pending sc %p itt 0x%x\n",
15779c19a7d0SMike Christie 				   task->sc, task->itt);
15789c19a7d0SMike Christie 			fail_command(conn, task, error << 16);
1579843c0a8aSMike Christie 		}
1580843c0a8aSMike Christie 	}
1581843c0a8aSMike Christie 
15829c19a7d0SMike Christie 	list_for_each_entry_safe(task, tmp, &conn->requeue, running) {
15839c19a7d0SMike Christie 		if (lun == task->sc->device->lun || lun == -1) {
1584843c0a8aSMike Christie 			debug_scsi("failing requeued sc %p itt 0x%x\n",
15859c19a7d0SMike Christie 				   task->sc, task->itt);
15869c19a7d0SMike Christie 			fail_command(conn, task, error << 16);
1587843c0a8aSMike Christie 		}
1588843c0a8aSMike Christie 	}
1589843c0a8aSMike Christie 
1590843c0a8aSMike Christie 	/* fail all other running */
15919c19a7d0SMike Christie 	list_for_each_entry_safe(task, tmp, &conn->run_list, running) {
15929c19a7d0SMike Christie 		if (lun == task->sc->device->lun || lun == -1) {
1593843c0a8aSMike Christie 			debug_scsi("failing in progress sc %p itt 0x%x\n",
15949c19a7d0SMike Christie 				   task->sc, task->itt);
1595ac26d41dSMike Christie 			fail_command(conn, task, error << 16);
1596843c0a8aSMike Christie 		}
1597843c0a8aSMike Christie 	}
1598843c0a8aSMike Christie }
1599843c0a8aSMike Christie 
1600b40977d9SMike Christie void iscsi_suspend_tx(struct iscsi_conn *conn)
16016724add1SMike Christie {
16026724add1SMike Christie 	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
1603052d0144SMike Christie 	if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
16046724add1SMike Christie 		scsi_flush_work(conn->session->host);
16056724add1SMike Christie }
1606b40977d9SMike Christie EXPORT_SYMBOL_GPL(iscsi_suspend_tx);
16076724add1SMike Christie 
16086724add1SMike Christie static void iscsi_start_tx(struct iscsi_conn *conn)
16096724add1SMike Christie {
16106724add1SMike Christie 	clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
1611052d0144SMike Christie 	if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
16126724add1SMike Christie 		scsi_queue_work(conn->session->host, &conn->xmitwork);
16136724add1SMike Christie }
16146724add1SMike Christie 
1615242f9dcbSJens Axboe static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
1616f6d5180cSMike Christie {
1617f6d5180cSMike Christie 	struct iscsi_cls_session *cls_session;
1618f6d5180cSMike Christie 	struct iscsi_session *session;
1619f6d5180cSMike Christie 	struct iscsi_conn *conn;
1620242f9dcbSJens Axboe 	enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED;
1621f6d5180cSMike Christie 
1622f6d5180cSMike Christie 	cls_session = starget_to_session(scsi_target(scmd->device));
162375613521SMike Christie 	session = cls_session->dd_data;
1624f6d5180cSMike Christie 
1625f6d5180cSMike Christie 	debug_scsi("scsi cmd %p timedout\n", scmd);
1626f6d5180cSMike Christie 
1627f6d5180cSMike Christie 	spin_lock(&session->lock);
1628f6d5180cSMike Christie 	if (session->state != ISCSI_STATE_LOGGED_IN) {
1629f6d5180cSMike Christie 		/*
1630f6d5180cSMike Christie 		 * We are probably in the middle of iscsi recovery so let
1631f6d5180cSMike Christie 		 * that complete and handle the error.
1632f6d5180cSMike Christie 		 */
1633242f9dcbSJens Axboe 		rc = BLK_EH_RESET_TIMER;
1634f6d5180cSMike Christie 		goto done;
1635f6d5180cSMike Christie 	}
1636f6d5180cSMike Christie 
1637f6d5180cSMike Christie 	conn = session->leadconn;
1638f6d5180cSMike Christie 	if (!conn) {
1639f6d5180cSMike Christie 		/* In the middle of shuting down */
1640242f9dcbSJens Axboe 		rc = BLK_EH_RESET_TIMER;
1641f6d5180cSMike Christie 		goto done;
1642f6d5180cSMike Christie 	}
1643f6d5180cSMike Christie 
1644f6d5180cSMike Christie 	if (!conn->recv_timeout && !conn->ping_timeout)
1645f6d5180cSMike Christie 		goto done;
1646f6d5180cSMike Christie 	/*
1647f6d5180cSMike Christie 	 * if the ping timedout then we are in the middle of cleaning up
1648f6d5180cSMike Christie 	 * and can let the iscsi eh handle it
1649f6d5180cSMike Christie 	 */
1650f6d5180cSMike Christie 	if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) +
1651f6d5180cSMike Christie 			    (conn->ping_timeout * HZ), jiffies))
1652242f9dcbSJens Axboe 		rc = BLK_EH_RESET_TIMER;
1653f6d5180cSMike Christie 	/*
1654f6d5180cSMike Christie 	 * if we are about to check the transport then give the command
1655f6d5180cSMike Christie 	 * more time
1656f6d5180cSMike Christie 	 */
1657f6d5180cSMike Christie 	if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ),
1658f6d5180cSMike Christie 			   jiffies))
1659242f9dcbSJens Axboe 		rc = BLK_EH_RESET_TIMER;
1660f6d5180cSMike Christie 	/* if in the middle of checking the transport then give us more time */
16619c19a7d0SMike Christie 	if (conn->ping_task)
1662242f9dcbSJens Axboe 		rc = BLK_EH_RESET_TIMER;
1663f6d5180cSMike Christie done:
1664f6d5180cSMike Christie 	spin_unlock(&session->lock);
1665242f9dcbSJens Axboe 	debug_scsi("return %s\n", rc == BLK_EH_RESET_TIMER ?
1666242f9dcbSJens Axboe 					"timer reset" : "nh");
1667f6d5180cSMike Christie 	return rc;
1668f6d5180cSMike Christie }
1669f6d5180cSMike Christie 
1670f6d5180cSMike Christie static void iscsi_check_transport_timeouts(unsigned long data)
1671f6d5180cSMike Christie {
1672f6d5180cSMike Christie 	struct iscsi_conn *conn = (struct iscsi_conn *)data;
1673f6d5180cSMike Christie 	struct iscsi_session *session = conn->session;
16744cf10435SMike Christie 	unsigned long recv_timeout, next_timeout = 0, last_recv;
1675f6d5180cSMike Christie 
1676f6d5180cSMike Christie 	spin_lock(&session->lock);
1677f6d5180cSMike Christie 	if (session->state != ISCSI_STATE_LOGGED_IN)
1678f6d5180cSMike Christie 		goto done;
1679f6d5180cSMike Christie 
16804cf10435SMike Christie 	recv_timeout = conn->recv_timeout;
16814cf10435SMike Christie 	if (!recv_timeout)
1682f6d5180cSMike Christie 		goto done;
1683f6d5180cSMike Christie 
16844cf10435SMike Christie 	recv_timeout *= HZ;
1685f6d5180cSMike Christie 	last_recv = conn->last_recv;
16869c19a7d0SMike Christie 	if (conn->ping_task &&
16874cf10435SMike Christie 	    time_before_eq(conn->last_ping + (conn->ping_timeout * HZ),
1688f6d5180cSMike Christie 			   jiffies)) {
1689322d739dSMike Christie 		iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs "
1690322d739dSMike Christie 				  "expired, last rx %lu, last ping %lu, "
1691322d739dSMike Christie 				  "now %lu\n", conn->ping_timeout, last_recv,
1692f6d5180cSMike Christie 				  conn->last_ping, jiffies);
1693f6d5180cSMike Christie 		spin_unlock(&session->lock);
1694f6d5180cSMike Christie 		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
1695f6d5180cSMike Christie 		return;
1696f6d5180cSMike Christie 	}
1697f6d5180cSMike Christie 
16984cf10435SMike Christie 	if (time_before_eq(last_recv + recv_timeout, jiffies)) {
1699f6d5180cSMike Christie 		/* send a ping to try to provoke some traffic */
1700f6d5180cSMike Christie 		debug_scsi("Sending nopout as ping on conn %p\n", conn);
1701f6d5180cSMike Christie 		iscsi_send_nopout(conn, NULL);
17024cf10435SMike Christie 		next_timeout = conn->last_ping + (conn->ping_timeout * HZ);
1703ad294e9cSMike Christie 	} else
17044cf10435SMike Christie 		next_timeout = last_recv + recv_timeout;
1705f6d5180cSMike Christie 
1706f6d5180cSMike Christie 	debug_scsi("Setting next tmo %lu\n", next_timeout);
1707f6d5180cSMike Christie 	mod_timer(&conn->transport_timer, next_timeout);
1708f6d5180cSMike Christie done:
1709f6d5180cSMike Christie 	spin_unlock(&session->lock);
1710f6d5180cSMike Christie }
1711f6d5180cSMike Christie 
17129c19a7d0SMike Christie static void iscsi_prep_abort_task_pdu(struct iscsi_task *task,
1713843c0a8aSMike Christie 				      struct iscsi_tm *hdr)
1714843c0a8aSMike Christie {
1715843c0a8aSMike Christie 	memset(hdr, 0, sizeof(*hdr));
1716843c0a8aSMike Christie 	hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
1717843c0a8aSMike Christie 	hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK;
1718843c0a8aSMike Christie 	hdr->flags |= ISCSI_FLAG_CMD_FINAL;
1719577577daSMike Christie 	memcpy(hdr->lun, task->lun, sizeof(hdr->lun));
1720577577daSMike Christie 	hdr->rtt = task->hdr_itt;
1721577577daSMike Christie 	hdr->refcmdsn = task->cmdsn;
1722843c0a8aSMike Christie }
1723843c0a8aSMike Christie 
17247996a778SMike Christie int iscsi_eh_abort(struct scsi_cmnd *sc)
17257996a778SMike Christie {
172675613521SMike Christie 	struct iscsi_cls_session *cls_session;
172775613521SMike Christie 	struct iscsi_session *session;
1728f47f2cf5SMike Christie 	struct iscsi_conn *conn;
17299c19a7d0SMike Christie 	struct iscsi_task *task;
1730843c0a8aSMike Christie 	struct iscsi_tm *hdr;
1731843c0a8aSMike Christie 	int rc, age;
17327996a778SMike Christie 
173375613521SMike Christie 	cls_session = starget_to_session(scsi_target(sc->device));
173475613521SMike Christie 	session = cls_session->dd_data;
173575613521SMike Christie 
17366724add1SMike Christie 	mutex_lock(&session->eh_mutex);
17376724add1SMike Christie 	spin_lock_bh(&session->lock);
1738f47f2cf5SMike Christie 	/*
1739f47f2cf5SMike Christie 	 * if session was ISCSI_STATE_IN_RECOVERY then we may not have
1740f47f2cf5SMike Christie 	 * got the command.
1741f47f2cf5SMike Christie 	 */
1742f47f2cf5SMike Christie 	if (!sc->SCp.ptr) {
1743f47f2cf5SMike Christie 		debug_scsi("sc never reached iscsi layer or it completed.\n");
17446724add1SMike Christie 		spin_unlock_bh(&session->lock);
17456724add1SMike Christie 		mutex_unlock(&session->eh_mutex);
1746f47f2cf5SMike Christie 		return SUCCESS;
1747f47f2cf5SMike Christie 	}
1748f47f2cf5SMike Christie 
17497996a778SMike Christie 	/*
17507996a778SMike Christie 	 * If we are not logged in or we have started a new session
17517996a778SMike Christie 	 * then let the host reset code handle this
17527996a778SMike Christie 	 */
1753843c0a8aSMike Christie 	if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN ||
1754843c0a8aSMike Christie 	    sc->SCp.phase != session->age) {
1755843c0a8aSMike Christie 		spin_unlock_bh(&session->lock);
1756843c0a8aSMike Christie 		mutex_unlock(&session->eh_mutex);
1757843c0a8aSMike Christie 		return FAILED;
1758843c0a8aSMike Christie 	}
1759843c0a8aSMike Christie 
1760843c0a8aSMike Christie 	conn = session->leadconn;
1761843c0a8aSMike Christie 	conn->eh_abort_cnt++;
1762843c0a8aSMike Christie 	age = session->age;
1763843c0a8aSMike Christie 
17649c19a7d0SMike Christie 	task = (struct iscsi_task *)sc->SCp.ptr;
17659c19a7d0SMike Christie 	debug_scsi("aborting [sc %p itt 0x%x]\n", sc, task->itt);
17667996a778SMike Christie 
17679c19a7d0SMike Christie 	/* task completed before time out */
17689c19a7d0SMike Christie 	if (!task->sc) {
17697ea8b828SMike Christie 		debug_scsi("sc completed while abort in progress\n");
177077a23c21SMike Christie 		goto success;
17717ea8b828SMike Christie 	}
17727996a778SMike Christie 
17739c19a7d0SMike Christie 	if (task->state == ISCSI_TASK_PENDING) {
17749c19a7d0SMike Christie 		fail_command(conn, task, DID_ABORT << 16);
177577a23c21SMike Christie 		goto success;
177677a23c21SMike Christie 	}
17777996a778SMike Christie 
1778843c0a8aSMike Christie 	/* only have one tmf outstanding at a time */
1779843c0a8aSMike Christie 	if (conn->tmf_state != TMF_INITIAL)
17807996a778SMike Christie 		goto failed;
1781843c0a8aSMike Christie 	conn->tmf_state = TMF_QUEUED;
17827996a778SMike Christie 
1783843c0a8aSMike Christie 	hdr = &conn->tmhdr;
17849c19a7d0SMike Christie 	iscsi_prep_abort_task_pdu(task, hdr);
1785843c0a8aSMike Christie 
17869c19a7d0SMike Christie 	if (iscsi_exec_task_mgmt_fn(conn, hdr, age, session->abort_timeout)) {
1787843c0a8aSMike Christie 		rc = FAILED;
1788843c0a8aSMike Christie 		goto failed;
1789843c0a8aSMike Christie 	}
1790843c0a8aSMike Christie 
1791843c0a8aSMike Christie 	switch (conn->tmf_state) {
1792843c0a8aSMike Christie 	case TMF_SUCCESS:
17937ea8b828SMike Christie 		spin_unlock_bh(&session->lock);
1794913e5bf4SMike Christie 		/*
1795913e5bf4SMike Christie 		 * stop tx side incase the target had sent a abort rsp but
1796913e5bf4SMike Christie 		 * the initiator was still writing out data.
1797913e5bf4SMike Christie 		 */
17986724add1SMike Christie 		iscsi_suspend_tx(conn);
17997996a778SMike Christie 		/*
1800913e5bf4SMike Christie 		 * we do not stop the recv side because targets have been
1801913e5bf4SMike Christie 		 * good and have never sent us a successful tmf response
1802913e5bf4SMike Christie 		 * then sent more data for the cmd.
18037996a778SMike Christie 		 */
18047996a778SMike Christie 		spin_lock(&session->lock);
18059c19a7d0SMike Christie 		fail_command(conn, task, DID_ABORT << 16);
1806843c0a8aSMike Christie 		conn->tmf_state = TMF_INITIAL;
18077996a778SMike Christie 		spin_unlock(&session->lock);
18086724add1SMike Christie 		iscsi_start_tx(conn);
180977a23c21SMike Christie 		goto success_unlocked;
1810843c0a8aSMike Christie 	case TMF_TIMEDOUT:
1811843c0a8aSMike Christie 		spin_unlock_bh(&session->lock);
1812843c0a8aSMike Christie 		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
1813843c0a8aSMike Christie 		goto failed_unlocked;
1814843c0a8aSMike Christie 	case TMF_NOT_FOUND:
1815843c0a8aSMike Christie 		if (!sc->SCp.ptr) {
1816843c0a8aSMike Christie 			conn->tmf_state = TMF_INITIAL;
18179c19a7d0SMike Christie 			/* task completed before tmf abort response */
181877a23c21SMike Christie 			debug_scsi("sc completed while abort in progress\n");
181977a23c21SMike Christie 			goto success;
182077a23c21SMike Christie 		}
182177a23c21SMike Christie 		/* fall through */
182277a23c21SMike Christie 	default:
1823843c0a8aSMike Christie 		conn->tmf_state = TMF_INITIAL;
1824843c0a8aSMike Christie 		goto failed;
182577a23c21SMike Christie 	}
18267996a778SMike Christie 
182777a23c21SMike Christie success:
182877a23c21SMike Christie 	spin_unlock_bh(&session->lock);
182977a23c21SMike Christie success_unlocked:
18309c19a7d0SMike Christie 	debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, task->itt);
18316724add1SMike Christie 	mutex_unlock(&session->eh_mutex);
18327996a778SMike Christie 	return SUCCESS;
18337996a778SMike Christie 
18347996a778SMike Christie failed:
18357996a778SMike Christie 	spin_unlock_bh(&session->lock);
183677a23c21SMike Christie failed_unlocked:
1837843c0a8aSMike Christie 	debug_scsi("abort failed [sc %p itt 0x%x]\n", sc,
18389c19a7d0SMike Christie 		    task ? task->itt : 0);
18396724add1SMike Christie 	mutex_unlock(&session->eh_mutex);
18407996a778SMike Christie 	return FAILED;
18417996a778SMike Christie }
18427996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_eh_abort);
18437996a778SMike Christie 
1844843c0a8aSMike Christie static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr)
1845843c0a8aSMike Christie {
1846843c0a8aSMike Christie 	memset(hdr, 0, sizeof(*hdr));
1847843c0a8aSMike Christie 	hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
1848843c0a8aSMike Christie 	hdr->flags = ISCSI_TM_FUNC_LOGICAL_UNIT_RESET & ISCSI_FLAG_TM_FUNC_MASK;
1849843c0a8aSMike Christie 	hdr->flags |= ISCSI_FLAG_CMD_FINAL;
1850843c0a8aSMike Christie 	int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
1851f6d5180cSMike Christie 	hdr->rtt = RESERVED_ITT;
1852843c0a8aSMike Christie }
1853843c0a8aSMike Christie 
1854843c0a8aSMike Christie int iscsi_eh_device_reset(struct scsi_cmnd *sc)
1855843c0a8aSMike Christie {
185675613521SMike Christie 	struct iscsi_cls_session *cls_session;
185775613521SMike Christie 	struct iscsi_session *session;
1858843c0a8aSMike Christie 	struct iscsi_conn *conn;
1859843c0a8aSMike Christie 	struct iscsi_tm *hdr;
1860843c0a8aSMike Christie 	int rc = FAILED;
1861843c0a8aSMike Christie 
186275613521SMike Christie 	cls_session = starget_to_session(scsi_target(sc->device));
186375613521SMike Christie 	session = cls_session->dd_data;
186475613521SMike Christie 
1865843c0a8aSMike Christie 	debug_scsi("LU Reset [sc %p lun %u]\n", sc, sc->device->lun);
1866843c0a8aSMike Christie 
1867843c0a8aSMike Christie 	mutex_lock(&session->eh_mutex);
1868843c0a8aSMike Christie 	spin_lock_bh(&session->lock);
1869843c0a8aSMike Christie 	/*
1870843c0a8aSMike Christie 	 * Just check if we are not logged in. We cannot check for
1871843c0a8aSMike Christie 	 * the phase because the reset could come from a ioctl.
1872843c0a8aSMike Christie 	 */
1873843c0a8aSMike Christie 	if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN)
1874843c0a8aSMike Christie 		goto unlock;
1875843c0a8aSMike Christie 	conn = session->leadconn;
1876843c0a8aSMike Christie 
1877843c0a8aSMike Christie 	/* only have one tmf outstanding at a time */
1878843c0a8aSMike Christie 	if (conn->tmf_state != TMF_INITIAL)
1879843c0a8aSMike Christie 		goto unlock;
1880843c0a8aSMike Christie 	conn->tmf_state = TMF_QUEUED;
1881843c0a8aSMike Christie 
1882843c0a8aSMike Christie 	hdr = &conn->tmhdr;
1883843c0a8aSMike Christie 	iscsi_prep_lun_reset_pdu(sc, hdr);
1884843c0a8aSMike Christie 
18859c19a7d0SMike Christie 	if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age,
1886f6d5180cSMike Christie 				    session->lu_reset_timeout)) {
1887843c0a8aSMike Christie 		rc = FAILED;
1888843c0a8aSMike Christie 		goto unlock;
1889843c0a8aSMike Christie 	}
1890843c0a8aSMike Christie 
1891843c0a8aSMike Christie 	switch (conn->tmf_state) {
1892843c0a8aSMike Christie 	case TMF_SUCCESS:
1893843c0a8aSMike Christie 		break;
1894843c0a8aSMike Christie 	case TMF_TIMEDOUT:
1895843c0a8aSMike Christie 		spin_unlock_bh(&session->lock);
1896843c0a8aSMike Christie 		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
1897843c0a8aSMike Christie 		goto done;
1898843c0a8aSMike Christie 	default:
1899843c0a8aSMike Christie 		conn->tmf_state = TMF_INITIAL;
1900843c0a8aSMike Christie 		goto unlock;
1901843c0a8aSMike Christie 	}
1902843c0a8aSMike Christie 
1903843c0a8aSMike Christie 	rc = SUCCESS;
1904843c0a8aSMike Christie 	spin_unlock_bh(&session->lock);
1905843c0a8aSMike Christie 
1906843c0a8aSMike Christie 	iscsi_suspend_tx(conn);
1907913e5bf4SMike Christie 
1908a3439148SMike Christie 	spin_lock_bh(&session->lock);
19096eabafbeSMike Christie 	fail_all_commands(conn, sc->device->lun, DID_ERROR);
1910843c0a8aSMike Christie 	conn->tmf_state = TMF_INITIAL;
1911a3439148SMike Christie 	spin_unlock_bh(&session->lock);
1912843c0a8aSMike Christie 
1913843c0a8aSMike Christie 	iscsi_start_tx(conn);
1914843c0a8aSMike Christie 	goto done;
1915843c0a8aSMike Christie 
1916843c0a8aSMike Christie unlock:
1917843c0a8aSMike Christie 	spin_unlock_bh(&session->lock);
1918843c0a8aSMike Christie done:
1919843c0a8aSMike Christie 	debug_scsi("iscsi_eh_device_reset %s\n",
1920843c0a8aSMike Christie 		  rc == SUCCESS ? "SUCCESS" : "FAILED");
1921843c0a8aSMike Christie 	mutex_unlock(&session->eh_mutex);
1922843c0a8aSMike Christie 	return rc;
1923843c0a8aSMike Christie }
1924843c0a8aSMike Christie EXPORT_SYMBOL_GPL(iscsi_eh_device_reset);
1925843c0a8aSMike Christie 
19266320377fSOlaf Kirch /*
19276320377fSOlaf Kirch  * Pre-allocate a pool of @max items of @item_size. By default, the pool
19286320377fSOlaf Kirch  * should be accessed via kfifo_{get,put} on q->queue.
19296320377fSOlaf Kirch  * Optionally, the caller can obtain the array of object pointers
19306320377fSOlaf Kirch  * by passing in a non-NULL @items pointer
19316320377fSOlaf Kirch  */
19327996a778SMike Christie int
19336320377fSOlaf Kirch iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
19347996a778SMike Christie {
19356320377fSOlaf Kirch 	int i, num_arrays = 1;
19367996a778SMike Christie 
19376320377fSOlaf Kirch 	memset(q, 0, sizeof(*q));
19387996a778SMike Christie 
19397996a778SMike Christie 	q->max = max;
19406320377fSOlaf Kirch 
19416320377fSOlaf Kirch 	/* If the user passed an items pointer, he wants a copy of
19426320377fSOlaf Kirch 	 * the array. */
19436320377fSOlaf Kirch 	if (items)
19446320377fSOlaf Kirch 		num_arrays++;
19456320377fSOlaf Kirch 	q->pool = kzalloc(num_arrays * max * sizeof(void*), GFP_KERNEL);
19466320377fSOlaf Kirch 	if (q->pool == NULL)
1947*f474a37bSJean Delvare 		return -ENOMEM;
19487996a778SMike Christie 
19497996a778SMike Christie 	q->queue = kfifo_init((void*)q->pool, max * sizeof(void*),
19507996a778SMike Christie 			      GFP_KERNEL, NULL);
19516320377fSOlaf Kirch 	if (q->queue == ERR_PTR(-ENOMEM))
19526320377fSOlaf Kirch 		goto enomem;
19537996a778SMike Christie 
19547996a778SMike Christie 	for (i = 0; i < max; i++) {
19556320377fSOlaf Kirch 		q->pool[i] = kzalloc(item_size, GFP_KERNEL);
19567996a778SMike Christie 		if (q->pool[i] == NULL) {
19576320377fSOlaf Kirch 			q->max = i;
19586320377fSOlaf Kirch 			goto enomem;
19597996a778SMike Christie 		}
19607996a778SMike Christie 		__kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*));
19617996a778SMike Christie 	}
19626320377fSOlaf Kirch 
19636320377fSOlaf Kirch 	if (items) {
19646320377fSOlaf Kirch 		*items = q->pool + max;
19656320377fSOlaf Kirch 		memcpy(*items, q->pool, max * sizeof(void *));
19666320377fSOlaf Kirch 	}
19676320377fSOlaf Kirch 
19687996a778SMike Christie 	return 0;
19696320377fSOlaf Kirch 
19706320377fSOlaf Kirch enomem:
19716320377fSOlaf Kirch 	iscsi_pool_free(q);
19726320377fSOlaf Kirch 	return -ENOMEM;
19737996a778SMike Christie }
19747996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_pool_init);
19757996a778SMike Christie 
19766320377fSOlaf Kirch void iscsi_pool_free(struct iscsi_pool *q)
19777996a778SMike Christie {
19787996a778SMike Christie 	int i;
19797996a778SMike Christie 
19807996a778SMike Christie 	for (i = 0; i < q->max; i++)
19816320377fSOlaf Kirch 		kfree(q->pool[i]);
19827996a778SMike Christie 	kfree(q->pool);
19832f5899a3SMike Christie 	kfree(q->queue);
19847996a778SMike Christie }
19857996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_pool_free);
19867996a778SMike Christie 
1987a4804cd6SMike Christie /**
1988a4804cd6SMike Christie  * iscsi_host_add - add host to system
1989a4804cd6SMike Christie  * @shost: scsi host
1990a4804cd6SMike Christie  * @pdev: parent device
1991a4804cd6SMike Christie  *
1992a4804cd6SMike Christie  * This should be called by partial offload and software iscsi drivers
1993a4804cd6SMike Christie  * to add a host to the system.
1994a4804cd6SMike Christie  */
1995a4804cd6SMike Christie int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev)
19967996a778SMike Christie {
19978e9a20ceSMike Christie 	if (!shost->can_queue)
19988e9a20ceSMike Christie 		shost->can_queue = ISCSI_DEF_XMIT_CMDS_MAX;
19998e9a20ceSMike Christie 
2000308cec14SMike Christie 	if (!shost->transportt->eh_timed_out)
2001308cec14SMike Christie 		shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
2002a4804cd6SMike Christie 	return scsi_add_host(shost, pdev);
2003a4804cd6SMike Christie }
2004a4804cd6SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_add);
2005a4804cd6SMike Christie 
2006a4804cd6SMike Christie /**
2007a4804cd6SMike Christie  * iscsi_host_alloc - allocate a host and driver data
2008a4804cd6SMike Christie  * @sht: scsi host template
2009a4804cd6SMike Christie  * @dd_data_size: driver host data size
2010a4804cd6SMike Christie  * @qdepth: default device queue depth
2011a4804cd6SMike Christie  *
2012a4804cd6SMike Christie  * This should be called by partial offload and software iscsi drivers.
2013a4804cd6SMike Christie  * To access the driver specific memory use the iscsi_host_priv() macro.
2014a4804cd6SMike Christie  */
2015a4804cd6SMike Christie struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
2016a4804cd6SMike Christie 				   int dd_data_size, uint16_t qdepth)
2017a4804cd6SMike Christie {
2018a4804cd6SMike Christie 	struct Scsi_Host *shost;
2019e5bd7b54SMike Christie 	struct iscsi_host *ihost;
2020a4804cd6SMike Christie 
2021a4804cd6SMike Christie 	shost = scsi_host_alloc(sht, sizeof(struct iscsi_host) + dd_data_size);
2022a4804cd6SMike Christie 	if (!shost)
2023a4804cd6SMike Christie 		return NULL;
2024a4804cd6SMike Christie 
20251548271eSMike Christie 	if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) {
20261548271eSMike Christie 		if (qdepth != 0)
20271548271eSMike Christie 			printk(KERN_ERR "iscsi: invalid queue depth of %d. "
20281548271eSMike Christie 			       "Queue depth must be between 1 and %d.\n",
20291548271eSMike Christie 			       qdepth, ISCSI_MAX_CMD_PER_LUN);
20301548271eSMike Christie 		qdepth = ISCSI_DEF_CMD_PER_LUN;
20311548271eSMike Christie 	}
203275613521SMike Christie 	shost->cmd_per_lun = qdepth;
2033e5bd7b54SMike Christie 
2034e5bd7b54SMike Christie 	ihost = shost_priv(shost);
2035e5bd7b54SMike Christie 	spin_lock_init(&ihost->lock);
2036e5bd7b54SMike Christie 	ihost->state = ISCSI_HOST_SETUP;
2037e5bd7b54SMike Christie 	ihost->num_sessions = 0;
2038e5bd7b54SMike Christie 	init_waitqueue_head(&ihost->session_removal_wq);
2039a4804cd6SMike Christie 	return shost;
204075613521SMike Christie }
2041a4804cd6SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_alloc);
204275613521SMike Christie 
2043e5bd7b54SMike Christie static void iscsi_notify_host_removed(struct iscsi_cls_session *cls_session)
2044e5bd7b54SMike Christie {
2045e5bd7b54SMike Christie 	iscsi_session_failure(cls_session, ISCSI_ERR_INVALID_HOST);
2046e5bd7b54SMike Christie }
2047e5bd7b54SMike Christie 
2048a4804cd6SMike Christie /**
2049a4804cd6SMike Christie  * iscsi_host_remove - remove host and sessions
2050a4804cd6SMike Christie  * @shost: scsi host
2051a4804cd6SMike Christie  *
2052e5bd7b54SMike Christie  * If there are any sessions left, this will initiate the removal and wait
2053e5bd7b54SMike Christie  * for the completion.
2054a4804cd6SMike Christie  */
2055a4804cd6SMike Christie void iscsi_host_remove(struct Scsi_Host *shost)
2056a4804cd6SMike Christie {
2057e5bd7b54SMike Christie 	struct iscsi_host *ihost = shost_priv(shost);
2058e5bd7b54SMike Christie 	unsigned long flags;
2059e5bd7b54SMike Christie 
2060e5bd7b54SMike Christie 	spin_lock_irqsave(&ihost->lock, flags);
2061e5bd7b54SMike Christie 	ihost->state = ISCSI_HOST_REMOVED;
2062e5bd7b54SMike Christie 	spin_unlock_irqrestore(&ihost->lock, flags);
2063e5bd7b54SMike Christie 
2064e5bd7b54SMike Christie 	iscsi_host_for_each_session(shost, iscsi_notify_host_removed);
2065e5bd7b54SMike Christie 	wait_event_interruptible(ihost->session_removal_wq,
2066e5bd7b54SMike Christie 				 ihost->num_sessions == 0);
2067e5bd7b54SMike Christie 	if (signal_pending(current))
2068e5bd7b54SMike Christie 		flush_signals(current);
2069e5bd7b54SMike Christie 
2070a4804cd6SMike Christie 	scsi_remove_host(shost);
2071a4804cd6SMike Christie }
2072a4804cd6SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_remove);
2073a4804cd6SMike Christie 
2074a4804cd6SMike Christie void iscsi_host_free(struct Scsi_Host *shost)
207575613521SMike Christie {
207675613521SMike Christie 	struct iscsi_host *ihost = shost_priv(shost);
207775613521SMike Christie 
207875613521SMike Christie 	kfree(ihost->netdev);
207975613521SMike Christie 	kfree(ihost->hwaddress);
208075613521SMike Christie 	kfree(ihost->initiatorname);
2081a4804cd6SMike Christie 	scsi_host_put(shost);
208275613521SMike Christie }
2083a4804cd6SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_free);
208475613521SMike Christie 
2085e5bd7b54SMike Christie static void iscsi_host_dec_session_cnt(struct Scsi_Host *shost)
2086e5bd7b54SMike Christie {
2087e5bd7b54SMike Christie 	struct iscsi_host *ihost = shost_priv(shost);
2088e5bd7b54SMike Christie 	unsigned long flags;
2089e5bd7b54SMike Christie 
2090e5bd7b54SMike Christie 	shost = scsi_host_get(shost);
2091e5bd7b54SMike Christie 	if (!shost) {
2092e5bd7b54SMike Christie 		printk(KERN_ERR "Invalid state. Cannot notify host removal "
2093e5bd7b54SMike Christie 		      "of session teardown event because host already "
2094e5bd7b54SMike Christie 		      "removed.\n");
2095e5bd7b54SMike Christie 		return;
2096e5bd7b54SMike Christie 	}
2097e5bd7b54SMike Christie 
2098e5bd7b54SMike Christie 	spin_lock_irqsave(&ihost->lock, flags);
2099e5bd7b54SMike Christie 	ihost->num_sessions--;
2100e5bd7b54SMike Christie 	if (ihost->num_sessions == 0)
2101e5bd7b54SMike Christie 		wake_up(&ihost->session_removal_wq);
2102e5bd7b54SMike Christie 	spin_unlock_irqrestore(&ihost->lock, flags);
2103e5bd7b54SMike Christie 	scsi_host_put(shost);
2104e5bd7b54SMike Christie }
2105e5bd7b54SMike Christie 
210675613521SMike Christie /**
210775613521SMike Christie  * iscsi_session_setup - create iscsi cls session and host and session
210875613521SMike Christie  * @iscsit: iscsi transport template
210975613521SMike Christie  * @shost: scsi host
211075613521SMike Christie  * @cmds_max: session can queue
21119c19a7d0SMike Christie  * @cmd_task_size: LLD task private data size
211275613521SMike Christie  * @initial_cmdsn: initial CmdSN
211375613521SMike Christie  *
211475613521SMike Christie  * This can be used by software iscsi_transports that allocate
211575613521SMike Christie  * a session per scsi host.
21163cf7b233SMike Christie  *
21173cf7b233SMike Christie  * Callers should set cmds_max to the largest total numer (mgmt + scsi) of
21183cf7b233SMike Christie  * tasks they support. The iscsi layer reserves ISCSI_MGMT_CMDS_MAX tasks
21193cf7b233SMike Christie  * for nop handling and login/logout requests.
212075613521SMike Christie  */
212175613521SMike Christie struct iscsi_cls_session *
212275613521SMike Christie iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
21233cf7b233SMike Christie 		    uint16_t cmds_max, int cmd_task_size,
21247970634bSMike Christie 		    uint32_t initial_cmdsn, unsigned int id)
212575613521SMike Christie {
2126e5bd7b54SMike Christie 	struct iscsi_host *ihost = shost_priv(shost);
212775613521SMike Christie 	struct iscsi_session *session;
212875613521SMike Christie 	struct iscsi_cls_session *cls_session;
21293cf7b233SMike Christie 	int cmd_i, scsi_cmds, total_cmds = cmds_max;
2130e5bd7b54SMike Christie 	unsigned long flags;
2131e5bd7b54SMike Christie 
2132e5bd7b54SMike Christie 	spin_lock_irqsave(&ihost->lock, flags);
2133e5bd7b54SMike Christie 	if (ihost->state == ISCSI_HOST_REMOVED) {
2134e5bd7b54SMike Christie 		spin_unlock_irqrestore(&ihost->lock, flags);
2135e5bd7b54SMike Christie 		return NULL;
2136e5bd7b54SMike Christie 	}
2137e5bd7b54SMike Christie 	ihost->num_sessions++;
2138e5bd7b54SMike Christie 	spin_unlock_irqrestore(&ihost->lock, flags);
21398e9a20ceSMike Christie 
21408e9a20ceSMike Christie 	if (!total_cmds)
21418e9a20ceSMike Christie 		total_cmds = ISCSI_DEF_XMIT_CMDS_MAX;
21423e5c28adSMike Christie 	/*
21433cf7b233SMike Christie 	 * The iscsi layer needs some tasks for nop handling and tmfs,
21443cf7b233SMike Christie 	 * so the cmds_max must at least be greater than ISCSI_MGMT_CMDS_MAX
21453cf7b233SMike Christie 	 * + 1 command for scsi IO.
21463e5c28adSMike Christie 	 */
21473cf7b233SMike Christie 	if (total_cmds < ISCSI_TOTAL_CMDS_MIN) {
21483cf7b233SMike Christie 		printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue "
21493cf7b233SMike Christie 		       "must be a power of two that is at least %d.\n",
21503cf7b233SMike Christie 		       total_cmds, ISCSI_TOTAL_CMDS_MIN);
2151e5bd7b54SMike Christie 		goto dec_session_count;
21521548271eSMike Christie 	}
21533cf7b233SMike Christie 
21543cf7b233SMike Christie 	if (total_cmds > ISCSI_TOTAL_CMDS_MAX) {
21553cf7b233SMike Christie 		printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue "
21563cf7b233SMike Christie 		       "must be a power of 2 less than or equal to %d.\n",
21573cf7b233SMike Christie 		       cmds_max, ISCSI_TOTAL_CMDS_MAX);
21583cf7b233SMike Christie 		total_cmds = ISCSI_TOTAL_CMDS_MAX;
21593cf7b233SMike Christie 	}
21603cf7b233SMike Christie 
21613cf7b233SMike Christie 	if (!is_power_of_2(total_cmds)) {
21623cf7b233SMike Christie 		printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue "
21633cf7b233SMike Christie 		       "must be a power of 2.\n", total_cmds);
21643cf7b233SMike Christie 		total_cmds = rounddown_pow_of_two(total_cmds);
21653cf7b233SMike Christie 		if (total_cmds < ISCSI_TOTAL_CMDS_MIN)
21663cf7b233SMike Christie 			return NULL;
21673cf7b233SMike Christie 		printk(KERN_INFO "iscsi: Rounding can_queue to %d.\n",
21683cf7b233SMike Christie 		       total_cmds);
21693cf7b233SMike Christie 	}
21703cf7b233SMike Christie 	scsi_cmds = total_cmds - ISCSI_MGMT_CMDS_MAX;
21711548271eSMike Christie 
21725d91e209SMike Christie 	cls_session = iscsi_alloc_session(shost, iscsit,
21735d91e209SMike Christie 					  sizeof(struct iscsi_session));
217475613521SMike Christie 	if (!cls_session)
2175e5bd7b54SMike Christie 		goto dec_session_count;
217675613521SMike Christie 	session = cls_session->dd_data;
217775613521SMike Christie 	session->cls_session = cls_session;
21787996a778SMike Christie 	session->host = shost;
21797996a778SMike Christie 	session->state = ISCSI_STATE_FREE;
2180f6d5180cSMike Christie 	session->fast_abort = 1;
21814cd49ea1SMike Christie 	session->lu_reset_timeout = 15;
21824cd49ea1SMike Christie 	session->abort_timeout = 10;
21833cf7b233SMike Christie 	session->scsi_cmds_max = scsi_cmds;
21843cf7b233SMike Christie 	session->cmds_max = total_cmds;
2185e0726407SMike Christie 	session->queued_cmdsn = session->cmdsn = initial_cmdsn;
21867996a778SMike Christie 	session->exp_cmdsn = initial_cmdsn + 1;
21877996a778SMike Christie 	session->max_cmdsn = initial_cmdsn + 1;
21887996a778SMike Christie 	session->max_r2t = 1;
21897996a778SMike Christie 	session->tt = iscsit;
21906724add1SMike Christie 	mutex_init(&session->eh_mutex);
219175613521SMike Christie 	spin_lock_init(&session->lock);
21927996a778SMike Christie 
21937996a778SMike Christie 	/* initialize SCSI PDU commands pool */
21947996a778SMike Christie 	if (iscsi_pool_init(&session->cmdpool, session->cmds_max,
21957996a778SMike Christie 			    (void***)&session->cmds,
21969c19a7d0SMike Christie 			    cmd_task_size + sizeof(struct iscsi_task)))
21977996a778SMike Christie 		goto cmdpool_alloc_fail;
21987996a778SMike Christie 
21997996a778SMike Christie 	/* pre-format cmds pool with ITT */
22007996a778SMike Christie 	for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
22019c19a7d0SMike Christie 		struct iscsi_task *task = session->cmds[cmd_i];
22027996a778SMike Christie 
22039c19a7d0SMike Christie 		if (cmd_task_size)
22049c19a7d0SMike Christie 			task->dd_data = &task[1];
22059c19a7d0SMike Christie 		task->itt = cmd_i;
22069c19a7d0SMike Christie 		INIT_LIST_HEAD(&task->running);
22077996a778SMike Christie 	}
22087996a778SMike Christie 
2209f53a88daSMike Christie 	if (!try_module_get(iscsit->owner))
221075613521SMike Christie 		goto module_get_fail;
221175613521SMike Christie 
22127970634bSMike Christie 	if (iscsi_add_session(cls_session, id))
2213f53a88daSMike Christie 		goto cls_session_fail;
2214e5bd7b54SMike Christie 
22157996a778SMike Christie 	return cls_session;
22167996a778SMike Christie 
22177996a778SMike Christie cls_session_fail:
221875613521SMike Christie 	module_put(iscsit->owner);
221975613521SMike Christie module_get_fail:
22206320377fSOlaf Kirch 	iscsi_pool_free(&session->cmdpool);
22217996a778SMike Christie cmdpool_alloc_fail:
222275613521SMike Christie 	iscsi_free_session(cls_session);
2223e5bd7b54SMike Christie dec_session_count:
2224e5bd7b54SMike Christie 	iscsi_host_dec_session_cnt(shost);
22257996a778SMike Christie 	return NULL;
22267996a778SMike Christie }
22277996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_session_setup);
22287996a778SMike Christie 
22297996a778SMike Christie /**
22307996a778SMike Christie  * iscsi_session_teardown - destroy session, host, and cls_session
223175613521SMike Christie  * @cls_session: iscsi session
22327996a778SMike Christie  *
223375613521SMike Christie  * The driver must have called iscsi_remove_session before
223475613521SMike Christie  * calling this.
223575613521SMike Christie  */
22367996a778SMike Christie void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
22377996a778SMike Christie {
223875613521SMike Christie 	struct iscsi_session *session = cls_session->dd_data;
223963f75cc8SMike Christie 	struct module *owner = cls_session->transport->owner;
2240e5bd7b54SMike Christie 	struct Scsi_Host *shost = session->host;
22417996a778SMike Christie 
22426320377fSOlaf Kirch 	iscsi_pool_free(&session->cmdpool);
22437996a778SMike Christie 
2244b2c64167SMike Christie 	kfree(session->password);
2245b2c64167SMike Christie 	kfree(session->password_in);
2246b2c64167SMike Christie 	kfree(session->username);
2247b2c64167SMike Christie 	kfree(session->username_in);
2248f3ff0c36SMike Christie 	kfree(session->targetname);
224988dfd340SMike Christie 	kfree(session->initiatorname);
225088dfd340SMike Christie 	kfree(session->ifacename);
2251f3ff0c36SMike Christie 
225275613521SMike Christie 	iscsi_destroy_session(cls_session);
2253e5bd7b54SMike Christie 	iscsi_host_dec_session_cnt(shost);
225463f75cc8SMike Christie 	module_put(owner);
22557996a778SMike Christie }
22567996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_session_teardown);
22577996a778SMike Christie 
22587996a778SMike Christie /**
22597996a778SMike Christie  * iscsi_conn_setup - create iscsi_cls_conn and iscsi_conn
22607996a778SMike Christie  * @cls_session: iscsi_cls_session
22615d91e209SMike Christie  * @dd_size: private driver data size
22627996a778SMike Christie  * @conn_idx: cid
22635d91e209SMike Christie  */
22647996a778SMike Christie struct iscsi_cls_conn *
22655d91e209SMike Christie iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
22665d91e209SMike Christie 		 uint32_t conn_idx)
22677996a778SMike Christie {
226875613521SMike Christie 	struct iscsi_session *session = cls_session->dd_data;
22697996a778SMike Christie 	struct iscsi_conn *conn;
22707996a778SMike Christie 	struct iscsi_cls_conn *cls_conn;
2271d36ab6f3SMike Christie 	char *data;
22727996a778SMike Christie 
22735d91e209SMike Christie 	cls_conn = iscsi_create_conn(cls_session, sizeof(*conn) + dd_size,
22745d91e209SMike Christie 				     conn_idx);
22757996a778SMike Christie 	if (!cls_conn)
22767996a778SMike Christie 		return NULL;
22777996a778SMike Christie 	conn = cls_conn->dd_data;
22785d91e209SMike Christie 	memset(conn, 0, sizeof(*conn) + dd_size);
22797996a778SMike Christie 
22805d91e209SMike Christie 	conn->dd_data = cls_conn->dd_data + sizeof(*conn);
22817996a778SMike Christie 	conn->session = session;
22827996a778SMike Christie 	conn->cls_conn = cls_conn;
22837996a778SMike Christie 	conn->c_stage = ISCSI_CONN_INITIAL_STAGE;
22847996a778SMike Christie 	conn->id = conn_idx;
22857996a778SMike Christie 	conn->exp_statsn = 0;
2286843c0a8aSMike Christie 	conn->tmf_state = TMF_INITIAL;
2287f6d5180cSMike Christie 
2288f6d5180cSMike Christie 	init_timer(&conn->transport_timer);
2289f6d5180cSMike Christie 	conn->transport_timer.data = (unsigned long)conn;
2290f6d5180cSMike Christie 	conn->transport_timer.function = iscsi_check_transport_timeouts;
2291f6d5180cSMike Christie 
22927996a778SMike Christie 	INIT_LIST_HEAD(&conn->run_list);
22937996a778SMike Christie 	INIT_LIST_HEAD(&conn->mgmt_run_list);
2294843c0a8aSMike Christie 	INIT_LIST_HEAD(&conn->mgmtqueue);
2295b6c395edSMike Christie 	INIT_LIST_HEAD(&conn->xmitqueue);
2296843c0a8aSMike Christie 	INIT_LIST_HEAD(&conn->requeue);
2297c4028958SDavid Howells 	INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
22987996a778SMike Christie 
22999c19a7d0SMike Christie 	/* allocate login_task used for the login/text sequences */
23007996a778SMike Christie 	spin_lock_bh(&session->lock);
23013e5c28adSMike Christie 	if (!__kfifo_get(session->cmdpool.queue,
23029c19a7d0SMike Christie                          (void*)&conn->login_task,
23037996a778SMike Christie 			 sizeof(void*))) {
23047996a778SMike Christie 		spin_unlock_bh(&session->lock);
23059c19a7d0SMike Christie 		goto login_task_alloc_fail;
23067996a778SMike Christie 	}
23077996a778SMike Christie 	spin_unlock_bh(&session->lock);
23087996a778SMike Christie 
2309cfeb2cf9SMike Christie 	data = (char *) __get_free_pages(GFP_KERNEL,
2310cfeb2cf9SMike Christie 					 get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
2311d36ab6f3SMike Christie 	if (!data)
23129c19a7d0SMike Christie 		goto login_task_data_alloc_fail;
23139c19a7d0SMike Christie 	conn->login_task->data = conn->data = data;
2314d36ab6f3SMike Christie 
2315843c0a8aSMike Christie 	init_timer(&conn->tmf_timer);
23167996a778SMike Christie 	init_waitqueue_head(&conn->ehwait);
23177996a778SMike Christie 
23187996a778SMike Christie 	return cls_conn;
23197996a778SMike Christie 
23209c19a7d0SMike Christie login_task_data_alloc_fail:
23219c19a7d0SMike Christie 	__kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
2322d36ab6f3SMike Christie 		    sizeof(void*));
23239c19a7d0SMike Christie login_task_alloc_fail:
23247996a778SMike Christie 	iscsi_destroy_conn(cls_conn);
23257996a778SMike Christie 	return NULL;
23267996a778SMike Christie }
23277996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_setup);
23287996a778SMike Christie 
23297996a778SMike Christie /**
23307996a778SMike Christie  * iscsi_conn_teardown - teardown iscsi connection
23317996a778SMike Christie  * cls_conn: iscsi class connection
23327996a778SMike Christie  *
23337996a778SMike Christie  * TODO: we may need to make this into a two step process
23347996a778SMike Christie  * like scsi-mls remove + put host
23357996a778SMike Christie  */
23367996a778SMike Christie void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
23377996a778SMike Christie {
23387996a778SMike Christie 	struct iscsi_conn *conn = cls_conn->dd_data;
23397996a778SMike Christie 	struct iscsi_session *session = conn->session;
23407996a778SMike Christie 	unsigned long flags;
23417996a778SMike Christie 
2342f6d5180cSMike Christie 	del_timer_sync(&conn->transport_timer);
2343f6d5180cSMike Christie 
23447996a778SMike Christie 	spin_lock_bh(&session->lock);
23457996a778SMike Christie 	conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
23467996a778SMike Christie 	if (session->leadconn == conn) {
23477996a778SMike Christie 		/*
23487996a778SMike Christie 		 * leading connection? then give up on recovery.
23497996a778SMike Christie 		 */
23507996a778SMike Christie 		session->state = ISCSI_STATE_TERMINATE;
23517996a778SMike Christie 		wake_up(&conn->ehwait);
23527996a778SMike Christie 	}
23537996a778SMike Christie 	spin_unlock_bh(&session->lock);
23547996a778SMike Christie 
23557996a778SMike Christie 	/*
23567996a778SMike Christie 	 * Block until all in-progress commands for this connection
23577996a778SMike Christie 	 * time out or fail.
23587996a778SMike Christie 	 */
23597996a778SMike Christie 	for (;;) {
23607996a778SMike Christie 		spin_lock_irqsave(session->host->host_lock, flags);
23617996a778SMike Christie 		if (!session->host->host_busy) { /* OK for ERL == 0 */
23627996a778SMike Christie 			spin_unlock_irqrestore(session->host->host_lock, flags);
23637996a778SMike Christie 			break;
23647996a778SMike Christie 		}
23657996a778SMike Christie 		spin_unlock_irqrestore(session->host->host_lock, flags);
23667996a778SMike Christie 		msleep_interruptible(500);
2367322d739dSMike Christie 		iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): "
2368322d739dSMike Christie 				  "host_busy %d host_failed %d\n",
2369322d739dSMike Christie 				  session->host->host_busy,
2370be2df72eSOr Gerlitz 				  session->host->host_failed);
23717996a778SMike Christie 		/*
23727996a778SMike Christie 		 * force eh_abort() to unblock
23737996a778SMike Christie 		 */
23747996a778SMike Christie 		wake_up(&conn->ehwait);
23757996a778SMike Christie 	}
23767996a778SMike Christie 
2377779ea120SMike Christie 	/* flush queued up work because we free the connection below */
2378843c0a8aSMike Christie 	iscsi_suspend_tx(conn);
2379779ea120SMike Christie 
23807996a778SMike Christie 	spin_lock_bh(&session->lock);
2381cfeb2cf9SMike Christie 	free_pages((unsigned long) conn->data,
2382cfeb2cf9SMike Christie 		   get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
2383f3ff0c36SMike Christie 	kfree(conn->persistent_address);
23849c19a7d0SMike Christie 	__kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
23857996a778SMike Christie 		    sizeof(void*));
2386e0726407SMike Christie 	if (session->leadconn == conn)
23877996a778SMike Christie 		session->leadconn = NULL;
23887996a778SMike Christie 	spin_unlock_bh(&session->lock);
23897996a778SMike Christie 
23907996a778SMike Christie 	iscsi_destroy_conn(cls_conn);
23917996a778SMike Christie }
23927996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_teardown);
23937996a778SMike Christie 
23947996a778SMike Christie int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
23957996a778SMike Christie {
23967996a778SMike Christie 	struct iscsi_conn *conn = cls_conn->dd_data;
23977996a778SMike Christie 	struct iscsi_session *session = conn->session;
23987996a778SMike Christie 
2399ffd0436eSMike Christie 	if (!session) {
2400322d739dSMike Christie 		iscsi_conn_printk(KERN_ERR, conn,
2401322d739dSMike Christie 				  "can't start unbound connection\n");
24027996a778SMike Christie 		return -EPERM;
24037996a778SMike Christie 	}
24047996a778SMike Christie 
2405db98ccdeSMike Christie 	if ((session->imm_data_en || !session->initial_r2t_en) &&
2406db98ccdeSMike Christie 	     session->first_burst > session->max_burst) {
2407322d739dSMike Christie 		iscsi_conn_printk(KERN_INFO, conn, "invalid burst lengths: "
2408ffd0436eSMike Christie 				  "first_burst %d max_burst %d\n",
2409ffd0436eSMike Christie 				  session->first_burst, session->max_burst);
2410ffd0436eSMike Christie 		return -EINVAL;
2411ffd0436eSMike Christie 	}
2412ffd0436eSMike Christie 
2413f6d5180cSMike Christie 	if (conn->ping_timeout && !conn->recv_timeout) {
2414322d739dSMike Christie 		iscsi_conn_printk(KERN_ERR, conn, "invalid recv timeout of "
2415322d739dSMike Christie 				  "zero. Using 5 seconds\n.");
2416f6d5180cSMike Christie 		conn->recv_timeout = 5;
2417f6d5180cSMike Christie 	}
2418f6d5180cSMike Christie 
2419f6d5180cSMike Christie 	if (conn->recv_timeout && !conn->ping_timeout) {
2420322d739dSMike Christie 		iscsi_conn_printk(KERN_ERR, conn, "invalid ping timeout of "
2421322d739dSMike Christie 				  "zero. Using 5 seconds.\n");
2422f6d5180cSMike Christie 		conn->ping_timeout = 5;
2423f6d5180cSMike Christie 	}
2424f6d5180cSMike Christie 
24257996a778SMike Christie 	spin_lock_bh(&session->lock);
24267996a778SMike Christie 	conn->c_stage = ISCSI_CONN_STARTED;
24277996a778SMike Christie 	session->state = ISCSI_STATE_LOGGED_IN;
2428e0726407SMike Christie 	session->queued_cmdsn = session->cmdsn;
24297996a778SMike Christie 
2430f6d5180cSMike Christie 	conn->last_recv = jiffies;
2431f6d5180cSMike Christie 	conn->last_ping = jiffies;
2432f6d5180cSMike Christie 	if (conn->recv_timeout && conn->ping_timeout)
2433f6d5180cSMike Christie 		mod_timer(&conn->transport_timer,
2434f6d5180cSMike Christie 			  jiffies + (conn->recv_timeout * HZ));
2435f6d5180cSMike Christie 
24367996a778SMike Christie 	switch(conn->stop_stage) {
24377996a778SMike Christie 	case STOP_CONN_RECOVER:
24387996a778SMike Christie 		/*
24397996a778SMike Christie 		 * unblock eh_abort() if it is blocked. re-try all
24407996a778SMike Christie 		 * commands after successful recovery
24417996a778SMike Christie 		 */
24427996a778SMike Christie 		conn->stop_stage = 0;
2443843c0a8aSMike Christie 		conn->tmf_state = TMF_INITIAL;
24447996a778SMike Christie 		session->age++;
24458b1d0343SMike Christie 		if (session->age == 16)
24468b1d0343SMike Christie 			session->age = 0;
24476eabafbeSMike Christie 		break;
24487996a778SMike Christie 	case STOP_CONN_TERM:
24497996a778SMike Christie 		conn->stop_stage = 0;
24507996a778SMike Christie 		break;
24517996a778SMike Christie 	default:
24527996a778SMike Christie 		break;
24537996a778SMike Christie 	}
24547996a778SMike Christie 	spin_unlock_bh(&session->lock);
24557996a778SMike Christie 
245675613521SMike Christie 	iscsi_unblock_session(session->cls_session);
24576eabafbeSMike Christie 	wake_up(&conn->ehwait);
24587996a778SMike Christie 	return 0;
24597996a778SMike Christie }
24607996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_start);
24617996a778SMike Christie 
24627996a778SMike Christie static void
24637996a778SMike Christie flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn)
24647996a778SMike Christie {
24659c19a7d0SMike Christie 	struct iscsi_task *task, *tmp;
24667996a778SMike Christie 
24677996a778SMike Christie 	/* handle pending */
24689c19a7d0SMike Christie 	list_for_each_entry_safe(task, tmp, &conn->mgmtqueue, running) {
24699c19a7d0SMike Christie 		debug_scsi("flushing pending mgmt task itt 0x%x\n", task->itt);
24709c19a7d0SMike Christie 		/* release ref from prep task */
24719c19a7d0SMike Christie 		__iscsi_put_task(task);
24727996a778SMike Christie 	}
24737996a778SMike Christie 
24747996a778SMike Christie 	/* handle running */
24759c19a7d0SMike Christie 	list_for_each_entry_safe(task, tmp, &conn->mgmt_run_list, running) {
24769c19a7d0SMike Christie 		debug_scsi("flushing running mgmt task itt 0x%x\n", task->itt);
24779c19a7d0SMike Christie 		/* release ref from prep task */
24789c19a7d0SMike Christie 		__iscsi_put_task(task);
24797996a778SMike Christie 	}
24807996a778SMike Christie 
24819c19a7d0SMike Christie 	conn->task = NULL;
24827996a778SMike Christie }
24837996a778SMike Christie 
2484656cffc9SMike Christie static void iscsi_start_session_recovery(struct iscsi_session *session,
24857996a778SMike Christie 					 struct iscsi_conn *conn, int flag)
24867996a778SMike Christie {
2487ed2abc7fSMike Christie 	int old_stop_stage;
2488ed2abc7fSMike Christie 
2489f6d5180cSMike Christie 	del_timer_sync(&conn->transport_timer);
2490f6d5180cSMike Christie 
24916724add1SMike Christie 	mutex_lock(&session->eh_mutex);
24927996a778SMike Christie 	spin_lock_bh(&session->lock);
2493ed2abc7fSMike Christie 	if (conn->stop_stage == STOP_CONN_TERM) {
24947996a778SMike Christie 		spin_unlock_bh(&session->lock);
24956724add1SMike Christie 		mutex_unlock(&session->eh_mutex);
24966724add1SMike Christie 		return;
24976724add1SMike Christie 	}
24986724add1SMike Christie 
24996724add1SMike Christie 	/*
2500ed2abc7fSMike Christie 	 * When this is called for the in_login state, we only want to clean
25019c19a7d0SMike Christie 	 * up the login task and connection. We do not need to block and set
250267a61114SMike Christie 	 * the recovery state again
2503ed2abc7fSMike Christie 	 */
250467a61114SMike Christie 	if (flag == STOP_CONN_TERM)
250567a61114SMike Christie 		session->state = ISCSI_STATE_TERMINATE;
250667a61114SMike Christie 	else if (conn->stop_stage != STOP_CONN_RECOVER)
250767a61114SMike Christie 		session->state = ISCSI_STATE_IN_RECOVERY;
2508ed2abc7fSMike Christie 
2509ed2abc7fSMike Christie 	old_stop_stage = conn->stop_stage;
25107996a778SMike Christie 	conn->stop_stage = flag;
251167a61114SMike Christie 	conn->c_stage = ISCSI_CONN_STOPPED;
25127996a778SMike Christie 	spin_unlock_bh(&session->lock);
25136724add1SMike Christie 
25146724add1SMike Christie 	iscsi_suspend_tx(conn);
25157996a778SMike Christie 	/*
25167996a778SMike Christie 	 * for connection level recovery we should not calculate
25177996a778SMike Christie 	 * header digest. conn->hdr_size used for optimization
25187996a778SMike Christie 	 * in hdr_extract() and will be re-negotiated at
25197996a778SMike Christie 	 * set_param() time.
25207996a778SMike Christie 	 */
25217996a778SMike Christie 	if (flag == STOP_CONN_RECOVER) {
25227996a778SMike Christie 		conn->hdrdgst_en = 0;
25237996a778SMike Christie 		conn->datadgst_en = 0;
2524656cffc9SMike Christie 		if (session->state == ISCSI_STATE_IN_RECOVERY &&
252567a61114SMike Christie 		    old_stop_stage != STOP_CONN_RECOVER) {
252667a61114SMike Christie 			debug_scsi("blocking session\n");
252775613521SMike Christie 			iscsi_block_session(session->cls_session);
25287996a778SMike Christie 		}
252967a61114SMike Christie 	}
2530656cffc9SMike Christie 
2531656cffc9SMike Christie 	/*
2532656cffc9SMike Christie 	 * flush queues.
2533656cffc9SMike Christie 	 */
2534656cffc9SMike Christie 	spin_lock_bh(&session->lock);
253587cd9eabSMike Christie 	if (flag == STOP_CONN_RECOVER)
253656d7fcfaSMike Christie 		fail_all_commands(conn, -1, DID_TRANSPORT_DISRUPTED);
253756d7fcfaSMike Christie 	else
253856d7fcfaSMike Christie 		fail_all_commands(conn, -1, DID_ERROR);
2539656cffc9SMike Christie 	flush_control_queues(session, conn);
2540656cffc9SMike Christie 	spin_unlock_bh(&session->lock);
25416724add1SMike Christie 	mutex_unlock(&session->eh_mutex);
25427996a778SMike Christie }
25437996a778SMike Christie 
25447996a778SMike Christie void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
25457996a778SMike Christie {
25467996a778SMike Christie 	struct iscsi_conn *conn = cls_conn->dd_data;
25477996a778SMike Christie 	struct iscsi_session *session = conn->session;
25487996a778SMike Christie 
25497996a778SMike Christie 	switch (flag) {
25507996a778SMike Christie 	case STOP_CONN_RECOVER:
25517996a778SMike Christie 	case STOP_CONN_TERM:
25527996a778SMike Christie 		iscsi_start_session_recovery(session, conn, flag);
25538d2860b3SMike Christie 		break;
25547996a778SMike Christie 	default:
2555322d739dSMike Christie 		iscsi_conn_printk(KERN_ERR, conn,
2556322d739dSMike Christie 				  "invalid stop flag %d\n", flag);
25577996a778SMike Christie 	}
25587996a778SMike Christie }
25597996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_stop);
25607996a778SMike Christie 
25617996a778SMike Christie int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
25627996a778SMike Christie 		    struct iscsi_cls_conn *cls_conn, int is_leading)
25637996a778SMike Christie {
256475613521SMike Christie 	struct iscsi_session *session = cls_session->dd_data;
256598644047SMike Christie 	struct iscsi_conn *conn = cls_conn->dd_data;
25667996a778SMike Christie 
25677996a778SMike Christie 	spin_lock_bh(&session->lock);
25687996a778SMike Christie 	if (is_leading)
25697996a778SMike Christie 		session->leadconn = conn;
257098644047SMike Christie 	spin_unlock_bh(&session->lock);
25717996a778SMike Christie 
25727996a778SMike Christie 	/*
25737996a778SMike Christie 	 * Unblock xmitworker(), Login Phase will pass through.
25747996a778SMike Christie 	 */
25757996a778SMike Christie 	clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
25767996a778SMike Christie 	clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
25777996a778SMike Christie 	return 0;
25787996a778SMike Christie }
25797996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_bind);
25807996a778SMike Christie 
2581a54a52caSMike Christie 
2582a54a52caSMike Christie int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
2583a54a52caSMike Christie 		    enum iscsi_param param, char *buf, int buflen)
2584a54a52caSMike Christie {
2585a54a52caSMike Christie 	struct iscsi_conn *conn = cls_conn->dd_data;
2586a54a52caSMike Christie 	struct iscsi_session *session = conn->session;
2587a54a52caSMike Christie 	uint32_t value;
2588a54a52caSMike Christie 
2589a54a52caSMike Christie 	switch(param) {
2590843c0a8aSMike Christie 	case ISCSI_PARAM_FAST_ABORT:
2591843c0a8aSMike Christie 		sscanf(buf, "%d", &session->fast_abort);
2592843c0a8aSMike Christie 		break;
2593f6d5180cSMike Christie 	case ISCSI_PARAM_ABORT_TMO:
2594f6d5180cSMike Christie 		sscanf(buf, "%d", &session->abort_timeout);
2595f6d5180cSMike Christie 		break;
2596f6d5180cSMike Christie 	case ISCSI_PARAM_LU_RESET_TMO:
2597f6d5180cSMike Christie 		sscanf(buf, "%d", &session->lu_reset_timeout);
2598f6d5180cSMike Christie 		break;
2599f6d5180cSMike Christie 	case ISCSI_PARAM_PING_TMO:
2600f6d5180cSMike Christie 		sscanf(buf, "%d", &conn->ping_timeout);
2601f6d5180cSMike Christie 		break;
2602f6d5180cSMike Christie 	case ISCSI_PARAM_RECV_TMO:
2603f6d5180cSMike Christie 		sscanf(buf, "%d", &conn->recv_timeout);
2604f6d5180cSMike Christie 		break;
2605a54a52caSMike Christie 	case ISCSI_PARAM_MAX_RECV_DLENGTH:
2606a54a52caSMike Christie 		sscanf(buf, "%d", &conn->max_recv_dlength);
2607a54a52caSMike Christie 		break;
2608a54a52caSMike Christie 	case ISCSI_PARAM_MAX_XMIT_DLENGTH:
2609a54a52caSMike Christie 		sscanf(buf, "%d", &conn->max_xmit_dlength);
2610a54a52caSMike Christie 		break;
2611a54a52caSMike Christie 	case ISCSI_PARAM_HDRDGST_EN:
2612a54a52caSMike Christie 		sscanf(buf, "%d", &conn->hdrdgst_en);
2613a54a52caSMike Christie 		break;
2614a54a52caSMike Christie 	case ISCSI_PARAM_DATADGST_EN:
2615a54a52caSMike Christie 		sscanf(buf, "%d", &conn->datadgst_en);
2616a54a52caSMike Christie 		break;
2617a54a52caSMike Christie 	case ISCSI_PARAM_INITIAL_R2T_EN:
2618a54a52caSMike Christie 		sscanf(buf, "%d", &session->initial_r2t_en);
2619a54a52caSMike Christie 		break;
2620a54a52caSMike Christie 	case ISCSI_PARAM_MAX_R2T:
2621a54a52caSMike Christie 		sscanf(buf, "%d", &session->max_r2t);
2622a54a52caSMike Christie 		break;
2623a54a52caSMike Christie 	case ISCSI_PARAM_IMM_DATA_EN:
2624a54a52caSMike Christie 		sscanf(buf, "%d", &session->imm_data_en);
2625a54a52caSMike Christie 		break;
2626a54a52caSMike Christie 	case ISCSI_PARAM_FIRST_BURST:
2627a54a52caSMike Christie 		sscanf(buf, "%d", &session->first_burst);
2628a54a52caSMike Christie 		break;
2629a54a52caSMike Christie 	case ISCSI_PARAM_MAX_BURST:
2630a54a52caSMike Christie 		sscanf(buf, "%d", &session->max_burst);
2631a54a52caSMike Christie 		break;
2632a54a52caSMike Christie 	case ISCSI_PARAM_PDU_INORDER_EN:
2633a54a52caSMike Christie 		sscanf(buf, "%d", &session->pdu_inorder_en);
2634a54a52caSMike Christie 		break;
2635a54a52caSMike Christie 	case ISCSI_PARAM_DATASEQ_INORDER_EN:
2636a54a52caSMike Christie 		sscanf(buf, "%d", &session->dataseq_inorder_en);
2637a54a52caSMike Christie 		break;
2638a54a52caSMike Christie 	case ISCSI_PARAM_ERL:
2639a54a52caSMike Christie 		sscanf(buf, "%d", &session->erl);
2640a54a52caSMike Christie 		break;
2641a54a52caSMike Christie 	case ISCSI_PARAM_IFMARKER_EN:
2642a54a52caSMike Christie 		sscanf(buf, "%d", &value);
2643a54a52caSMike Christie 		BUG_ON(value);
2644a54a52caSMike Christie 		break;
2645a54a52caSMike Christie 	case ISCSI_PARAM_OFMARKER_EN:
2646a54a52caSMike Christie 		sscanf(buf, "%d", &value);
2647a54a52caSMike Christie 		BUG_ON(value);
2648a54a52caSMike Christie 		break;
2649a54a52caSMike Christie 	case ISCSI_PARAM_EXP_STATSN:
2650a54a52caSMike Christie 		sscanf(buf, "%u", &conn->exp_statsn);
2651a54a52caSMike Christie 		break;
2652b2c64167SMike Christie 	case ISCSI_PARAM_USERNAME:
2653b2c64167SMike Christie 		kfree(session->username);
2654b2c64167SMike Christie 		session->username = kstrdup(buf, GFP_KERNEL);
2655b2c64167SMike Christie 		if (!session->username)
2656b2c64167SMike Christie 			return -ENOMEM;
2657b2c64167SMike Christie 		break;
2658b2c64167SMike Christie 	case ISCSI_PARAM_USERNAME_IN:
2659b2c64167SMike Christie 		kfree(session->username_in);
2660b2c64167SMike Christie 		session->username_in = kstrdup(buf, GFP_KERNEL);
2661b2c64167SMike Christie 		if (!session->username_in)
2662b2c64167SMike Christie 			return -ENOMEM;
2663b2c64167SMike Christie 		break;
2664b2c64167SMike Christie 	case ISCSI_PARAM_PASSWORD:
2665b2c64167SMike Christie 		kfree(session->password);
2666b2c64167SMike Christie 		session->password = kstrdup(buf, GFP_KERNEL);
2667b2c64167SMike Christie 		if (!session->password)
2668b2c64167SMike Christie 			return -ENOMEM;
2669b2c64167SMike Christie 		break;
2670b2c64167SMike Christie 	case ISCSI_PARAM_PASSWORD_IN:
2671b2c64167SMike Christie 		kfree(session->password_in);
2672b2c64167SMike Christie 		session->password_in = kstrdup(buf, GFP_KERNEL);
2673b2c64167SMike Christie 		if (!session->password_in)
2674b2c64167SMike Christie 			return -ENOMEM;
2675b2c64167SMike Christie 		break;
2676a54a52caSMike Christie 	case ISCSI_PARAM_TARGET_NAME:
2677a54a52caSMike Christie 		/* this should not change between logins */
2678a54a52caSMike Christie 		if (session->targetname)
2679a54a52caSMike Christie 			break;
2680a54a52caSMike Christie 
2681a54a52caSMike Christie 		session->targetname = kstrdup(buf, GFP_KERNEL);
2682a54a52caSMike Christie 		if (!session->targetname)
2683a54a52caSMike Christie 			return -ENOMEM;
2684a54a52caSMike Christie 		break;
2685a54a52caSMike Christie 	case ISCSI_PARAM_TPGT:
2686a54a52caSMike Christie 		sscanf(buf, "%d", &session->tpgt);
2687a54a52caSMike Christie 		break;
2688a54a52caSMike Christie 	case ISCSI_PARAM_PERSISTENT_PORT:
2689a54a52caSMike Christie 		sscanf(buf, "%d", &conn->persistent_port);
2690a54a52caSMike Christie 		break;
2691a54a52caSMike Christie 	case ISCSI_PARAM_PERSISTENT_ADDRESS:
2692a54a52caSMike Christie 		/*
2693a54a52caSMike Christie 		 * this is the address returned in discovery so it should
2694a54a52caSMike Christie 		 * not change between logins.
2695a54a52caSMike Christie 		 */
2696a54a52caSMike Christie 		if (conn->persistent_address)
2697a54a52caSMike Christie 			break;
2698a54a52caSMike Christie 
2699a54a52caSMike Christie 		conn->persistent_address = kstrdup(buf, GFP_KERNEL);
2700a54a52caSMike Christie 		if (!conn->persistent_address)
2701a54a52caSMike Christie 			return -ENOMEM;
2702a54a52caSMike Christie 		break;
270388dfd340SMike Christie 	case ISCSI_PARAM_IFACE_NAME:
270488dfd340SMike Christie 		if (!session->ifacename)
270588dfd340SMike Christie 			session->ifacename = kstrdup(buf, GFP_KERNEL);
270688dfd340SMike Christie 		break;
270788dfd340SMike Christie 	case ISCSI_PARAM_INITIATOR_NAME:
270888dfd340SMike Christie 		if (!session->initiatorname)
270988dfd340SMike Christie 			session->initiatorname = kstrdup(buf, GFP_KERNEL);
271088dfd340SMike Christie 		break;
2711a54a52caSMike Christie 	default:
2712a54a52caSMike Christie 		return -ENOSYS;
2713a54a52caSMike Christie 	}
2714a54a52caSMike Christie 
2715a54a52caSMike Christie 	return 0;
2716a54a52caSMike Christie }
2717a54a52caSMike Christie EXPORT_SYMBOL_GPL(iscsi_set_param);
2718a54a52caSMike Christie 
2719a54a52caSMike Christie int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
2720a54a52caSMike Christie 			    enum iscsi_param param, char *buf)
2721a54a52caSMike Christie {
272275613521SMike Christie 	struct iscsi_session *session = cls_session->dd_data;
2723a54a52caSMike Christie 	int len;
2724a54a52caSMike Christie 
2725a54a52caSMike Christie 	switch(param) {
2726843c0a8aSMike Christie 	case ISCSI_PARAM_FAST_ABORT:
2727843c0a8aSMike Christie 		len = sprintf(buf, "%d\n", session->fast_abort);
2728843c0a8aSMike Christie 		break;
2729f6d5180cSMike Christie 	case ISCSI_PARAM_ABORT_TMO:
2730f6d5180cSMike Christie 		len = sprintf(buf, "%d\n", session->abort_timeout);
2731f6d5180cSMike Christie 		break;
2732f6d5180cSMike Christie 	case ISCSI_PARAM_LU_RESET_TMO:
2733f6d5180cSMike Christie 		len = sprintf(buf, "%d\n", session->lu_reset_timeout);
2734f6d5180cSMike Christie 		break;
2735a54a52caSMike Christie 	case ISCSI_PARAM_INITIAL_R2T_EN:
2736a54a52caSMike Christie 		len = sprintf(buf, "%d\n", session->initial_r2t_en);
2737a54a52caSMike Christie 		break;
2738a54a52caSMike Christie 	case ISCSI_PARAM_MAX_R2T:
2739a54a52caSMike Christie 		len = sprintf(buf, "%hu\n", session->max_r2t);
2740a54a52caSMike Christie 		break;
2741a54a52caSMike Christie 	case ISCSI_PARAM_IMM_DATA_EN:
2742a54a52caSMike Christie 		len = sprintf(buf, "%d\n", session->imm_data_en);
2743a54a52caSMike Christie 		break;
2744a54a52caSMike Christie 	case ISCSI_PARAM_FIRST_BURST:
2745a54a52caSMike Christie 		len = sprintf(buf, "%u\n", session->first_burst);
2746a54a52caSMike Christie 		break;
2747a54a52caSMike Christie 	case ISCSI_PARAM_MAX_BURST:
2748a54a52caSMike Christie 		len = sprintf(buf, "%u\n", session->max_burst);
2749a54a52caSMike Christie 		break;
2750a54a52caSMike Christie 	case ISCSI_PARAM_PDU_INORDER_EN:
2751a54a52caSMike Christie 		len = sprintf(buf, "%d\n", session->pdu_inorder_en);
2752a54a52caSMike Christie 		break;
2753a54a52caSMike Christie 	case ISCSI_PARAM_DATASEQ_INORDER_EN:
2754a54a52caSMike Christie 		len = sprintf(buf, "%d\n", session->dataseq_inorder_en);
2755a54a52caSMike Christie 		break;
2756a54a52caSMike Christie 	case ISCSI_PARAM_ERL:
2757a54a52caSMike Christie 		len = sprintf(buf, "%d\n", session->erl);
2758a54a52caSMike Christie 		break;
2759a54a52caSMike Christie 	case ISCSI_PARAM_TARGET_NAME:
2760a54a52caSMike Christie 		len = sprintf(buf, "%s\n", session->targetname);
2761a54a52caSMike Christie 		break;
2762a54a52caSMike Christie 	case ISCSI_PARAM_TPGT:
2763a54a52caSMike Christie 		len = sprintf(buf, "%d\n", session->tpgt);
2764a54a52caSMike Christie 		break;
2765b2c64167SMike Christie 	case ISCSI_PARAM_USERNAME:
2766b2c64167SMike Christie 		len = sprintf(buf, "%s\n", session->username);
2767b2c64167SMike Christie 		break;
2768b2c64167SMike Christie 	case ISCSI_PARAM_USERNAME_IN:
2769b2c64167SMike Christie 		len = sprintf(buf, "%s\n", session->username_in);
2770b2c64167SMike Christie 		break;
2771b2c64167SMike Christie 	case ISCSI_PARAM_PASSWORD:
2772b2c64167SMike Christie 		len = sprintf(buf, "%s\n", session->password);
2773b2c64167SMike Christie 		break;
2774b2c64167SMike Christie 	case ISCSI_PARAM_PASSWORD_IN:
2775b2c64167SMike Christie 		len = sprintf(buf, "%s\n", session->password_in);
2776b2c64167SMike Christie 		break;
277788dfd340SMike Christie 	case ISCSI_PARAM_IFACE_NAME:
277888dfd340SMike Christie 		len = sprintf(buf, "%s\n", session->ifacename);
277988dfd340SMike Christie 		break;
278088dfd340SMike Christie 	case ISCSI_PARAM_INITIATOR_NAME:
278188dfd340SMike Christie 		if (!session->initiatorname)
278288dfd340SMike Christie 			len = sprintf(buf, "%s\n", "unknown");
278388dfd340SMike Christie 		else
278488dfd340SMike Christie 			len = sprintf(buf, "%s\n", session->initiatorname);
278588dfd340SMike Christie 		break;
2786a54a52caSMike Christie 	default:
2787a54a52caSMike Christie 		return -ENOSYS;
2788a54a52caSMike Christie 	}
2789a54a52caSMike Christie 
2790a54a52caSMike Christie 	return len;
2791a54a52caSMike Christie }
2792a54a52caSMike Christie EXPORT_SYMBOL_GPL(iscsi_session_get_param);
2793a54a52caSMike Christie 
2794a54a52caSMike Christie int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
2795a54a52caSMike Christie 			 enum iscsi_param param, char *buf)
2796a54a52caSMike Christie {
2797a54a52caSMike Christie 	struct iscsi_conn *conn = cls_conn->dd_data;
2798a54a52caSMike Christie 	int len;
2799a54a52caSMike Christie 
2800a54a52caSMike Christie 	switch(param) {
2801f6d5180cSMike Christie 	case ISCSI_PARAM_PING_TMO:
2802f6d5180cSMike Christie 		len = sprintf(buf, "%u\n", conn->ping_timeout);
2803f6d5180cSMike Christie 		break;
2804f6d5180cSMike Christie 	case ISCSI_PARAM_RECV_TMO:
2805f6d5180cSMike Christie 		len = sprintf(buf, "%u\n", conn->recv_timeout);
2806f6d5180cSMike Christie 		break;
2807a54a52caSMike Christie 	case ISCSI_PARAM_MAX_RECV_DLENGTH:
2808a54a52caSMike Christie 		len = sprintf(buf, "%u\n", conn->max_recv_dlength);
2809a54a52caSMike Christie 		break;
2810a54a52caSMike Christie 	case ISCSI_PARAM_MAX_XMIT_DLENGTH:
2811a54a52caSMike Christie 		len = sprintf(buf, "%u\n", conn->max_xmit_dlength);
2812a54a52caSMike Christie 		break;
2813a54a52caSMike Christie 	case ISCSI_PARAM_HDRDGST_EN:
2814a54a52caSMike Christie 		len = sprintf(buf, "%d\n", conn->hdrdgst_en);
2815a54a52caSMike Christie 		break;
2816a54a52caSMike Christie 	case ISCSI_PARAM_DATADGST_EN:
2817a54a52caSMike Christie 		len = sprintf(buf, "%d\n", conn->datadgst_en);
2818a54a52caSMike Christie 		break;
2819a54a52caSMike Christie 	case ISCSI_PARAM_IFMARKER_EN:
2820a54a52caSMike Christie 		len = sprintf(buf, "%d\n", conn->ifmarker_en);
2821a54a52caSMike Christie 		break;
2822a54a52caSMike Christie 	case ISCSI_PARAM_OFMARKER_EN:
2823a54a52caSMike Christie 		len = sprintf(buf, "%d\n", conn->ofmarker_en);
2824a54a52caSMike Christie 		break;
2825a54a52caSMike Christie 	case ISCSI_PARAM_EXP_STATSN:
2826a54a52caSMike Christie 		len = sprintf(buf, "%u\n", conn->exp_statsn);
2827a54a52caSMike Christie 		break;
2828a54a52caSMike Christie 	case ISCSI_PARAM_PERSISTENT_PORT:
2829a54a52caSMike Christie 		len = sprintf(buf, "%d\n", conn->persistent_port);
2830a54a52caSMike Christie 		break;
2831a54a52caSMike Christie 	case ISCSI_PARAM_PERSISTENT_ADDRESS:
2832a54a52caSMike Christie 		len = sprintf(buf, "%s\n", conn->persistent_address);
2833a54a52caSMike Christie 		break;
2834a54a52caSMike Christie 	default:
2835a54a52caSMike Christie 		return -ENOSYS;
2836a54a52caSMike Christie 	}
2837a54a52caSMike Christie 
2838a54a52caSMike Christie 	return len;
2839a54a52caSMike Christie }
2840a54a52caSMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_get_param);
2841a54a52caSMike Christie 
28420801c242SMike Christie int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param,
28430801c242SMike Christie 			 char *buf)
28440801c242SMike Christie {
284575613521SMike Christie 	struct iscsi_host *ihost = shost_priv(shost);
28460801c242SMike Christie 	int len;
28470801c242SMike Christie 
28480801c242SMike Christie 	switch (param) {
2849d8196ed2SMike Christie 	case ISCSI_HOST_PARAM_NETDEV_NAME:
285075613521SMike Christie 		if (!ihost->netdev)
2851d8196ed2SMike Christie 			len = sprintf(buf, "%s\n", "default");
2852d8196ed2SMike Christie 		else
285375613521SMike Christie 			len = sprintf(buf, "%s\n", ihost->netdev);
2854d8196ed2SMike Christie 		break;
28550801c242SMike Christie 	case ISCSI_HOST_PARAM_HWADDRESS:
285675613521SMike Christie 		if (!ihost->hwaddress)
28570801c242SMike Christie 			len = sprintf(buf, "%s\n", "default");
28580801c242SMike Christie 		else
285975613521SMike Christie 			len = sprintf(buf, "%s\n", ihost->hwaddress);
28600801c242SMike Christie 		break;
28618ad5781aSMike Christie 	case ISCSI_HOST_PARAM_INITIATOR_NAME:
286275613521SMike Christie 		if (!ihost->initiatorname)
28638ad5781aSMike Christie 			len = sprintf(buf, "%s\n", "unknown");
28648ad5781aSMike Christie 		else
286575613521SMike Christie 			len = sprintf(buf, "%s\n", ihost->initiatorname);
28668ad5781aSMike Christie 		break;
286775613521SMike Christie 	case ISCSI_HOST_PARAM_IPADDRESS:
286875613521SMike Christie 		if (!strlen(ihost->local_address))
286975613521SMike Christie 			len = sprintf(buf, "%s\n", "unknown");
287075613521SMike Christie 		else
287175613521SMike Christie 			len = sprintf(buf, "%s\n",
287275613521SMike Christie 				      ihost->local_address);
287388dfd340SMike Christie 		break;
28740801c242SMike Christie 	default:
28750801c242SMike Christie 		return -ENOSYS;
28760801c242SMike Christie 	}
28770801c242SMike Christie 
28780801c242SMike Christie 	return len;
28790801c242SMike Christie }
28800801c242SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_get_param);
28810801c242SMike Christie 
28820801c242SMike Christie int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param,
28830801c242SMike Christie 			 char *buf, int buflen)
28840801c242SMike Christie {
288575613521SMike Christie 	struct iscsi_host *ihost = shost_priv(shost);
28860801c242SMike Christie 
28870801c242SMike Christie 	switch (param) {
2888d8196ed2SMike Christie 	case ISCSI_HOST_PARAM_NETDEV_NAME:
288975613521SMike Christie 		if (!ihost->netdev)
289075613521SMike Christie 			ihost->netdev = kstrdup(buf, GFP_KERNEL);
2891d8196ed2SMike Christie 		break;
28920801c242SMike Christie 	case ISCSI_HOST_PARAM_HWADDRESS:
289375613521SMike Christie 		if (!ihost->hwaddress)
289475613521SMike Christie 			ihost->hwaddress = kstrdup(buf, GFP_KERNEL);
28950801c242SMike Christie 		break;
28968ad5781aSMike Christie 	case ISCSI_HOST_PARAM_INITIATOR_NAME:
289775613521SMike Christie 		if (!ihost->initiatorname)
289875613521SMike Christie 			ihost->initiatorname = kstrdup(buf, GFP_KERNEL);
28998ad5781aSMike Christie 		break;
29000801c242SMike Christie 	default:
29010801c242SMike Christie 		return -ENOSYS;
29020801c242SMike Christie 	}
29030801c242SMike Christie 
29040801c242SMike Christie 	return 0;
29050801c242SMike Christie }
29060801c242SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_set_param);
29070801c242SMike Christie 
29087996a778SMike Christie MODULE_AUTHOR("Mike Christie");
29097996a778SMike Christie MODULE_DESCRIPTION("iSCSI library functions");
29107996a778SMike Christie MODULE_LICENSE("GPL");
2911