xref: /linux/drivers/scsi/libiscsi.c (revision ac26d41dee65167109e7cdcd0289b44ca61cd741)
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 
919c19a7d0SMike Christie void iscsi_prep_unsolicit_data_pdu(struct iscsi_task *task,
92ffd0436eSMike Christie 				   struct iscsi_data *hdr)
937996a778SMike Christie {
949c19a7d0SMike Christie 	struct iscsi_conn *conn = task->conn;
957996a778SMike Christie 
967996a778SMike Christie 	memset(hdr, 0, sizeof(struct iscsi_data));
977996a778SMike Christie 	hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG);
989c19a7d0SMike Christie 	hdr->datasn = cpu_to_be32(task->unsol_datasn);
999c19a7d0SMike Christie 	task->unsol_datasn++;
1007996a778SMike Christie 	hdr->opcode = ISCSI_OP_SCSI_DATA_OUT;
1019c19a7d0SMike Christie 	memcpy(hdr->lun, task->hdr->lun, sizeof(hdr->lun));
1027996a778SMike Christie 
1039c19a7d0SMike Christie 	hdr->itt = task->hdr->itt;
1047996a778SMike Christie 	hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
1059c19a7d0SMike Christie 	hdr->offset = cpu_to_be32(task->unsol_offset);
1067996a778SMike Christie 
1079c19a7d0SMike Christie 	if (task->unsol_count > conn->max_xmit_dlength) {
1087996a778SMike Christie 		hton24(hdr->dlength, conn->max_xmit_dlength);
1099c19a7d0SMike Christie 		task->data_count = conn->max_xmit_dlength;
1109c19a7d0SMike Christie 		task->unsol_offset += task->data_count;
1117996a778SMike Christie 		hdr->flags = 0;
1127996a778SMike Christie 	} else {
1139c19a7d0SMike Christie 		hton24(hdr->dlength, task->unsol_count);
1149c19a7d0SMike Christie 		task->data_count = task->unsol_count;
1157996a778SMike Christie 		hdr->flags = ISCSI_FLAG_CMD_FINAL;
1167996a778SMike Christie 	}
1177996a778SMike Christie }
1187996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu);
1197996a778SMike Christie 
1209c19a7d0SMike Christie static int iscsi_add_hdr(struct iscsi_task *task, unsigned len)
121004d6530SBoaz Harrosh {
1229c19a7d0SMike Christie 	unsigned exp_len = task->hdr_len + len;
123004d6530SBoaz Harrosh 
1249c19a7d0SMike Christie 	if (exp_len > task->hdr_max) {
125004d6530SBoaz Harrosh 		WARN_ON(1);
126004d6530SBoaz Harrosh 		return -EINVAL;
127004d6530SBoaz Harrosh 	}
128004d6530SBoaz Harrosh 
129004d6530SBoaz Harrosh 	WARN_ON(len & (ISCSI_PAD_LEN - 1)); /* caller must pad the AHS */
1309c19a7d0SMike Christie 	task->hdr_len = exp_len;
131004d6530SBoaz Harrosh 	return 0;
132004d6530SBoaz Harrosh }
133004d6530SBoaz Harrosh 
13438d1c069SBoaz Harrosh /*
13538d1c069SBoaz Harrosh  * make an extended cdb AHS
13638d1c069SBoaz Harrosh  */
1379c19a7d0SMike Christie static int iscsi_prep_ecdb_ahs(struct iscsi_task *task)
13838d1c069SBoaz Harrosh {
1399c19a7d0SMike Christie 	struct scsi_cmnd *cmd = task->sc;
14038d1c069SBoaz Harrosh 	unsigned rlen, pad_len;
14138d1c069SBoaz Harrosh 	unsigned short ahslength;
14238d1c069SBoaz Harrosh 	struct iscsi_ecdb_ahdr *ecdb_ahdr;
14338d1c069SBoaz Harrosh 	int rc;
14438d1c069SBoaz Harrosh 
1459c19a7d0SMike Christie 	ecdb_ahdr = iscsi_next_hdr(task);
14638d1c069SBoaz Harrosh 	rlen = cmd->cmd_len - ISCSI_CDB_SIZE;
14738d1c069SBoaz Harrosh 
14838d1c069SBoaz Harrosh 	BUG_ON(rlen > sizeof(ecdb_ahdr->ecdb));
14938d1c069SBoaz Harrosh 	ahslength = rlen + sizeof(ecdb_ahdr->reserved);
15038d1c069SBoaz Harrosh 
15138d1c069SBoaz Harrosh 	pad_len = iscsi_padding(rlen);
15238d1c069SBoaz Harrosh 
1539c19a7d0SMike Christie 	rc = iscsi_add_hdr(task, sizeof(ecdb_ahdr->ahslength) +
15438d1c069SBoaz Harrosh 	                   sizeof(ecdb_ahdr->ahstype) + ahslength + pad_len);
15538d1c069SBoaz Harrosh 	if (rc)
15638d1c069SBoaz Harrosh 		return rc;
15738d1c069SBoaz Harrosh 
15838d1c069SBoaz Harrosh 	if (pad_len)
15938d1c069SBoaz Harrosh 		memset(&ecdb_ahdr->ecdb[rlen], 0, pad_len);
16038d1c069SBoaz Harrosh 
16138d1c069SBoaz Harrosh 	ecdb_ahdr->ahslength = cpu_to_be16(ahslength);
16238d1c069SBoaz Harrosh 	ecdb_ahdr->ahstype = ISCSI_AHSTYPE_CDB;
16338d1c069SBoaz Harrosh 	ecdb_ahdr->reserved = 0;
16438d1c069SBoaz Harrosh 	memcpy(ecdb_ahdr->ecdb, cmd->cmnd + ISCSI_CDB_SIZE, rlen);
16538d1c069SBoaz Harrosh 
16638d1c069SBoaz Harrosh 	debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d "
16738d1c069SBoaz Harrosh 		   "rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n",
1689c19a7d0SMike Christie 		   cmd->cmd_len, rlen, pad_len, ahslength, task->hdr_len);
16938d1c069SBoaz Harrosh 
17038d1c069SBoaz Harrosh 	return 0;
17138d1c069SBoaz Harrosh }
17238d1c069SBoaz Harrosh 
1739c19a7d0SMike Christie static int iscsi_prep_bidi_ahs(struct iscsi_task *task)
174c07d4444SBoaz Harrosh {
1759c19a7d0SMike Christie 	struct scsi_cmnd *sc = task->sc;
176c07d4444SBoaz Harrosh 	struct iscsi_rlength_ahdr *rlen_ahdr;
177c07d4444SBoaz Harrosh 	int rc;
178c07d4444SBoaz Harrosh 
1799c19a7d0SMike Christie 	rlen_ahdr = iscsi_next_hdr(task);
1809c19a7d0SMike Christie 	rc = iscsi_add_hdr(task, sizeof(*rlen_ahdr));
181c07d4444SBoaz Harrosh 	if (rc)
182c07d4444SBoaz Harrosh 		return rc;
183c07d4444SBoaz Harrosh 
184c07d4444SBoaz Harrosh 	rlen_ahdr->ahslength =
185c07d4444SBoaz Harrosh 		cpu_to_be16(sizeof(rlen_ahdr->read_length) +
186c07d4444SBoaz Harrosh 						  sizeof(rlen_ahdr->reserved));
187c07d4444SBoaz Harrosh 	rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
188c07d4444SBoaz Harrosh 	rlen_ahdr->reserved = 0;
189c07d4444SBoaz Harrosh 	rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
190c07d4444SBoaz Harrosh 
191c07d4444SBoaz Harrosh 	debug_scsi("bidi-in rlen_ahdr->read_length(%d) "
192c07d4444SBoaz Harrosh 		   "rlen_ahdr->ahslength(%d)\n",
193c07d4444SBoaz Harrosh 		   be32_to_cpu(rlen_ahdr->read_length),
194c07d4444SBoaz Harrosh 		   be16_to_cpu(rlen_ahdr->ahslength));
195c07d4444SBoaz Harrosh 	return 0;
196c07d4444SBoaz Harrosh }
197c07d4444SBoaz Harrosh 
1987996a778SMike Christie /**
1997996a778SMike Christie  * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
2009c19a7d0SMike Christie  * @task: iscsi task
2017996a778SMike Christie  *
2027996a778SMike Christie  * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set
2037996a778SMike Christie  * fields like dlength or final based on how much data it sends
2047996a778SMike Christie  */
2059c19a7d0SMike Christie static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
2067996a778SMike Christie {
2079c19a7d0SMike Christie 	struct iscsi_conn *conn = task->conn;
2087996a778SMike Christie 	struct iscsi_session *session = conn->session;
2099c19a7d0SMike Christie 	struct iscsi_cmd *hdr = task->hdr;
2109c19a7d0SMike Christie 	struct scsi_cmnd *sc = task->sc;
21138d1c069SBoaz Harrosh 	unsigned hdrlength, cmd_len;
212004d6530SBoaz Harrosh 	int rc;
2137996a778SMike Christie 
2149c19a7d0SMike Christie 	task->hdr_len = 0;
2159c19a7d0SMike Christie 	rc = iscsi_add_hdr(task, sizeof(*hdr));
216004d6530SBoaz Harrosh 	if (rc)
217004d6530SBoaz Harrosh 		return rc;
2187996a778SMike Christie 	hdr->opcode = ISCSI_OP_SCSI_CMD;
2197996a778SMike Christie 	hdr->flags = ISCSI_ATTR_SIMPLE;
2207996a778SMike Christie 	int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
2219c19a7d0SMike Christie 	hdr->itt = build_itt(task->itt, session->age);
2227996a778SMike Christie 	hdr->cmdsn = cpu_to_be32(session->cmdsn);
2237996a778SMike Christie 	session->cmdsn++;
2247996a778SMike Christie 	hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
22538d1c069SBoaz Harrosh 	cmd_len = sc->cmd_len;
22638d1c069SBoaz Harrosh 	if (cmd_len < ISCSI_CDB_SIZE)
22738d1c069SBoaz Harrosh 		memset(&hdr->cdb[cmd_len], 0, ISCSI_CDB_SIZE - cmd_len);
22838d1c069SBoaz Harrosh 	else if (cmd_len > ISCSI_CDB_SIZE) {
2299c19a7d0SMike Christie 		rc = iscsi_prep_ecdb_ahs(task);
23038d1c069SBoaz Harrosh 		if (rc)
23138d1c069SBoaz Harrosh 			return rc;
23238d1c069SBoaz Harrosh 		cmd_len = ISCSI_CDB_SIZE;
23338d1c069SBoaz Harrosh 	}
23438d1c069SBoaz Harrosh 	memcpy(hdr->cdb, sc->cmnd, cmd_len);
2357996a778SMike Christie 
2369c19a7d0SMike Christie 	task->imm_count = 0;
237c07d4444SBoaz Harrosh 	if (scsi_bidi_cmnd(sc)) {
238c07d4444SBoaz Harrosh 		hdr->flags |= ISCSI_FLAG_CMD_READ;
2399c19a7d0SMike Christie 		rc = iscsi_prep_bidi_ahs(task);
240c07d4444SBoaz Harrosh 		if (rc)
241c07d4444SBoaz Harrosh 			return rc;
242c07d4444SBoaz Harrosh 	}
2437996a778SMike Christie 	if (sc->sc_data_direction == DMA_TO_DEVICE) {
244c07d4444SBoaz Harrosh 		unsigned out_len = scsi_out(sc)->length;
245c07d4444SBoaz Harrosh 		hdr->data_length = cpu_to_be32(out_len);
2467996a778SMike Christie 		hdr->flags |= ISCSI_FLAG_CMD_WRITE;
2477996a778SMike Christie 		/*
2487996a778SMike Christie 		 * Write counters:
2497996a778SMike Christie 		 *
2507996a778SMike Christie 		 *	imm_count	bytes to be sent right after
2517996a778SMike Christie 		 *			SCSI PDU Header
2527996a778SMike Christie 		 *
2537996a778SMike Christie 		 *	unsol_count	bytes(as Data-Out) to be sent
2547996a778SMike Christie 		 *			without	R2T ack right after
2557996a778SMike Christie 		 *			immediate data
2567996a778SMike Christie 		 *
2577996a778SMike Christie 		 *	r2t_data_count	bytes to be sent via R2T ack's
2587996a778SMike Christie 		 *
2597996a778SMike Christie 		 *      pad_count       bytes to be sent as zero-padding
2607996a778SMike Christie 		 */
2619c19a7d0SMike Christie 		task->unsol_count = 0;
2629c19a7d0SMike Christie 		task->unsol_offset = 0;
2639c19a7d0SMike Christie 		task->unsol_datasn = 0;
2647996a778SMike Christie 
2657996a778SMike Christie 		if (session->imm_data_en) {
266c07d4444SBoaz Harrosh 			if (out_len >= session->first_burst)
2679c19a7d0SMike Christie 				task->imm_count = min(session->first_burst,
2687996a778SMike Christie 							conn->max_xmit_dlength);
2697996a778SMike Christie 			else
2709c19a7d0SMike Christie 				task->imm_count = min(out_len,
2717996a778SMike Christie 							conn->max_xmit_dlength);
2729c19a7d0SMike Christie 			hton24(hdr->dlength, task->imm_count);
2737996a778SMike Christie 		} else
274a8ac6311SOlaf Kirch 			zero_data(hdr->dlength);
2757996a778SMike Christie 
276ffd0436eSMike Christie 		if (!session->initial_r2t_en) {
2779c19a7d0SMike Christie 			task->unsol_count = min(session->first_burst, out_len)
2789c19a7d0SMike Christie 							     - task->imm_count;
2799c19a7d0SMike Christie 			task->unsol_offset = task->imm_count;
280ffd0436eSMike Christie 		}
281ffd0436eSMike Christie 
2829c19a7d0SMike Christie 		if (!task->unsol_count)
2837996a778SMike Christie 			/* No unsolicit Data-Out's */
284a8ac6311SOlaf Kirch 			hdr->flags |= ISCSI_FLAG_CMD_FINAL;
2857996a778SMike Christie 	} else {
2867996a778SMike Christie 		hdr->flags |= ISCSI_FLAG_CMD_FINAL;
2877996a778SMike Christie 		zero_data(hdr->dlength);
288c07d4444SBoaz Harrosh 		hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
2897996a778SMike Christie 
2907996a778SMike Christie 		if (sc->sc_data_direction == DMA_FROM_DEVICE)
2917996a778SMike Christie 			hdr->flags |= ISCSI_FLAG_CMD_READ;
2927996a778SMike Christie 	}
2937996a778SMike Christie 
294004d6530SBoaz Harrosh 	/* calculate size of additional header segments (AHSs) */
2959c19a7d0SMike Christie 	hdrlength = task->hdr_len - sizeof(*hdr);
296004d6530SBoaz Harrosh 
297004d6530SBoaz Harrosh 	WARN_ON(hdrlength & (ISCSI_PAD_LEN-1));
298004d6530SBoaz Harrosh 	hdrlength /= ISCSI_PAD_LEN;
299004d6530SBoaz Harrosh 
300004d6530SBoaz Harrosh 	WARN_ON(hdrlength >= 256);
301004d6530SBoaz Harrosh 	hdr->hlength = hdrlength & 0xFF;
302004d6530SBoaz Harrosh 
3033e5c28adSMike Christie 	if (conn->session->tt->init_task &&
3049c19a7d0SMike Christie 	    conn->session->tt->init_task(task))
305052d0144SMike Christie 		return -EIO;
306052d0144SMike Christie 
3079c19a7d0SMike Christie 	task->state = ISCSI_TASK_RUNNING;
3089c19a7d0SMike Christie 	list_move_tail(&task->running, &conn->run_list);
30977a23c21SMike Christie 
310a8ac6311SOlaf Kirch 	conn->scsicmd_pdus_cnt++;
3113e5c28adSMike Christie 	debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
3123e5c28adSMike Christie 		   "bidi_len %d cmdsn %d win %d]\n", scsi_bidi_cmnd(sc) ?
3133e5c28adSMike Christie 		   "bidirectional" : sc->sc_data_direction == DMA_TO_DEVICE ?
3149c19a7d0SMike Christie 		   "write" : "read", conn->id, sc, sc->cmnd[0], task->itt,
3153e5c28adSMike Christie 		   scsi_bufflen(sc),
3163e5c28adSMike Christie 		   scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
31777a23c21SMike Christie 		   session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
318004d6530SBoaz Harrosh 	return 0;
3197996a778SMike Christie }
3207996a778SMike Christie 
3217996a778SMike Christie /**
3223e5c28adSMike Christie  * iscsi_complete_command - finish a task
3239c19a7d0SMike Christie  * @task: iscsi cmd task
3247996a778SMike Christie  *
3257996a778SMike Christie  * Must be called with session lock.
3263e5c28adSMike Christie  * This function returns the scsi command to scsi-ml or cleans
3273e5c28adSMike Christie  * up mgmt tasks then returns the task to the pool.
3287996a778SMike Christie  */
3299c19a7d0SMike Christie static void iscsi_complete_command(struct iscsi_task *task)
3307996a778SMike Christie {
3319c19a7d0SMike Christie 	struct iscsi_conn *conn = task->conn;
332c1635cb7SMike Christie 	struct iscsi_session *session = conn->session;
3339c19a7d0SMike Christie 	struct scsi_cmnd *sc = task->sc;
3347996a778SMike Christie 
3359c19a7d0SMike Christie 	list_del_init(&task->running);
3369c19a7d0SMike Christie 	task->state = ISCSI_TASK_COMPLETED;
3379c19a7d0SMike Christie 	task->sc = NULL;
3383e5c28adSMike Christie 
3399c19a7d0SMike Christie 	if (conn->task == task)
3409c19a7d0SMike Christie 		conn->task = NULL;
3413e5c28adSMike Christie 	/*
3429c19a7d0SMike Christie 	 * login task is preallocated so do not free
3433e5c28adSMike Christie 	 */
3449c19a7d0SMike Christie 	if (conn->login_task == task)
3453e5c28adSMike Christie 		return;
3463e5c28adSMike Christie 
3479c19a7d0SMike Christie 	__kfifo_put(session->cmdpool.queue, (void*)&task, sizeof(void*));
3483e5c28adSMike Christie 
3499c19a7d0SMike Christie 	if (conn->ping_task == task)
3509c19a7d0SMike Christie 		conn->ping_task = NULL;
3513e5c28adSMike Christie 
3523e5c28adSMike Christie 	if (sc) {
3539c19a7d0SMike Christie 		task->sc = NULL;
354f47f2cf5SMike Christie 		/* SCSI eh reuses commands to verify us */
355f47f2cf5SMike Christie 		sc->SCp.ptr = NULL;
3563e5c28adSMike Christie 		/*
3573e5c28adSMike Christie 		 * queue command may call this to free the task, but
3583e5c28adSMike Christie 		 * not have setup the sc callback
3593e5c28adSMike Christie 		 */
360052d0144SMike Christie 		if (sc->scsi_done)
3617996a778SMike Christie 			sc->scsi_done(sc);
3627996a778SMike Christie 	}
3633e5c28adSMike Christie }
3647996a778SMike Christie 
365913e5bf4SMike Christie void __iscsi_get_task(struct iscsi_task *task)
36660ecebf5SMike Christie {
3679c19a7d0SMike Christie 	atomic_inc(&task->refcount);
36860ecebf5SMike Christie }
369913e5bf4SMike Christie EXPORT_SYMBOL_GPL(__iscsi_get_task);
37060ecebf5SMike Christie 
3719c19a7d0SMike Christie static void __iscsi_put_task(struct iscsi_task *task)
37260ecebf5SMike Christie {
3739c19a7d0SMike Christie 	if (atomic_dec_and_test(&task->refcount))
3749c19a7d0SMike Christie 		iscsi_complete_command(task);
37560ecebf5SMike Christie }
37660ecebf5SMike Christie 
3779c19a7d0SMike Christie void iscsi_put_task(struct iscsi_task *task)
3783e5c28adSMike Christie {
3799c19a7d0SMike Christie 	struct iscsi_session *session = task->conn->session;
3803e5c28adSMike Christie 
3813e5c28adSMike Christie 	spin_lock_bh(&session->lock);
3829c19a7d0SMike Christie 	__iscsi_put_task(task);
3833e5c28adSMike Christie 	spin_unlock_bh(&session->lock);
3843e5c28adSMike Christie }
3859c19a7d0SMike Christie EXPORT_SYMBOL_GPL(iscsi_put_task);
3863e5c28adSMike Christie 
387b3a7ea8dSMike Christie /*
388b3a7ea8dSMike Christie  * session lock must be held
389b3a7ea8dSMike Christie  */
3909c19a7d0SMike Christie static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task,
391b3a7ea8dSMike Christie 			 int err)
392b3a7ea8dSMike Christie {
393b3a7ea8dSMike Christie 	struct scsi_cmnd *sc;
394b3a7ea8dSMike Christie 
3959c19a7d0SMike Christie 	sc = task->sc;
396b3a7ea8dSMike Christie 	if (!sc)
397b3a7ea8dSMike Christie 		return;
398b3a7ea8dSMike Christie 
3999c19a7d0SMike Christie 	if (task->state == ISCSI_TASK_PENDING)
400b3a7ea8dSMike Christie 		/*
401b3a7ea8dSMike Christie 		 * cmd never made it to the xmit thread, so we should not count
402b3a7ea8dSMike Christie 		 * the cmd in the sequencing
403b3a7ea8dSMike Christie 		 */
404b3a7ea8dSMike Christie 		conn->session->queued_cmdsn--;
405b3a7ea8dSMike Christie 	else
4069c19a7d0SMike Christie 		conn->session->tt->cleanup_task(conn, task);
407913e5bf4SMike Christie 	/*
408913e5bf4SMike Christie 	 * Check if cleanup_task dropped the lock and the command completed,
409913e5bf4SMike Christie 	 */
410913e5bf4SMike Christie 	if (!task->sc)
411913e5bf4SMike Christie 		return;
412b3a7ea8dSMike Christie 
413b3a7ea8dSMike Christie 	sc->result = err;
414c07d4444SBoaz Harrosh 	if (!scsi_bidi_cmnd(sc))
415b3a7ea8dSMike Christie 		scsi_set_resid(sc, scsi_bufflen(sc));
416c07d4444SBoaz Harrosh 	else {
417c07d4444SBoaz Harrosh 		scsi_out(sc)->resid = scsi_out(sc)->length;
418c07d4444SBoaz Harrosh 		scsi_in(sc)->resid = scsi_in(sc)->length;
419c07d4444SBoaz Harrosh 	}
4203e5c28adSMike Christie 
4219c19a7d0SMike Christie 	if (conn->task == task)
4229c19a7d0SMike Christie 		conn->task = NULL;
423b3a7ea8dSMike Christie 	/* release ref from queuecommand */
4249c19a7d0SMike Christie 	__iscsi_put_task(task);
425b3a7ea8dSMike Christie }
426b3a7ea8dSMike Christie 
4273e5c28adSMike Christie static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
4289c19a7d0SMike Christie 				struct iscsi_task *task)
429052d0144SMike Christie {
430052d0144SMike Christie 	struct iscsi_session *session = conn->session;
4319c19a7d0SMike Christie 	struct iscsi_hdr *hdr = (struct iscsi_hdr *)task->hdr;
432052d0144SMike Christie 	struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr;
433052d0144SMike Christie 
434052d0144SMike Christie 	if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
435052d0144SMike Christie 		return -ENOTCONN;
436052d0144SMike Christie 
437052d0144SMike Christie 	if (hdr->opcode != (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) &&
438052d0144SMike Christie 	    hdr->opcode != (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
439052d0144SMike Christie 		nop->exp_statsn = cpu_to_be32(conn->exp_statsn);
440052d0144SMike Christie 	/*
441052d0144SMike Christie 	 * pre-format CmdSN for outgoing PDU.
442052d0144SMike Christie 	 */
443052d0144SMike Christie 	nop->cmdsn = cpu_to_be32(session->cmdsn);
444052d0144SMike Christie 	if (hdr->itt != RESERVED_ITT) {
4459c19a7d0SMike Christie 		hdr->itt = build_itt(task->itt, session->age);
446052d0144SMike Christie 		/*
447052d0144SMike Christie 		 * TODO: We always use immediate, so we never hit this.
448052d0144SMike Christie 		 * If we start to send tmfs or nops as non-immediate then
449052d0144SMike Christie 		 * we should start checking the cmdsn numbers for mgmt tasks.
450052d0144SMike Christie 		 */
451052d0144SMike Christie 		if (conn->c_stage == ISCSI_CONN_STARTED &&
452052d0144SMike Christie 		    !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
453052d0144SMike Christie 			session->queued_cmdsn++;
454052d0144SMike Christie 			session->cmdsn++;
455052d0144SMike Christie 		}
456052d0144SMike Christie 	}
457052d0144SMike Christie 
4583e5c28adSMike Christie 	if (session->tt->init_task)
4599c19a7d0SMike Christie 		session->tt->init_task(task);
460052d0144SMike Christie 
461052d0144SMike Christie 	if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT)
462052d0144SMike Christie 		session->state = ISCSI_STATE_LOGGING_OUT;
463052d0144SMike Christie 
4649c19a7d0SMike Christie 	list_move_tail(&task->running, &conn->mgmt_run_list);
465052d0144SMike Christie 	debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n",
466052d0144SMike Christie 		   hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt,
4679c19a7d0SMike Christie 		   task->data_count);
468052d0144SMike Christie 	return 0;
469052d0144SMike Christie }
470052d0144SMike Christie 
4719c19a7d0SMike Christie static struct iscsi_task *
472f6d5180cSMike Christie __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
473f6d5180cSMike Christie 		      char *data, uint32_t data_size)
474f6d5180cSMike Christie {
475f6d5180cSMike Christie 	struct iscsi_session *session = conn->session;
4769c19a7d0SMike Christie 	struct iscsi_task *task;
477f6d5180cSMike Christie 
478f6d5180cSMike Christie 	if (session->state == ISCSI_STATE_TERMINATE)
479f6d5180cSMike Christie 		return NULL;
480f6d5180cSMike Christie 
481f6d5180cSMike Christie 	if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) ||
482f6d5180cSMike Christie 	    hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
483f6d5180cSMike Christie 		/*
484f6d5180cSMike Christie 		 * Login and Text are sent serially, in
485f6d5180cSMike Christie 		 * request-followed-by-response sequence.
4863e5c28adSMike Christie 		 * Same task can be used. Same ITT must be used.
4873e5c28adSMike Christie 		 * Note that login_task is preallocated at conn_create().
488f6d5180cSMike Christie 		 */
4899c19a7d0SMike Christie 		task = conn->login_task;
490f6d5180cSMike Christie 	else {
491f6d5180cSMike Christie 		BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
492f6d5180cSMike Christie 		BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
493f6d5180cSMike Christie 
4943e5c28adSMike Christie 		if (!__kfifo_get(session->cmdpool.queue,
4959c19a7d0SMike Christie 				 (void*)&task, sizeof(void*)))
496f6d5180cSMike Christie 			return NULL;
497052d0144SMike Christie 
498052d0144SMike Christie 		if ((hdr->opcode == (ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE)) &&
499052d0144SMike Christie 		     hdr->ttt == RESERVED_ITT) {
5009c19a7d0SMike Christie 			conn->ping_task = task;
501052d0144SMike Christie 			conn->last_ping = jiffies;
502052d0144SMike Christie 		}
503f6d5180cSMike Christie 	}
5043e5c28adSMike Christie 	/*
5053e5c28adSMike Christie 	 * released in complete pdu for task we expect a response for, and
5063e5c28adSMike Christie 	 * released by the lld when it has transmitted the task for
5073e5c28adSMike Christie 	 * pdus we do not expect a response for.
5083e5c28adSMike Christie 	 */
5099c19a7d0SMike Christie 	atomic_set(&task->refcount, 1);
5109c19a7d0SMike Christie 	task->conn = conn;
5119c19a7d0SMike Christie 	task->sc = NULL;
512f6d5180cSMike Christie 
513f6d5180cSMike Christie 	if (data_size) {
5149c19a7d0SMike Christie 		memcpy(task->data, data, data_size);
5159c19a7d0SMike Christie 		task->data_count = data_size;
516f6d5180cSMike Christie 	} else
5179c19a7d0SMike Christie 		task->data_count = 0;
518f6d5180cSMike Christie 
5199c19a7d0SMike Christie 	memcpy(task->hdr, hdr, sizeof(struct iscsi_hdr));
5209c19a7d0SMike Christie 	INIT_LIST_HEAD(&task->running);
5219c19a7d0SMike Christie 	list_add_tail(&task->running, &conn->mgmtqueue);
522052d0144SMike Christie 
523052d0144SMike Christie 	if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) {
5249c19a7d0SMike Christie 		if (iscsi_prep_mgmt_task(conn, task)) {
5259c19a7d0SMike Christie 			__iscsi_put_task(task);
526052d0144SMike Christie 			return NULL;
527052d0144SMike Christie 		}
528052d0144SMike Christie 
5299c19a7d0SMike Christie 		if (session->tt->xmit_task(task))
5309c19a7d0SMike Christie 			task = NULL;
531052d0144SMike Christie 
532052d0144SMike Christie 	} else
533052d0144SMike Christie 		scsi_queue_work(conn->session->host, &conn->xmitwork);
534052d0144SMike Christie 
5359c19a7d0SMike Christie 	return task;
536f6d5180cSMike Christie }
537f6d5180cSMike Christie 
538f6d5180cSMike Christie int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
539f6d5180cSMike Christie 			char *data, uint32_t data_size)
540f6d5180cSMike Christie {
541f6d5180cSMike Christie 	struct iscsi_conn *conn = cls_conn->dd_data;
542f6d5180cSMike Christie 	struct iscsi_session *session = conn->session;
543f6d5180cSMike Christie 	int err = 0;
544f6d5180cSMike Christie 
545f6d5180cSMike Christie 	spin_lock_bh(&session->lock);
546f6d5180cSMike Christie 	if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
547f6d5180cSMike Christie 		err = -EPERM;
548f6d5180cSMike Christie 	spin_unlock_bh(&session->lock);
549f6d5180cSMike Christie 	return err;
550f6d5180cSMike Christie }
551f6d5180cSMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
552f6d5180cSMike Christie 
5537996a778SMike Christie /**
5547996a778SMike Christie  * iscsi_cmd_rsp - SCSI Command Response processing
5557996a778SMike Christie  * @conn: iscsi connection
5567996a778SMike Christie  * @hdr: iscsi header
5579c19a7d0SMike Christie  * @task: scsi command task
5587996a778SMike Christie  * @data: cmd data buffer
5597996a778SMike Christie  * @datalen: len of buffer
5607996a778SMike Christie  *
5617996a778SMike Christie  * iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and
5629c19a7d0SMike Christie  * then completes the command and task.
5637996a778SMike Christie  **/
56477a23c21SMike Christie static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
5659c19a7d0SMike Christie 			       struct iscsi_task *task, char *data,
5667996a778SMike Christie 			       int datalen)
5677996a778SMike Christie {
5687996a778SMike Christie 	struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr;
5697996a778SMike Christie 	struct iscsi_session *session = conn->session;
5709c19a7d0SMike Christie 	struct scsi_cmnd *sc = task->sc;
5717996a778SMike Christie 
57277a23c21SMike Christie 	iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
5737996a778SMike Christie 	conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
5747996a778SMike Christie 
5757996a778SMike Christie 	sc->result = (DID_OK << 16) | rhdr->cmd_status;
5767996a778SMike Christie 
5777996a778SMike Christie 	if (rhdr->response != ISCSI_STATUS_CMD_COMPLETED) {
5787996a778SMike Christie 		sc->result = DID_ERROR << 16;
5797996a778SMike Christie 		goto out;
5807996a778SMike Christie 	}
5817996a778SMike Christie 
5827996a778SMike Christie 	if (rhdr->cmd_status == SAM_STAT_CHECK_CONDITION) {
5839b80cb4bSMike Christie 		uint16_t senselen;
5847996a778SMike Christie 
5857996a778SMike Christie 		if (datalen < 2) {
5867996a778SMike Christie invalid_datalen:
587322d739dSMike Christie 			iscsi_conn_printk(KERN_ERR,  conn,
588322d739dSMike Christie 					 "Got CHECK_CONDITION but invalid data "
589322d739dSMike Christie 					 "buffer size of %d\n", datalen);
5907996a778SMike Christie 			sc->result = DID_BAD_TARGET << 16;
5917996a778SMike Christie 			goto out;
5927996a778SMike Christie 		}
5937996a778SMike Christie 
5948f333991SHarvey Harrison 		senselen = get_unaligned_be16(data);
5957996a778SMike Christie 		if (datalen < senselen)
5967996a778SMike Christie 			goto invalid_datalen;
5977996a778SMike Christie 
5987996a778SMike Christie 		memcpy(sc->sense_buffer, data + 2,
5999b80cb4bSMike Christie 		       min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
6007996a778SMike Christie 		debug_scsi("copied %d bytes of sense\n",
6018eb00539SMike Christie 			   min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
6027996a778SMike Christie 	}
6037996a778SMike Christie 
604c07d4444SBoaz Harrosh 	if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
605c07d4444SBoaz Harrosh 			   ISCSI_FLAG_CMD_BIDI_OVERFLOW)) {
606c07d4444SBoaz Harrosh 		int res_count = be32_to_cpu(rhdr->bi_residual_count);
607c07d4444SBoaz Harrosh 
608c07d4444SBoaz Harrosh 		if (scsi_bidi_cmnd(sc) && res_count > 0 &&
609c07d4444SBoaz Harrosh 				(rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW ||
610c07d4444SBoaz Harrosh 				 res_count <= scsi_in(sc)->length))
611c07d4444SBoaz Harrosh 			scsi_in(sc)->resid = res_count;
612c07d4444SBoaz Harrosh 		else
613c07d4444SBoaz Harrosh 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
614c07d4444SBoaz Harrosh 	}
615c07d4444SBoaz Harrosh 
6167207fea4SBoaz Harrosh 	if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW |
6177207fea4SBoaz Harrosh 	                   ISCSI_FLAG_CMD_OVERFLOW)) {
6187996a778SMike Christie 		int res_count = be32_to_cpu(rhdr->residual_count);
6197996a778SMike Christie 
6207207fea4SBoaz Harrosh 		if (res_count > 0 &&
6217207fea4SBoaz Harrosh 		    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
6227207fea4SBoaz Harrosh 		     res_count <= scsi_bufflen(sc)))
623c07d4444SBoaz Harrosh 			/* write side for bidi or uni-io set_resid */
6241c138991SFUJITA Tomonori 			scsi_set_resid(sc, res_count);
6257996a778SMike Christie 		else
6267996a778SMike Christie 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
627c07d4444SBoaz Harrosh 	}
6287996a778SMike Christie out:
6297996a778SMike Christie 	debug_scsi("done [sc %lx res %d itt 0x%x]\n",
6309c19a7d0SMike Christie 		   (long)sc, sc->result, task->itt);
6317996a778SMike Christie 	conn->scsirsp_pdus_cnt++;
6327996a778SMike Christie 
6339c19a7d0SMike Christie 	__iscsi_put_task(task);
6347996a778SMike Christie }
6357996a778SMike Christie 
6367ea8b828SMike Christie static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
6377ea8b828SMike Christie {
6387ea8b828SMike Christie 	struct iscsi_tm_rsp *tmf = (struct iscsi_tm_rsp *)hdr;
6397ea8b828SMike Christie 
6407ea8b828SMike Christie 	conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
6417ea8b828SMike Christie 	conn->tmfrsp_pdus_cnt++;
6427ea8b828SMike Christie 
643843c0a8aSMike Christie 	if (conn->tmf_state != TMF_QUEUED)
6447ea8b828SMike Christie 		return;
6457ea8b828SMike Christie 
6467ea8b828SMike Christie 	if (tmf->response == ISCSI_TMF_RSP_COMPLETE)
647843c0a8aSMike Christie 		conn->tmf_state = TMF_SUCCESS;
6487ea8b828SMike Christie 	else if (tmf->response == ISCSI_TMF_RSP_NO_TASK)
649843c0a8aSMike Christie 		conn->tmf_state = TMF_NOT_FOUND;
6507ea8b828SMike Christie 	else
651843c0a8aSMike Christie 		conn->tmf_state = TMF_FAILED;
6527ea8b828SMike Christie 	wake_up(&conn->ehwait);
6537ea8b828SMike Christie }
6547ea8b828SMike Christie 
655f6d5180cSMike Christie static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
656f6d5180cSMike Christie {
657f6d5180cSMike Christie         struct iscsi_nopout hdr;
6589c19a7d0SMike Christie 	struct iscsi_task *task;
659f6d5180cSMike Christie 
6609c19a7d0SMike Christie 	if (!rhdr && conn->ping_task)
661f6d5180cSMike Christie 		return;
662f6d5180cSMike Christie 
663f6d5180cSMike Christie 	memset(&hdr, 0, sizeof(struct iscsi_nopout));
664f6d5180cSMike Christie 	hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
665f6d5180cSMike Christie 	hdr.flags = ISCSI_FLAG_CMD_FINAL;
666f6d5180cSMike Christie 
667f6d5180cSMike Christie 	if (rhdr) {
668f6d5180cSMike Christie 		memcpy(hdr.lun, rhdr->lun, 8);
669f6d5180cSMike Christie 		hdr.ttt = rhdr->ttt;
670f6d5180cSMike Christie 		hdr.itt = RESERVED_ITT;
671f6d5180cSMike Christie 	} else
672f6d5180cSMike Christie 		hdr.ttt = RESERVED_ITT;
673f6d5180cSMike Christie 
6749c19a7d0SMike Christie 	task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
6759c19a7d0SMike Christie 	if (!task)
676322d739dSMike Christie 		iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n");
677f6d5180cSMike Christie }
678f6d5180cSMike Christie 
67962f38300SMike Christie static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
68062f38300SMike Christie 			       char *data, int datalen)
68162f38300SMike Christie {
68262f38300SMike Christie 	struct iscsi_reject *reject = (struct iscsi_reject *)hdr;
68362f38300SMike Christie 	struct iscsi_hdr rejected_pdu;
68462f38300SMike Christie 	uint32_t itt;
68562f38300SMike Christie 
68662f38300SMike Christie 	conn->exp_statsn = be32_to_cpu(reject->statsn) + 1;
68762f38300SMike Christie 
68862f38300SMike Christie 	if (reject->reason == ISCSI_REASON_DATA_DIGEST_ERROR) {
68962f38300SMike Christie 		if (ntoh24(reject->dlength) > datalen)
69062f38300SMike Christie 			return ISCSI_ERR_PROTO;
69162f38300SMike Christie 
69262f38300SMike Christie 		if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) {
69362f38300SMike Christie 			memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
694b4377356SAl Viro 			itt = get_itt(rejected_pdu.itt);
695322d739dSMike Christie 			iscsi_conn_printk(KERN_ERR, conn,
696322d739dSMike Christie 					  "itt 0x%x had pdu (op 0x%x) rejected "
69762f38300SMike Christie 					  "due to DataDigest error.\n", itt,
69862f38300SMike Christie 					  rejected_pdu.opcode);
69962f38300SMike Christie 		}
70062f38300SMike Christie 	}
70162f38300SMike Christie 	return 0;
70262f38300SMike Christie }
70362f38300SMike Christie 
7047996a778SMike Christie /**
705913e5bf4SMike Christie  * iscsi_itt_to_task - look up task by itt
706913e5bf4SMike Christie  * @conn: iscsi connection
707913e5bf4SMike Christie  * @itt: itt
708913e5bf4SMike Christie  *
709913e5bf4SMike Christie  * This should be used for mgmt tasks like login and nops, or if
710913e5bf4SMike Christie  * the LDD's itt space does not include the session age.
711913e5bf4SMike Christie  *
712913e5bf4SMike Christie  * The session lock must be held.
713913e5bf4SMike Christie  */
714913e5bf4SMike Christie static struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
715913e5bf4SMike Christie {
716913e5bf4SMike Christie 	struct iscsi_session *session = conn->session;
717913e5bf4SMike Christie 	uint32_t i;
718913e5bf4SMike Christie 
719913e5bf4SMike Christie 	if (itt == RESERVED_ITT)
720913e5bf4SMike Christie 		return NULL;
721913e5bf4SMike Christie 
722913e5bf4SMike Christie 	i = get_itt(itt);
723913e5bf4SMike Christie 	if (i >= session->cmds_max)
724913e5bf4SMike Christie 		return NULL;
725913e5bf4SMike Christie 
726913e5bf4SMike Christie 	return session->cmds[i];
727913e5bf4SMike Christie }
728913e5bf4SMike Christie 
729913e5bf4SMike Christie /**
7307996a778SMike Christie  * __iscsi_complete_pdu - complete pdu
7317996a778SMike Christie  * @conn: iscsi conn
7327996a778SMike Christie  * @hdr: iscsi header
7337996a778SMike Christie  * @data: data buffer
7347996a778SMike Christie  * @datalen: len of data buffer
7357996a778SMike Christie  *
7367996a778SMike Christie  * Completes pdu processing by freeing any resources allocated at
7377996a778SMike Christie  * queuecommand or send generic. session lock must be held and verify
7387996a778SMike Christie  * itt must have been called.
7397996a778SMike Christie  */
740913e5bf4SMike Christie int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
7417996a778SMike Christie 			 char *data, int datalen)
7427996a778SMike Christie {
7437996a778SMike Christie 	struct iscsi_session *session = conn->session;
7447996a778SMike Christie 	int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0;
7459c19a7d0SMike Christie 	struct iscsi_task *task;
7467996a778SMike Christie 	uint32_t itt;
7477996a778SMike Christie 
748f6d5180cSMike Christie 	conn->last_recv = jiffies;
7490af967f5SMike Christie 	rc = iscsi_verify_itt(conn, hdr->itt);
7500af967f5SMike Christie 	if (rc)
7510af967f5SMike Christie 		return rc;
7520af967f5SMike Christie 
753b4377356SAl Viro 	if (hdr->itt != RESERVED_ITT)
754b4377356SAl Viro 		itt = get_itt(hdr->itt);
7557996a778SMike Christie 	else
756b4377356SAl Viro 		itt = ~0U;
7577996a778SMike Christie 
7583e5c28adSMike Christie 	debug_scsi("[op 0x%x cid %d itt 0x%x len %d]\n",
7593e5c28adSMike Christie 		   opcode, conn->id, itt, datalen);
7607996a778SMike Christie 
7613e5c28adSMike Christie 	if (itt == ~0U) {
76277a23c21SMike Christie 		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
76362f38300SMike Christie 
7647996a778SMike Christie 		switch(opcode) {
7657996a778SMike Christie 		case ISCSI_OP_NOOP_IN:
76640527afeSMike Christie 			if (datalen) {
76740527afeSMike Christie 				rc = ISCSI_ERR_PROTO;
76840527afeSMike Christie 				break;
76940527afeSMike Christie 			}
77040527afeSMike Christie 
771b4377356SAl Viro 			if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG))
77240527afeSMike Christie 				break;
77340527afeSMike Christie 
774f6d5180cSMike Christie 			iscsi_send_nopout(conn, (struct iscsi_nopin*)hdr);
7757996a778SMike Christie 			break;
7767996a778SMike Christie 		case ISCSI_OP_REJECT:
77762f38300SMike Christie 			rc = iscsi_handle_reject(conn, hdr, data, datalen);
77862f38300SMike Christie 			break;
7797996a778SMike Christie 		case ISCSI_OP_ASYNC_EVENT:
7808d2860b3SMike Christie 			conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
7815831c737SMike Christie 			if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
7825831c737SMike Christie 				rc = ISCSI_ERR_CONN_FAILED;
7837996a778SMike Christie 			break;
7847996a778SMike Christie 		default:
7857996a778SMike Christie 			rc = ISCSI_ERR_BAD_OPCODE;
7867996a778SMike Christie 			break;
7877996a778SMike Christie 		}
7883e5c28adSMike Christie 		goto out;
7893e5c28adSMike Christie 	}
7907996a778SMike Christie 
7913e5c28adSMike Christie 	switch(opcode) {
7923e5c28adSMike Christie 	case ISCSI_OP_SCSI_CMD_RSP:
793913e5bf4SMike Christie 	case ISCSI_OP_SCSI_DATA_IN:
794913e5bf4SMike Christie 		task = iscsi_itt_to_ctask(conn, hdr->itt);
795913e5bf4SMike Christie 		if (!task)
796913e5bf4SMike Christie 			return ISCSI_ERR_BAD_ITT;
7973e5c28adSMike Christie 		break;
798913e5bf4SMike Christie 	case ISCSI_OP_R2T:
799913e5bf4SMike Christie 		/*
800913e5bf4SMike Christie 		 * LLD handles R2Ts if they need to.
801913e5bf4SMike Christie 		 */
802913e5bf4SMike Christie 		return 0;
803913e5bf4SMike Christie 	case ISCSI_OP_LOGOUT_RSP:
804913e5bf4SMike Christie 	case ISCSI_OP_LOGIN_RSP:
805913e5bf4SMike Christie 	case ISCSI_OP_TEXT_RSP:
806913e5bf4SMike Christie 	case ISCSI_OP_SCSI_TMFUNC_RSP:
807913e5bf4SMike Christie 	case ISCSI_OP_NOOP_IN:
808913e5bf4SMike Christie 		task = iscsi_itt_to_task(conn, hdr->itt);
809913e5bf4SMike Christie 		if (!task)
810913e5bf4SMike Christie 			return ISCSI_ERR_BAD_ITT;
811913e5bf4SMike Christie 		break;
812913e5bf4SMike Christie 	default:
813913e5bf4SMike Christie 		return ISCSI_ERR_BAD_OPCODE;
8143e5c28adSMike Christie 	}
815913e5bf4SMike Christie 
816913e5bf4SMike Christie 	switch(opcode) {
817913e5bf4SMike Christie 	case ISCSI_OP_SCSI_CMD_RSP:
8189c19a7d0SMike Christie 		iscsi_scsi_cmd_rsp(conn, hdr, task, data, datalen);
8193e5c28adSMike Christie 		break;
8203e5c28adSMike Christie 	case ISCSI_OP_SCSI_DATA_IN:
8213e5c28adSMike Christie 		if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
8223e5c28adSMike Christie 			conn->scsirsp_pdus_cnt++;
8233e5c28adSMike Christie 			iscsi_update_cmdsn(session,
8243e5c28adSMike Christie 					   (struct iscsi_nopin*) hdr);
8259c19a7d0SMike Christie 			__iscsi_put_task(task);
8263e5c28adSMike Christie 		}
8273e5c28adSMike Christie 		break;
8283e5c28adSMike Christie 	case ISCSI_OP_LOGOUT_RSP:
8293e5c28adSMike Christie 		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
8303e5c28adSMike Christie 		if (datalen) {
8313e5c28adSMike Christie 			rc = ISCSI_ERR_PROTO;
8323e5c28adSMike Christie 			break;
8333e5c28adSMike Christie 		}
8343e5c28adSMike Christie 		conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
8353e5c28adSMike Christie 		goto recv_pdu;
8363e5c28adSMike Christie 	case ISCSI_OP_LOGIN_RSP:
8373e5c28adSMike Christie 	case ISCSI_OP_TEXT_RSP:
8383e5c28adSMike Christie 		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
8393e5c28adSMike Christie 		/*
8403e5c28adSMike Christie 		 * login related PDU's exp_statsn is handled in
8413e5c28adSMike Christie 		 * userspace
8423e5c28adSMike Christie 		 */
8433e5c28adSMike Christie 		goto recv_pdu;
8443e5c28adSMike Christie 	case ISCSI_OP_SCSI_TMFUNC_RSP:
8453e5c28adSMike Christie 		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
8463e5c28adSMike Christie 		if (datalen) {
8473e5c28adSMike Christie 			rc = ISCSI_ERR_PROTO;
8483e5c28adSMike Christie 			break;
8493e5c28adSMike Christie 		}
8503e5c28adSMike Christie 
8513e5c28adSMike Christie 		iscsi_tmf_rsp(conn, hdr);
8529c19a7d0SMike Christie 		__iscsi_put_task(task);
8533e5c28adSMike Christie 		break;
8543e5c28adSMike Christie 	case ISCSI_OP_NOOP_IN:
8553e5c28adSMike Christie 		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
8563e5c28adSMike Christie 		if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) {
8573e5c28adSMike Christie 			rc = ISCSI_ERR_PROTO;
8583e5c28adSMike Christie 			break;
8593e5c28adSMike Christie 		}
8603e5c28adSMike Christie 		conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
8613e5c28adSMike Christie 
8629c19a7d0SMike Christie 		if (conn->ping_task != task)
8633e5c28adSMike Christie 			/*
8643e5c28adSMike Christie 			 * If this is not in response to one of our
8653e5c28adSMike Christie 			 * nops then it must be from userspace.
8663e5c28adSMike Christie 			 */
8673e5c28adSMike Christie 			goto recv_pdu;
8689c19a7d0SMike Christie 
8699c19a7d0SMike Christie 		mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout);
8709c19a7d0SMike Christie 		__iscsi_put_task(task);
8713e5c28adSMike Christie 		break;
8723e5c28adSMike Christie 	default:
8733e5c28adSMike Christie 		rc = ISCSI_ERR_BAD_OPCODE;
8743e5c28adSMike Christie 		break;
8753e5c28adSMike Christie 	}
8763e5c28adSMike Christie 
8773e5c28adSMike Christie out:
8783e5c28adSMike Christie 	return rc;
8793e5c28adSMike Christie recv_pdu:
8803e5c28adSMike Christie 	if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
8813e5c28adSMike Christie 		rc = ISCSI_ERR_CONN_FAILED;
8829c19a7d0SMike Christie 	__iscsi_put_task(task);
8837996a778SMike Christie 	return rc;
8847996a778SMike Christie }
885913e5bf4SMike Christie EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
8867996a778SMike Christie 
8877996a778SMike Christie int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
8887996a778SMike Christie 		       char *data, int datalen)
8897996a778SMike Christie {
8907996a778SMike Christie 	int rc;
8917996a778SMike Christie 
8927996a778SMike Christie 	spin_lock(&conn->session->lock);
8937996a778SMike Christie 	rc = __iscsi_complete_pdu(conn, hdr, data, datalen);
8947996a778SMike Christie 	spin_unlock(&conn->session->lock);
8957996a778SMike Christie 	return rc;
8967996a778SMike Christie }
8977996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_complete_pdu);
8987996a778SMike Christie 
8990af967f5SMike Christie int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt)
9007996a778SMike Christie {
9017996a778SMike Christie 	struct iscsi_session *session = conn->session;
9023e5c28adSMike Christie 	uint32_t i;
9037996a778SMike Christie 
9040af967f5SMike Christie 	if (itt == RESERVED_ITT)
9050af967f5SMike Christie 		return 0;
9060af967f5SMike Christie 
9070af967f5SMike Christie 	if (((__force u32)itt & ISCSI_AGE_MASK) !=
9087996a778SMike Christie 	    (session->age << ISCSI_AGE_SHIFT)) {
909322d739dSMike Christie 		iscsi_conn_printk(KERN_ERR, conn,
9100af967f5SMike Christie 				  "received itt %x expected session age (%x)\n",
911913e5bf4SMike Christie 				  (__force u32)itt, session->age);
9127996a778SMike Christie 		return ISCSI_ERR_BAD_ITT;
9137996a778SMike Christie 	}
9147996a778SMike Christie 
9153e5c28adSMike Christie 	i = get_itt(itt);
9163e5c28adSMike Christie 	if (i >= session->cmds_max) {
9173e5c28adSMike Christie 		iscsi_conn_printk(KERN_ERR, conn,
9183e5c28adSMike Christie 				  "received invalid itt index %u (max cmds "
9193e5c28adSMike Christie 				   "%u.\n", i, session->cmds_max);
9203e5c28adSMike Christie 		return ISCSI_ERR_BAD_ITT;
9217996a778SMike Christie 	}
9227996a778SMike Christie 	return 0;
9237996a778SMike Christie }
9247996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_verify_itt);
9257996a778SMike Christie 
926913e5bf4SMike Christie /**
927913e5bf4SMike Christie  * iscsi_itt_to_ctask - look up ctask by itt
928913e5bf4SMike Christie  * @conn: iscsi connection
929913e5bf4SMike Christie  * @itt: itt
930913e5bf4SMike Christie  *
931913e5bf4SMike Christie  * This should be used for cmd tasks.
932913e5bf4SMike Christie  *
933913e5bf4SMike Christie  * The session lock must be held.
934913e5bf4SMike Christie  */
935913e5bf4SMike Christie struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt)
9360af967f5SMike Christie {
9379c19a7d0SMike Christie 	struct iscsi_task *task;
9380af967f5SMike Christie 
9390af967f5SMike Christie 	if (iscsi_verify_itt(conn, itt))
9400af967f5SMike Christie 		return NULL;
9410af967f5SMike Christie 
942913e5bf4SMike Christie 	task = iscsi_itt_to_task(conn, itt);
943913e5bf4SMike Christie 	if (!task || !task->sc)
9440af967f5SMike Christie 		return NULL;
9450af967f5SMike Christie 
946913e5bf4SMike Christie 	if (task->sc->SCp.phase != conn->session->age) {
947913e5bf4SMike Christie 		iscsi_session_printk(KERN_ERR, conn->session,
948913e5bf4SMike Christie 				  "task's session age %d, expected %d\n",
949913e5bf4SMike Christie 				  task->sc->SCp.phase, conn->session->age);
9500af967f5SMike Christie 		return NULL;
951913e5bf4SMike Christie 	}
9520af967f5SMike Christie 
9539c19a7d0SMike Christie 	return task;
9540af967f5SMike Christie }
9550af967f5SMike Christie EXPORT_SYMBOL_GPL(iscsi_itt_to_ctask);
9560af967f5SMike Christie 
9577996a778SMike Christie void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
9587996a778SMike Christie {
9597996a778SMike Christie 	struct iscsi_session *session = conn->session;
9607996a778SMike Christie 	unsigned long flags;
9617996a778SMike Christie 
9627996a778SMike Christie 	spin_lock_irqsave(&session->lock, flags);
963656cffc9SMike Christie 	if (session->state == ISCSI_STATE_FAILED) {
964656cffc9SMike Christie 		spin_unlock_irqrestore(&session->lock, flags);
965656cffc9SMike Christie 		return;
966656cffc9SMike Christie 	}
967656cffc9SMike Christie 
96867a61114SMike Christie 	if (conn->stop_stage == 0)
9697996a778SMike Christie 		session->state = ISCSI_STATE_FAILED;
9707996a778SMike Christie 	spin_unlock_irqrestore(&session->lock, flags);
9717996a778SMike Christie 	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
9727996a778SMike Christie 	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
9737996a778SMike Christie 	iscsi_conn_error(conn->cls_conn, err);
9747996a778SMike Christie }
9757996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_failure);
9767996a778SMike Christie 
97777a23c21SMike Christie static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn)
97877a23c21SMike Christie {
97977a23c21SMike Christie 	struct iscsi_session *session = conn->session;
98077a23c21SMike Christie 
98177a23c21SMike Christie 	/*
98277a23c21SMike Christie 	 * Check for iSCSI window and take care of CmdSN wrap-around
98377a23c21SMike Christie 	 */
984e0726407SMike Christie 	if (!iscsi_sna_lte(session->queued_cmdsn, session->max_cmdsn)) {
985e0726407SMike Christie 		debug_scsi("iSCSI CmdSN closed. ExpCmdSn %u MaxCmdSN %u "
986e0726407SMike Christie 			   "CmdSN %u/%u\n", session->exp_cmdsn,
987e0726407SMike Christie 			   session->max_cmdsn, session->cmdsn,
988e0726407SMike Christie 			   session->queued_cmdsn);
98977a23c21SMike Christie 		return -ENOSPC;
99077a23c21SMike Christie 	}
99177a23c21SMike Christie 	return 0;
99277a23c21SMike Christie }
99377a23c21SMike Christie 
9949c19a7d0SMike Christie static int iscsi_xmit_task(struct iscsi_conn *conn)
99577a23c21SMike Christie {
9969c19a7d0SMike Christie 	struct iscsi_task *task = conn->task;
997843c0a8aSMike Christie 	int rc;
99877a23c21SMike Christie 
9999c19a7d0SMike Christie 	__iscsi_get_task(task);
100077a23c21SMike Christie 	spin_unlock_bh(&conn->session->lock);
10019c19a7d0SMike Christie 	rc = conn->session->tt->xmit_task(task);
100277a23c21SMike Christie 	spin_lock_bh(&conn->session->lock);
10039c19a7d0SMike Christie 	__iscsi_put_task(task);
100477a23c21SMike Christie 	if (!rc)
10059c19a7d0SMike Christie 		/* done with this task */
10069c19a7d0SMike Christie 		conn->task = NULL;
100777a23c21SMike Christie 	return rc;
100877a23c21SMike Christie }
100977a23c21SMike Christie 
10107996a778SMike Christie /**
10119c19a7d0SMike Christie  * iscsi_requeue_task - requeue task to run from session workqueue
10129c19a7d0SMike Christie  * @task: task to requeue
1013843c0a8aSMike Christie  *
10149c19a7d0SMike Christie  * LLDs that need to run a task from the session workqueue should call
1015052d0144SMike Christie  * this. The session lock must be held. This should only be called
1016052d0144SMike Christie  * by software drivers.
1017843c0a8aSMike Christie  */
10189c19a7d0SMike Christie void iscsi_requeue_task(struct iscsi_task *task)
1019843c0a8aSMike Christie {
10209c19a7d0SMike Christie 	struct iscsi_conn *conn = task->conn;
1021843c0a8aSMike Christie 
10229c19a7d0SMike Christie 	list_move_tail(&task->running, &conn->requeue);
1023843c0a8aSMike Christie 	scsi_queue_work(conn->session->host, &conn->xmitwork);
1024843c0a8aSMike Christie }
10259c19a7d0SMike Christie EXPORT_SYMBOL_GPL(iscsi_requeue_task);
1026843c0a8aSMike Christie 
1027843c0a8aSMike Christie /**
10287996a778SMike Christie  * iscsi_data_xmit - xmit any command into the scheduled connection
10297996a778SMike Christie  * @conn: iscsi connection
10307996a778SMike Christie  *
10317996a778SMike Christie  * Notes:
10327996a778SMike Christie  *	The function can return -EAGAIN in which case the caller must
10337996a778SMike Christie  *	re-schedule it again later or recover. '0' return code means
10347996a778SMike Christie  *	successful xmit.
10357996a778SMike Christie  **/
10367996a778SMike Christie static int iscsi_data_xmit(struct iscsi_conn *conn)
10377996a778SMike Christie {
10383219e529SMike Christie 	int rc = 0;
10397996a778SMike Christie 
104077a23c21SMike Christie 	spin_lock_bh(&conn->session->lock);
10417996a778SMike Christie 	if (unlikely(conn->suspend_tx)) {
10427996a778SMike Christie 		debug_scsi("conn %d Tx suspended!\n", conn->id);
104377a23c21SMike Christie 		spin_unlock_bh(&conn->session->lock);
10443219e529SMike Christie 		return -ENODATA;
10457996a778SMike Christie 	}
10467996a778SMike Christie 
10479c19a7d0SMike Christie 	if (conn->task) {
10489c19a7d0SMike Christie 		rc = iscsi_xmit_task(conn);
10493219e529SMike Christie 	        if (rc)
10507996a778SMike Christie 		        goto again;
10517996a778SMike Christie 	}
105277a23c21SMike Christie 
105377a23c21SMike Christie 	/*
105477a23c21SMike Christie 	 * process mgmt pdus like nops before commands since we should
105577a23c21SMike Christie 	 * only have one nop-out as a ping from us and targets should not
105677a23c21SMike Christie 	 * overflow us with nop-ins
105777a23c21SMike Christie 	 */
105877a23c21SMike Christie check_mgmt:
1059843c0a8aSMike Christie 	while (!list_empty(&conn->mgmtqueue)) {
10609c19a7d0SMike Christie 		conn->task = list_entry(conn->mgmtqueue.next,
10619c19a7d0SMike Christie 					 struct iscsi_task, running);
10629c19a7d0SMike Christie 		if (iscsi_prep_mgmt_task(conn, conn->task)) {
10639c19a7d0SMike Christie 			__iscsi_put_task(conn->task);
10649c19a7d0SMike Christie 			conn->task = NULL;
1065b3a7ea8dSMike Christie 			continue;
1066b3a7ea8dSMike Christie 		}
10679c19a7d0SMike Christie 		rc = iscsi_xmit_task(conn);
10683219e529SMike Christie 		if (rc)
10697996a778SMike Christie 			goto again;
10707996a778SMike Christie 	}
10717996a778SMike Christie 
1072843c0a8aSMike Christie 	/* process pending command queue */
1073b6c395edSMike Christie 	while (!list_empty(&conn->xmitqueue)) {
1074843c0a8aSMike Christie 		if (conn->tmf_state == TMF_QUEUED)
1075843c0a8aSMike Christie 			break;
1076843c0a8aSMike Christie 
10779c19a7d0SMike Christie 		conn->task = list_entry(conn->xmitqueue.next,
10789c19a7d0SMike Christie 					 struct iscsi_task, running);
1079b3a7ea8dSMike Christie 		if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
10809c19a7d0SMike Christie 			fail_command(conn, conn->task, DID_IMM_RETRY << 16);
1081b3a7ea8dSMike Christie 			continue;
1082b3a7ea8dSMike Christie 		}
10839c19a7d0SMike Christie 		if (iscsi_prep_scsi_cmd_pdu(conn->task)) {
10849c19a7d0SMike Christie 			fail_command(conn, conn->task, DID_ABORT << 16);
1085004d6530SBoaz Harrosh 			continue;
1086004d6530SBoaz Harrosh 		}
10879c19a7d0SMike Christie 		rc = iscsi_xmit_task(conn);
10883219e529SMike Christie 		if (rc)
10897996a778SMike Christie 			goto again;
109077a23c21SMike Christie 		/*
10919c19a7d0SMike Christie 		 * we could continuously get new task requests so
109277a23c21SMike Christie 		 * we need to check the mgmt queue for nops that need to
109377a23c21SMike Christie 		 * be sent to aviod starvation
109477a23c21SMike Christie 		 */
1095843c0a8aSMike Christie 		if (!list_empty(&conn->mgmtqueue))
1096843c0a8aSMike Christie 			goto check_mgmt;
1097843c0a8aSMike Christie 	}
1098843c0a8aSMike Christie 
1099843c0a8aSMike Christie 	while (!list_empty(&conn->requeue)) {
1100843c0a8aSMike Christie 		if (conn->session->fast_abort && conn->tmf_state != TMF_INITIAL)
1101843c0a8aSMike Christie 			break;
1102843c0a8aSMike Christie 
1103b3a7ea8dSMike Christie 		/*
1104b3a7ea8dSMike Christie 		 * we always do fastlogout - conn stop code will clean up.
1105b3a7ea8dSMike Christie 		 */
1106b3a7ea8dSMike Christie 		if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
1107b3a7ea8dSMike Christie 			break;
1108b3a7ea8dSMike Christie 
11099c19a7d0SMike Christie 		conn->task = list_entry(conn->requeue.next,
11109c19a7d0SMike Christie 					 struct iscsi_task, running);
11119c19a7d0SMike Christie 		conn->task->state = ISCSI_TASK_RUNNING;
1112843c0a8aSMike Christie 		list_move_tail(conn->requeue.next, &conn->run_list);
11139c19a7d0SMike Christie 		rc = iscsi_xmit_task(conn);
1114843c0a8aSMike Christie 		if (rc)
1115843c0a8aSMike Christie 			goto again;
1116843c0a8aSMike Christie 		if (!list_empty(&conn->mgmtqueue))
111777a23c21SMike Christie 			goto check_mgmt;
11187996a778SMike Christie 	}
111977a23c21SMike Christie 	spin_unlock_bh(&conn->session->lock);
11203219e529SMike Christie 	return -ENODATA;
11217996a778SMike Christie 
11227996a778SMike Christie again:
11237996a778SMike Christie 	if (unlikely(conn->suspend_tx))
112477a23c21SMike Christie 		rc = -ENODATA;
112577a23c21SMike Christie 	spin_unlock_bh(&conn->session->lock);
11263219e529SMike Christie 	return rc;
11277996a778SMike Christie }
11287996a778SMike Christie 
1129c4028958SDavid Howells static void iscsi_xmitworker(struct work_struct *work)
11307996a778SMike Christie {
1131c4028958SDavid Howells 	struct iscsi_conn *conn =
1132c4028958SDavid Howells 		container_of(work, struct iscsi_conn, xmitwork);
11333219e529SMike Christie 	int rc;
11347996a778SMike Christie 	/*
11357996a778SMike Christie 	 * serialize Xmit worker on a per-connection basis.
11367996a778SMike Christie 	 */
11373219e529SMike Christie 	do {
11383219e529SMike Christie 		rc = iscsi_data_xmit(conn);
11393219e529SMike Christie 	} while (rc >= 0 || rc == -EAGAIN);
11407996a778SMike Christie }
11417996a778SMike Christie 
11427996a778SMike Christie enum {
11437996a778SMike Christie 	FAILURE_BAD_HOST = 1,
11447996a778SMike Christie 	FAILURE_SESSION_FAILED,
11457996a778SMike Christie 	FAILURE_SESSION_FREED,
11467996a778SMike Christie 	FAILURE_WINDOW_CLOSED,
114760ecebf5SMike Christie 	FAILURE_OOM,
11487996a778SMike Christie 	FAILURE_SESSION_TERMINATE,
1149656cffc9SMike Christie 	FAILURE_SESSION_IN_RECOVERY,
11507996a778SMike Christie 	FAILURE_SESSION_RECOVERY_TIMEOUT,
1151b3a7ea8dSMike Christie 	FAILURE_SESSION_LOGGING_OUT,
11526eabafbeSMike Christie 	FAILURE_SESSION_NOT_READY,
11537996a778SMike Christie };
11547996a778SMike Christie 
11557996a778SMike Christie int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
11567996a778SMike Christie {
115775613521SMike Christie 	struct iscsi_cls_session *cls_session;
11587996a778SMike Christie 	struct Scsi_Host *host;
11597996a778SMike Christie 	int reason = 0;
11607996a778SMike Christie 	struct iscsi_session *session;
11617996a778SMike Christie 	struct iscsi_conn *conn;
11629c19a7d0SMike Christie 	struct iscsi_task *task = NULL;
11637996a778SMike Christie 
11647996a778SMike Christie 	sc->scsi_done = done;
11657996a778SMike Christie 	sc->result = 0;
1166f47f2cf5SMike Christie 	sc->SCp.ptr = NULL;
11677996a778SMike Christie 
11687996a778SMike Christie 	host = sc->device->host;
11691040c99dSMike Christie 	spin_unlock(host->host_lock);
11707996a778SMike Christie 
117175613521SMike Christie 	cls_session = starget_to_session(scsi_target(sc->device));
117275613521SMike Christie 	session = cls_session->dd_data;
11737996a778SMike Christie 	spin_lock(&session->lock);
11747996a778SMike Christie 
117575613521SMike Christie 	reason = iscsi_session_chkready(cls_session);
11766eabafbeSMike Christie 	if (reason) {
11776eabafbeSMike Christie 		sc->result = reason;
11786eabafbeSMike Christie 		goto fault;
11796eabafbeSMike Christie 	}
11806eabafbeSMike Christie 
1181656cffc9SMike Christie 	/*
1182656cffc9SMike Christie 	 * ISCSI_STATE_FAILED is a temp. state. The recovery
1183656cffc9SMike Christie 	 * code will decide what is best to do with command queued
1184656cffc9SMike Christie 	 * during this time
1185656cffc9SMike Christie 	 */
1186656cffc9SMike Christie 	if (session->state != ISCSI_STATE_LOGGED_IN &&
1187656cffc9SMike Christie 	    session->state != ISCSI_STATE_FAILED) {
1188656cffc9SMike Christie 		/*
1189656cffc9SMike Christie 		 * to handle the race between when we set the recovery state
1190656cffc9SMike Christie 		 * and block the session we requeue here (commands could
1191656cffc9SMike Christie 		 * be entering our queuecommand while a block is starting
1192656cffc9SMike Christie 		 * up because the block code is not locked)
1193656cffc9SMike Christie 		 */
11949000bcd6SMike Christie 		switch (session->state) {
11959000bcd6SMike Christie 		case ISCSI_STATE_IN_RECOVERY:
1196656cffc9SMike Christie 			reason = FAILURE_SESSION_IN_RECOVERY;
11976eabafbeSMike Christie 			sc->result = DID_IMM_RETRY << 16;
11986eabafbeSMike Christie 			break;
11999000bcd6SMike Christie 		case ISCSI_STATE_LOGGING_OUT:
12009000bcd6SMike Christie 			reason = FAILURE_SESSION_LOGGING_OUT;
12016eabafbeSMike Christie 			sc->result = DID_IMM_RETRY << 16;
12026eabafbeSMike Christie 			break;
1203b3a7ea8dSMike Christie 		case ISCSI_STATE_RECOVERY_FAILED:
1204656cffc9SMike Christie 			reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
12056eabafbeSMike Christie 			sc->result = DID_NO_CONNECT << 16;
1206b3a7ea8dSMike Christie 			break;
1207b3a7ea8dSMike Christie 		case ISCSI_STATE_TERMINATE:
1208656cffc9SMike Christie 			reason = FAILURE_SESSION_TERMINATE;
12096eabafbeSMike Christie 			sc->result = DID_NO_CONNECT << 16;
1210b3a7ea8dSMike Christie 			break;
1211b3a7ea8dSMike Christie 		default:
12127996a778SMike Christie 			reason = FAILURE_SESSION_FREED;
12136eabafbeSMike Christie 			sc->result = DID_NO_CONNECT << 16;
1214b3a7ea8dSMike Christie 		}
12157996a778SMike Christie 		goto fault;
12167996a778SMike Christie 	}
12177996a778SMike Christie 
12187996a778SMike Christie 	conn = session->leadconn;
121998644047SMike Christie 	if (!conn) {
122098644047SMike Christie 		reason = FAILURE_SESSION_FREED;
12216eabafbeSMike Christie 		sc->result = DID_NO_CONNECT << 16;
122298644047SMike Christie 		goto fault;
122398644047SMike Christie 	}
12247996a778SMike Christie 
122577a23c21SMike Christie 	if (iscsi_check_cmdsn_window_closed(conn)) {
122677a23c21SMike Christie 		reason = FAILURE_WINDOW_CLOSED;
122777a23c21SMike Christie 		goto reject;
122877a23c21SMike Christie 	}
122977a23c21SMike Christie 
12309c19a7d0SMike Christie 	if (!__kfifo_get(session->cmdpool.queue, (void*)&task,
123160ecebf5SMike Christie 			 sizeof(void*))) {
123260ecebf5SMike Christie 		reason = FAILURE_OOM;
123360ecebf5SMike Christie 		goto reject;
123460ecebf5SMike Christie 	}
12357996a778SMike Christie 	sc->SCp.phase = session->age;
12369c19a7d0SMike Christie 	sc->SCp.ptr = (char *)task;
12377996a778SMike Christie 
12389c19a7d0SMike Christie 	atomic_set(&task->refcount, 1);
12399c19a7d0SMike Christie 	task->state = ISCSI_TASK_PENDING;
12409c19a7d0SMike Christie 	task->conn = conn;
12419c19a7d0SMike Christie 	task->sc = sc;
12429c19a7d0SMike Christie 	INIT_LIST_HEAD(&task->running);
12439c19a7d0SMike Christie 	list_add_tail(&task->running, &conn->xmitqueue);
12447996a778SMike Christie 
1245052d0144SMike Christie 	if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) {
12469c19a7d0SMike Christie 		if (iscsi_prep_scsi_cmd_pdu(task)) {
1247052d0144SMike Christie 			sc->result = DID_ABORT << 16;
1248052d0144SMike Christie 			sc->scsi_done = NULL;
12499c19a7d0SMike Christie 			iscsi_complete_command(task);
1250052d0144SMike Christie 			goto fault;
1251052d0144SMike Christie 		}
12529c19a7d0SMike Christie 		if (session->tt->xmit_task(task)) {
1253052d0144SMike Christie 			sc->scsi_done = NULL;
12549c19a7d0SMike Christie 			iscsi_complete_command(task);
1255052d0144SMike Christie 			reason = FAILURE_SESSION_NOT_READY;
1256052d0144SMike Christie 			goto reject;
1257052d0144SMike Christie 		}
1258052d0144SMike Christie 	} else
1259052d0144SMike Christie 		scsi_queue_work(session->host, &conn->xmitwork);
1260052d0144SMike Christie 
1261052d0144SMike Christie 	session->queued_cmdsn++;
1262052d0144SMike Christie 	spin_unlock(&session->lock);
12631040c99dSMike Christie 	spin_lock(host->host_lock);
12647996a778SMike Christie 	return 0;
12657996a778SMike Christie 
12667996a778SMike Christie reject:
12677996a778SMike Christie 	spin_unlock(&session->lock);
12687996a778SMike Christie 	debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason);
12691040c99dSMike Christie 	spin_lock(host->host_lock);
12707996a778SMike Christie 	return SCSI_MLQUEUE_HOST_BUSY;
12717996a778SMike Christie 
12727996a778SMike Christie fault:
12737996a778SMike Christie 	spin_unlock(&session->lock);
12746eabafbeSMike Christie 	debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason);
1275c07d4444SBoaz Harrosh 	if (!scsi_bidi_cmnd(sc))
12761c138991SFUJITA Tomonori 		scsi_set_resid(sc, scsi_bufflen(sc));
1277c07d4444SBoaz Harrosh 	else {
1278c07d4444SBoaz Harrosh 		scsi_out(sc)->resid = scsi_out(sc)->length;
1279c07d4444SBoaz Harrosh 		scsi_in(sc)->resid = scsi_in(sc)->length;
1280c07d4444SBoaz Harrosh 	}
1281052d0144SMike Christie 	done(sc);
12821040c99dSMike Christie 	spin_lock(host->host_lock);
12837996a778SMike Christie 	return 0;
12847996a778SMike Christie }
12857996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_queuecommand);
12867996a778SMike Christie 
12877996a778SMike Christie int iscsi_change_queue_depth(struct scsi_device *sdev, int depth)
12887996a778SMike Christie {
12897996a778SMike Christie 	if (depth > ISCSI_MAX_CMD_PER_LUN)
12907996a778SMike Christie 		depth = ISCSI_MAX_CMD_PER_LUN;
12917996a778SMike Christie 	scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
12927996a778SMike Christie 	return sdev->queue_depth;
12937996a778SMike Christie }
12947996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
12957996a778SMike Christie 
12967996a778SMike Christie void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
12977996a778SMike Christie {
129875613521SMike Christie 	struct iscsi_session *session = cls_session->dd_data;
12997996a778SMike Christie 
13007996a778SMike Christie 	spin_lock_bh(&session->lock);
13017996a778SMike Christie 	if (session->state != ISCSI_STATE_LOGGED_IN) {
1302656cffc9SMike Christie 		session->state = ISCSI_STATE_RECOVERY_FAILED;
1303843c0a8aSMike Christie 		if (session->leadconn)
1304843c0a8aSMike Christie 			wake_up(&session->leadconn->ehwait);
13057996a778SMike Christie 	}
13067996a778SMike Christie 	spin_unlock_bh(&session->lock);
13077996a778SMike Christie }
13087996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout);
13097996a778SMike Christie 
13107996a778SMike Christie int iscsi_eh_host_reset(struct scsi_cmnd *sc)
13117996a778SMike Christie {
131275613521SMike Christie 	struct iscsi_cls_session *cls_session;
131375613521SMike Christie 	struct iscsi_session *session;
131475613521SMike Christie 	struct iscsi_conn *conn;
131575613521SMike Christie 
131675613521SMike Christie 	cls_session = starget_to_session(scsi_target(sc->device));
131775613521SMike Christie 	session = cls_session->dd_data;
131875613521SMike Christie 	conn = session->leadconn;
13197996a778SMike Christie 
1320bc436b27SMike Christie 	mutex_lock(&session->eh_mutex);
13217996a778SMike Christie 	spin_lock_bh(&session->lock);
13227996a778SMike Christie 	if (session->state == ISCSI_STATE_TERMINATE) {
13237996a778SMike Christie failed:
13247996a778SMike Christie 		debug_scsi("failing host reset: session terminated "
1325d6e24d1cSPete Wyckoff 			   "[CID %d age %d]\n", conn->id, session->age);
13267996a778SMike Christie 		spin_unlock_bh(&session->lock);
1327bc436b27SMike Christie 		mutex_unlock(&session->eh_mutex);
13287996a778SMike Christie 		return FAILED;
13297996a778SMike Christie 	}
13307996a778SMike Christie 
13317996a778SMike Christie 	spin_unlock_bh(&session->lock);
1332bc436b27SMike Christie 	mutex_unlock(&session->eh_mutex);
13337996a778SMike Christie 	/*
13347996a778SMike Christie 	 * we drop the lock here but the leadconn cannot be destoyed while
13357996a778SMike Christie 	 * we are in the scsi eh
13367996a778SMike Christie 	 */
13377996a778SMike Christie 	iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
13387996a778SMike Christie 
13397996a778SMike Christie 	debug_scsi("iscsi_eh_host_reset wait for relogin\n");
13407996a778SMike Christie 	wait_event_interruptible(conn->ehwait,
13417996a778SMike Christie 				 session->state == ISCSI_STATE_TERMINATE ||
13427996a778SMike Christie 				 session->state == ISCSI_STATE_LOGGED_IN ||
1343656cffc9SMike Christie 				 session->state == ISCSI_STATE_RECOVERY_FAILED);
13447996a778SMike Christie 	if (signal_pending(current))
13457996a778SMike Christie 		flush_signals(current);
13467996a778SMike Christie 
1347bc436b27SMike Christie 	mutex_lock(&session->eh_mutex);
13487996a778SMike Christie 	spin_lock_bh(&session->lock);
13497996a778SMike Christie 	if (session->state == ISCSI_STATE_LOGGED_IN)
1350322d739dSMike Christie 		iscsi_session_printk(KERN_INFO, session,
1351322d739dSMike Christie 				     "host reset succeeded\n");
13527996a778SMike Christie 	else
13537996a778SMike Christie 		goto failed;
13547996a778SMike Christie 	spin_unlock_bh(&session->lock);
1355bc436b27SMike Christie 	mutex_unlock(&session->eh_mutex);
13567996a778SMike Christie 	return SUCCESS;
13577996a778SMike Christie }
13587996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_eh_host_reset);
13597996a778SMike Christie 
1360843c0a8aSMike Christie static void iscsi_tmf_timedout(unsigned long data)
13617996a778SMike Christie {
1362843c0a8aSMike Christie 	struct iscsi_conn *conn = (struct iscsi_conn *)data;
13637996a778SMike Christie 	struct iscsi_session *session = conn->session;
13647996a778SMike Christie 
13657996a778SMike Christie 	spin_lock(&session->lock);
1366843c0a8aSMike Christie 	if (conn->tmf_state == TMF_QUEUED) {
1367843c0a8aSMike Christie 		conn->tmf_state = TMF_TIMEDOUT;
1368843c0a8aSMike Christie 		debug_scsi("tmf timedout\n");
13697996a778SMike Christie 		/* unblock eh_abort() */
13707996a778SMike Christie 		wake_up(&conn->ehwait);
13717996a778SMike Christie 	}
13727996a778SMike Christie 	spin_unlock(&session->lock);
13737996a778SMike Christie }
13747996a778SMike Christie 
13759c19a7d0SMike Christie static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
1376f6d5180cSMike Christie 				   struct iscsi_tm *hdr, int age,
1377f6d5180cSMike Christie 				   int timeout)
13787996a778SMike Christie {
13797996a778SMike Christie 	struct iscsi_session *session = conn->session;
13809c19a7d0SMike Christie 	struct iscsi_task *task;
13817996a778SMike Christie 
13829c19a7d0SMike Christie 	task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
13837996a778SMike Christie 				      NULL, 0);
13849c19a7d0SMike Christie 	if (!task) {
13856724add1SMike Christie 		spin_unlock_bh(&session->lock);
13867996a778SMike Christie 		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
1387843c0a8aSMike Christie 		spin_lock_bh(&session->lock);
1388843c0a8aSMike Christie 		debug_scsi("tmf exec failure\n");
138977a23c21SMike Christie 		return -EPERM;
13907996a778SMike Christie 	}
13917996a778SMike Christie 	conn->tmfcmd_pdus_cnt++;
1392f6d5180cSMike Christie 	conn->tmf_timer.expires = timeout * HZ + jiffies;
1393843c0a8aSMike Christie 	conn->tmf_timer.function = iscsi_tmf_timedout;
1394843c0a8aSMike Christie 	conn->tmf_timer.data = (unsigned long)conn;
1395843c0a8aSMike Christie 	add_timer(&conn->tmf_timer);
1396843c0a8aSMike Christie 	debug_scsi("tmf set timeout\n");
1397843c0a8aSMike Christie 
13987996a778SMike Christie 	spin_unlock_bh(&session->lock);
13996724add1SMike Christie 	mutex_unlock(&session->eh_mutex);
14007996a778SMike Christie 
14017996a778SMike Christie 	/*
14027996a778SMike Christie 	 * block eh thread until:
14037996a778SMike Christie 	 *
1404843c0a8aSMike Christie 	 * 1) tmf response
1405843c0a8aSMike Christie 	 * 2) tmf timeout
14067996a778SMike Christie 	 * 3) session is terminated or restarted or userspace has
14077996a778SMike Christie 	 * given up on recovery
14087996a778SMike Christie 	 */
1409843c0a8aSMike Christie 	wait_event_interruptible(conn->ehwait, age != session->age ||
14107996a778SMike Christie 				 session->state != ISCSI_STATE_LOGGED_IN ||
1411843c0a8aSMike Christie 				 conn->tmf_state != TMF_QUEUED);
14127996a778SMike Christie 	if (signal_pending(current))
14137996a778SMike Christie 		flush_signals(current);
1414843c0a8aSMike Christie 	del_timer_sync(&conn->tmf_timer);
1415843c0a8aSMike Christie 
14166724add1SMike Christie 	mutex_lock(&session->eh_mutex);
141777a23c21SMike Christie 	spin_lock_bh(&session->lock);
14189c19a7d0SMike Christie 	/* if the session drops it will clean up the task */
1419843c0a8aSMike Christie 	if (age != session->age ||
1420843c0a8aSMike Christie 	    session->state != ISCSI_STATE_LOGGED_IN)
1421843c0a8aSMike Christie 		return -ENOTCONN;
14227996a778SMike Christie 	return 0;
14237996a778SMike Christie }
14247996a778SMike Christie 
14257996a778SMike Christie /*
1426843c0a8aSMike Christie  * Fail commands. session lock held and recv side suspended and xmit
1427843c0a8aSMike Christie  * thread flushed
1428843c0a8aSMike Christie  */
14296eabafbeSMike Christie static void fail_all_commands(struct iscsi_conn *conn, unsigned lun,
14306eabafbeSMike Christie 			      int error)
1431843c0a8aSMike Christie {
14329c19a7d0SMike Christie 	struct iscsi_task *task, *tmp;
1433843c0a8aSMike Christie 
14349c19a7d0SMike Christie 	if (conn->task && (conn->task->sc->device->lun == lun || lun == -1))
14359c19a7d0SMike Christie 		conn->task = NULL;
1436843c0a8aSMike Christie 
1437843c0a8aSMike Christie 	/* flush pending */
14389c19a7d0SMike Christie 	list_for_each_entry_safe(task, tmp, &conn->xmitqueue, running) {
14399c19a7d0SMike Christie 		if (lun == task->sc->device->lun || lun == -1) {
1440843c0a8aSMike Christie 			debug_scsi("failing pending sc %p itt 0x%x\n",
14419c19a7d0SMike Christie 				   task->sc, task->itt);
14429c19a7d0SMike Christie 			fail_command(conn, task, error << 16);
1443843c0a8aSMike Christie 		}
1444843c0a8aSMike Christie 	}
1445843c0a8aSMike Christie 
14469c19a7d0SMike Christie 	list_for_each_entry_safe(task, tmp, &conn->requeue, running) {
14479c19a7d0SMike Christie 		if (lun == task->sc->device->lun || lun == -1) {
1448843c0a8aSMike Christie 			debug_scsi("failing requeued sc %p itt 0x%x\n",
14499c19a7d0SMike Christie 				   task->sc, task->itt);
14509c19a7d0SMike Christie 			fail_command(conn, task, error << 16);
1451843c0a8aSMike Christie 		}
1452843c0a8aSMike Christie 	}
1453843c0a8aSMike Christie 
1454843c0a8aSMike Christie 	/* fail all other running */
14559c19a7d0SMike Christie 	list_for_each_entry_safe(task, tmp, &conn->run_list, running) {
14569c19a7d0SMike Christie 		if (lun == task->sc->device->lun || lun == -1) {
1457843c0a8aSMike Christie 			debug_scsi("failing in progress sc %p itt 0x%x\n",
14589c19a7d0SMike Christie 				   task->sc, task->itt);
1459*ac26d41dSMike Christie 			fail_command(conn, task, error << 16);
1460843c0a8aSMike Christie 		}
1461843c0a8aSMike Christie 	}
1462843c0a8aSMike Christie }
1463843c0a8aSMike Christie 
1464b40977d9SMike Christie void iscsi_suspend_tx(struct iscsi_conn *conn)
14656724add1SMike Christie {
14666724add1SMike Christie 	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
1467052d0144SMike Christie 	if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
14686724add1SMike Christie 		scsi_flush_work(conn->session->host);
14696724add1SMike Christie }
1470b40977d9SMike Christie EXPORT_SYMBOL_GPL(iscsi_suspend_tx);
14716724add1SMike Christie 
14726724add1SMike Christie static void iscsi_start_tx(struct iscsi_conn *conn)
14736724add1SMike Christie {
14746724add1SMike Christie 	clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
1475052d0144SMike Christie 	if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
14766724add1SMike Christie 		scsi_queue_work(conn->session->host, &conn->xmitwork);
14776724add1SMike Christie }
14786724add1SMike Christie 
1479f6d5180cSMike Christie static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
1480f6d5180cSMike Christie {
1481f6d5180cSMike Christie 	struct iscsi_cls_session *cls_session;
1482f6d5180cSMike Christie 	struct iscsi_session *session;
1483f6d5180cSMike Christie 	struct iscsi_conn *conn;
1484f6d5180cSMike Christie 	enum scsi_eh_timer_return rc = EH_NOT_HANDLED;
1485f6d5180cSMike Christie 
1486f6d5180cSMike Christie 	cls_session = starget_to_session(scsi_target(scmd->device));
148775613521SMike Christie 	session = cls_session->dd_data;
1488f6d5180cSMike Christie 
1489f6d5180cSMike Christie 	debug_scsi("scsi cmd %p timedout\n", scmd);
1490f6d5180cSMike Christie 
1491f6d5180cSMike Christie 	spin_lock(&session->lock);
1492f6d5180cSMike Christie 	if (session->state != ISCSI_STATE_LOGGED_IN) {
1493f6d5180cSMike Christie 		/*
1494f6d5180cSMike Christie 		 * We are probably in the middle of iscsi recovery so let
1495f6d5180cSMike Christie 		 * that complete and handle the error.
1496f6d5180cSMike Christie 		 */
1497f6d5180cSMike Christie 		rc = EH_RESET_TIMER;
1498f6d5180cSMike Christie 		goto done;
1499f6d5180cSMike Christie 	}
1500f6d5180cSMike Christie 
1501f6d5180cSMike Christie 	conn = session->leadconn;
1502f6d5180cSMike Christie 	if (!conn) {
1503f6d5180cSMike Christie 		/* In the middle of shuting down */
1504f6d5180cSMike Christie 		rc = EH_RESET_TIMER;
1505f6d5180cSMike Christie 		goto done;
1506f6d5180cSMike Christie 	}
1507f6d5180cSMike Christie 
1508f6d5180cSMike Christie 	if (!conn->recv_timeout && !conn->ping_timeout)
1509f6d5180cSMike Christie 		goto done;
1510f6d5180cSMike Christie 	/*
1511f6d5180cSMike Christie 	 * if the ping timedout then we are in the middle of cleaning up
1512f6d5180cSMike Christie 	 * and can let the iscsi eh handle it
1513f6d5180cSMike Christie 	 */
1514f6d5180cSMike Christie 	if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) +
1515f6d5180cSMike Christie 			    (conn->ping_timeout * HZ), jiffies))
1516f6d5180cSMike Christie 		rc = EH_RESET_TIMER;
1517f6d5180cSMike Christie 	/*
1518f6d5180cSMike Christie 	 * if we are about to check the transport then give the command
1519f6d5180cSMike Christie 	 * more time
1520f6d5180cSMike Christie 	 */
1521f6d5180cSMike Christie 	if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ),
1522f6d5180cSMike Christie 			   jiffies))
1523f6d5180cSMike Christie 		rc = EH_RESET_TIMER;
1524f6d5180cSMike Christie 	/* if in the middle of checking the transport then give us more time */
15259c19a7d0SMike Christie 	if (conn->ping_task)
1526f6d5180cSMike Christie 		rc = EH_RESET_TIMER;
1527f6d5180cSMike Christie done:
1528f6d5180cSMike Christie 	spin_unlock(&session->lock);
1529f6d5180cSMike Christie 	debug_scsi("return %s\n", rc == EH_RESET_TIMER ? "timer reset" : "nh");
1530f6d5180cSMike Christie 	return rc;
1531f6d5180cSMike Christie }
1532f6d5180cSMike Christie 
1533f6d5180cSMike Christie static void iscsi_check_transport_timeouts(unsigned long data)
1534f6d5180cSMike Christie {
1535f6d5180cSMike Christie 	struct iscsi_conn *conn = (struct iscsi_conn *)data;
1536f6d5180cSMike Christie 	struct iscsi_session *session = conn->session;
15374cf10435SMike Christie 	unsigned long recv_timeout, next_timeout = 0, last_recv;
1538f6d5180cSMike Christie 
1539f6d5180cSMike Christie 	spin_lock(&session->lock);
1540f6d5180cSMike Christie 	if (session->state != ISCSI_STATE_LOGGED_IN)
1541f6d5180cSMike Christie 		goto done;
1542f6d5180cSMike Christie 
15434cf10435SMike Christie 	recv_timeout = conn->recv_timeout;
15444cf10435SMike Christie 	if (!recv_timeout)
1545f6d5180cSMike Christie 		goto done;
1546f6d5180cSMike Christie 
15474cf10435SMike Christie 	recv_timeout *= HZ;
1548f6d5180cSMike Christie 	last_recv = conn->last_recv;
15499c19a7d0SMike Christie 	if (conn->ping_task &&
15504cf10435SMike Christie 	    time_before_eq(conn->last_ping + (conn->ping_timeout * HZ),
1551f6d5180cSMike Christie 			   jiffies)) {
1552322d739dSMike Christie 		iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs "
1553322d739dSMike Christie 				  "expired, last rx %lu, last ping %lu, "
1554322d739dSMike Christie 				  "now %lu\n", conn->ping_timeout, last_recv,
1555f6d5180cSMike Christie 				  conn->last_ping, jiffies);
1556f6d5180cSMike Christie 		spin_unlock(&session->lock);
1557f6d5180cSMike Christie 		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
1558f6d5180cSMike Christie 		return;
1559f6d5180cSMike Christie 	}
1560f6d5180cSMike Christie 
15614cf10435SMike Christie 	if (time_before_eq(last_recv + recv_timeout, jiffies)) {
1562f6d5180cSMike Christie 		/* send a ping to try to provoke some traffic */
1563f6d5180cSMike Christie 		debug_scsi("Sending nopout as ping on conn %p\n", conn);
1564f6d5180cSMike Christie 		iscsi_send_nopout(conn, NULL);
15654cf10435SMike Christie 		next_timeout = conn->last_ping + (conn->ping_timeout * HZ);
1566ad294e9cSMike Christie 	} else
15674cf10435SMike Christie 		next_timeout = last_recv + recv_timeout;
1568f6d5180cSMike Christie 
1569f6d5180cSMike Christie 	debug_scsi("Setting next tmo %lu\n", next_timeout);
1570f6d5180cSMike Christie 	mod_timer(&conn->transport_timer, next_timeout);
1571f6d5180cSMike Christie done:
1572f6d5180cSMike Christie 	spin_unlock(&session->lock);
1573f6d5180cSMike Christie }
1574f6d5180cSMike Christie 
15759c19a7d0SMike Christie static void iscsi_prep_abort_task_pdu(struct iscsi_task *task,
1576843c0a8aSMike Christie 				      struct iscsi_tm *hdr)
1577843c0a8aSMike Christie {
1578843c0a8aSMike Christie 	memset(hdr, 0, sizeof(*hdr));
1579843c0a8aSMike Christie 	hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
1580843c0a8aSMike Christie 	hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK;
1581843c0a8aSMike Christie 	hdr->flags |= ISCSI_FLAG_CMD_FINAL;
15829c19a7d0SMike Christie 	memcpy(hdr->lun, task->hdr->lun, sizeof(hdr->lun));
15839c19a7d0SMike Christie 	hdr->rtt = task->hdr->itt;
15849c19a7d0SMike Christie 	hdr->refcmdsn = task->hdr->cmdsn;
1585843c0a8aSMike Christie }
1586843c0a8aSMike Christie 
15877996a778SMike Christie int iscsi_eh_abort(struct scsi_cmnd *sc)
15887996a778SMike Christie {
158975613521SMike Christie 	struct iscsi_cls_session *cls_session;
159075613521SMike Christie 	struct iscsi_session *session;
1591f47f2cf5SMike Christie 	struct iscsi_conn *conn;
15929c19a7d0SMike Christie 	struct iscsi_task *task;
1593843c0a8aSMike Christie 	struct iscsi_tm *hdr;
1594843c0a8aSMike Christie 	int rc, age;
15957996a778SMike Christie 
159675613521SMike Christie 	cls_session = starget_to_session(scsi_target(sc->device));
159775613521SMike Christie 	session = cls_session->dd_data;
159875613521SMike Christie 
15996724add1SMike Christie 	mutex_lock(&session->eh_mutex);
16006724add1SMike Christie 	spin_lock_bh(&session->lock);
1601f47f2cf5SMike Christie 	/*
1602f47f2cf5SMike Christie 	 * if session was ISCSI_STATE_IN_RECOVERY then we may not have
1603f47f2cf5SMike Christie 	 * got the command.
1604f47f2cf5SMike Christie 	 */
1605f47f2cf5SMike Christie 	if (!sc->SCp.ptr) {
1606f47f2cf5SMike Christie 		debug_scsi("sc never reached iscsi layer or it completed.\n");
16076724add1SMike Christie 		spin_unlock_bh(&session->lock);
16086724add1SMike Christie 		mutex_unlock(&session->eh_mutex);
1609f47f2cf5SMike Christie 		return SUCCESS;
1610f47f2cf5SMike Christie 	}
1611f47f2cf5SMike Christie 
16127996a778SMike Christie 	/*
16137996a778SMike Christie 	 * If we are not logged in or we have started a new session
16147996a778SMike Christie 	 * then let the host reset code handle this
16157996a778SMike Christie 	 */
1616843c0a8aSMike Christie 	if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN ||
1617843c0a8aSMike Christie 	    sc->SCp.phase != session->age) {
1618843c0a8aSMike Christie 		spin_unlock_bh(&session->lock);
1619843c0a8aSMike Christie 		mutex_unlock(&session->eh_mutex);
1620843c0a8aSMike Christie 		return FAILED;
1621843c0a8aSMike Christie 	}
1622843c0a8aSMike Christie 
1623843c0a8aSMike Christie 	conn = session->leadconn;
1624843c0a8aSMike Christie 	conn->eh_abort_cnt++;
1625843c0a8aSMike Christie 	age = session->age;
1626843c0a8aSMike Christie 
16279c19a7d0SMike Christie 	task = (struct iscsi_task *)sc->SCp.ptr;
16289c19a7d0SMike Christie 	debug_scsi("aborting [sc %p itt 0x%x]\n", sc, task->itt);
16297996a778SMike Christie 
16309c19a7d0SMike Christie 	/* task completed before time out */
16319c19a7d0SMike Christie 	if (!task->sc) {
16327ea8b828SMike Christie 		debug_scsi("sc completed while abort in progress\n");
163377a23c21SMike Christie 		goto success;
16347ea8b828SMike Christie 	}
16357996a778SMike Christie 
16369c19a7d0SMike Christie 	if (task->state == ISCSI_TASK_PENDING) {
16379c19a7d0SMike Christie 		fail_command(conn, task, DID_ABORT << 16);
163877a23c21SMike Christie 		goto success;
163977a23c21SMike Christie 	}
16407996a778SMike Christie 
1641843c0a8aSMike Christie 	/* only have one tmf outstanding at a time */
1642843c0a8aSMike Christie 	if (conn->tmf_state != TMF_INITIAL)
16437996a778SMike Christie 		goto failed;
1644843c0a8aSMike Christie 	conn->tmf_state = TMF_QUEUED;
16457996a778SMike Christie 
1646843c0a8aSMike Christie 	hdr = &conn->tmhdr;
16479c19a7d0SMike Christie 	iscsi_prep_abort_task_pdu(task, hdr);
1648843c0a8aSMike Christie 
16499c19a7d0SMike Christie 	if (iscsi_exec_task_mgmt_fn(conn, hdr, age, session->abort_timeout)) {
1650843c0a8aSMike Christie 		rc = FAILED;
1651843c0a8aSMike Christie 		goto failed;
1652843c0a8aSMike Christie 	}
1653843c0a8aSMike Christie 
1654843c0a8aSMike Christie 	switch (conn->tmf_state) {
1655843c0a8aSMike Christie 	case TMF_SUCCESS:
16567ea8b828SMike Christie 		spin_unlock_bh(&session->lock);
1657913e5bf4SMike Christie 		/*
1658913e5bf4SMike Christie 		 * stop tx side incase the target had sent a abort rsp but
1659913e5bf4SMike Christie 		 * the initiator was still writing out data.
1660913e5bf4SMike Christie 		 */
16616724add1SMike Christie 		iscsi_suspend_tx(conn);
16627996a778SMike Christie 		/*
1663913e5bf4SMike Christie 		 * we do not stop the recv side because targets have been
1664913e5bf4SMike Christie 		 * good and have never sent us a successful tmf response
1665913e5bf4SMike Christie 		 * then sent more data for the cmd.
16667996a778SMike Christie 		 */
16677996a778SMike Christie 		spin_lock(&session->lock);
16689c19a7d0SMike Christie 		fail_command(conn, task, DID_ABORT << 16);
1669843c0a8aSMike Christie 		conn->tmf_state = TMF_INITIAL;
16707996a778SMike Christie 		spin_unlock(&session->lock);
16716724add1SMike Christie 		iscsi_start_tx(conn);
167277a23c21SMike Christie 		goto success_unlocked;
1673843c0a8aSMike Christie 	case TMF_TIMEDOUT:
1674843c0a8aSMike Christie 		spin_unlock_bh(&session->lock);
1675843c0a8aSMike Christie 		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
1676843c0a8aSMike Christie 		goto failed_unlocked;
1677843c0a8aSMike Christie 	case TMF_NOT_FOUND:
1678843c0a8aSMike Christie 		if (!sc->SCp.ptr) {
1679843c0a8aSMike Christie 			conn->tmf_state = TMF_INITIAL;
16809c19a7d0SMike Christie 			/* task completed before tmf abort response */
168177a23c21SMike Christie 			debug_scsi("sc completed while abort in progress\n");
168277a23c21SMike Christie 			goto success;
168377a23c21SMike Christie 		}
168477a23c21SMike Christie 		/* fall through */
168577a23c21SMike Christie 	default:
1686843c0a8aSMike Christie 		conn->tmf_state = TMF_INITIAL;
1687843c0a8aSMike Christie 		goto failed;
168877a23c21SMike Christie 	}
16897996a778SMike Christie 
169077a23c21SMike Christie success:
169177a23c21SMike Christie 	spin_unlock_bh(&session->lock);
169277a23c21SMike Christie success_unlocked:
16939c19a7d0SMike Christie 	debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, task->itt);
16946724add1SMike Christie 	mutex_unlock(&session->eh_mutex);
16957996a778SMike Christie 	return SUCCESS;
16967996a778SMike Christie 
16977996a778SMike Christie failed:
16987996a778SMike Christie 	spin_unlock_bh(&session->lock);
169977a23c21SMike Christie failed_unlocked:
1700843c0a8aSMike Christie 	debug_scsi("abort failed [sc %p itt 0x%x]\n", sc,
17019c19a7d0SMike Christie 		    task ? task->itt : 0);
17026724add1SMike Christie 	mutex_unlock(&session->eh_mutex);
17037996a778SMike Christie 	return FAILED;
17047996a778SMike Christie }
17057996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_eh_abort);
17067996a778SMike Christie 
1707843c0a8aSMike Christie static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr)
1708843c0a8aSMike Christie {
1709843c0a8aSMike Christie 	memset(hdr, 0, sizeof(*hdr));
1710843c0a8aSMike Christie 	hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
1711843c0a8aSMike Christie 	hdr->flags = ISCSI_TM_FUNC_LOGICAL_UNIT_RESET & ISCSI_FLAG_TM_FUNC_MASK;
1712843c0a8aSMike Christie 	hdr->flags |= ISCSI_FLAG_CMD_FINAL;
1713843c0a8aSMike Christie 	int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
1714f6d5180cSMike Christie 	hdr->rtt = RESERVED_ITT;
1715843c0a8aSMike Christie }
1716843c0a8aSMike Christie 
1717843c0a8aSMike Christie int iscsi_eh_device_reset(struct scsi_cmnd *sc)
1718843c0a8aSMike Christie {
171975613521SMike Christie 	struct iscsi_cls_session *cls_session;
172075613521SMike Christie 	struct iscsi_session *session;
1721843c0a8aSMike Christie 	struct iscsi_conn *conn;
1722843c0a8aSMike Christie 	struct iscsi_tm *hdr;
1723843c0a8aSMike Christie 	int rc = FAILED;
1724843c0a8aSMike Christie 
172575613521SMike Christie 	cls_session = starget_to_session(scsi_target(sc->device));
172675613521SMike Christie 	session = cls_session->dd_data;
172775613521SMike Christie 
1728843c0a8aSMike Christie 	debug_scsi("LU Reset [sc %p lun %u]\n", sc, sc->device->lun);
1729843c0a8aSMike Christie 
1730843c0a8aSMike Christie 	mutex_lock(&session->eh_mutex);
1731843c0a8aSMike Christie 	spin_lock_bh(&session->lock);
1732843c0a8aSMike Christie 	/*
1733843c0a8aSMike Christie 	 * Just check if we are not logged in. We cannot check for
1734843c0a8aSMike Christie 	 * the phase because the reset could come from a ioctl.
1735843c0a8aSMike Christie 	 */
1736843c0a8aSMike Christie 	if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN)
1737843c0a8aSMike Christie 		goto unlock;
1738843c0a8aSMike Christie 	conn = session->leadconn;
1739843c0a8aSMike Christie 
1740843c0a8aSMike Christie 	/* only have one tmf outstanding at a time */
1741843c0a8aSMike Christie 	if (conn->tmf_state != TMF_INITIAL)
1742843c0a8aSMike Christie 		goto unlock;
1743843c0a8aSMike Christie 	conn->tmf_state = TMF_QUEUED;
1744843c0a8aSMike Christie 
1745843c0a8aSMike Christie 	hdr = &conn->tmhdr;
1746843c0a8aSMike Christie 	iscsi_prep_lun_reset_pdu(sc, hdr);
1747843c0a8aSMike Christie 
17489c19a7d0SMike Christie 	if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age,
1749f6d5180cSMike Christie 				    session->lu_reset_timeout)) {
1750843c0a8aSMike Christie 		rc = FAILED;
1751843c0a8aSMike Christie 		goto unlock;
1752843c0a8aSMike Christie 	}
1753843c0a8aSMike Christie 
1754843c0a8aSMike Christie 	switch (conn->tmf_state) {
1755843c0a8aSMike Christie 	case TMF_SUCCESS:
1756843c0a8aSMike Christie 		break;
1757843c0a8aSMike Christie 	case TMF_TIMEDOUT:
1758843c0a8aSMike Christie 		spin_unlock_bh(&session->lock);
1759843c0a8aSMike Christie 		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
1760843c0a8aSMike Christie 		goto done;
1761843c0a8aSMike Christie 	default:
1762843c0a8aSMike Christie 		conn->tmf_state = TMF_INITIAL;
1763843c0a8aSMike Christie 		goto unlock;
1764843c0a8aSMike Christie 	}
1765843c0a8aSMike Christie 
1766843c0a8aSMike Christie 	rc = SUCCESS;
1767843c0a8aSMike Christie 	spin_unlock_bh(&session->lock);
1768843c0a8aSMike Christie 
1769843c0a8aSMike Christie 	iscsi_suspend_tx(conn);
1770913e5bf4SMike Christie 
1771843c0a8aSMike Christie 	spin_lock(&session->lock);
17726eabafbeSMike Christie 	fail_all_commands(conn, sc->device->lun, DID_ERROR);
1773843c0a8aSMike Christie 	conn->tmf_state = TMF_INITIAL;
1774843c0a8aSMike Christie 	spin_unlock(&session->lock);
1775843c0a8aSMike Christie 
1776843c0a8aSMike Christie 	iscsi_start_tx(conn);
1777843c0a8aSMike Christie 	goto done;
1778843c0a8aSMike Christie 
1779843c0a8aSMike Christie unlock:
1780843c0a8aSMike Christie 	spin_unlock_bh(&session->lock);
1781843c0a8aSMike Christie done:
1782843c0a8aSMike Christie 	debug_scsi("iscsi_eh_device_reset %s\n",
1783843c0a8aSMike Christie 		  rc == SUCCESS ? "SUCCESS" : "FAILED");
1784843c0a8aSMike Christie 	mutex_unlock(&session->eh_mutex);
1785843c0a8aSMike Christie 	return rc;
1786843c0a8aSMike Christie }
1787843c0a8aSMike Christie EXPORT_SYMBOL_GPL(iscsi_eh_device_reset);
1788843c0a8aSMike Christie 
17896320377fSOlaf Kirch /*
17906320377fSOlaf Kirch  * Pre-allocate a pool of @max items of @item_size. By default, the pool
17916320377fSOlaf Kirch  * should be accessed via kfifo_{get,put} on q->queue.
17926320377fSOlaf Kirch  * Optionally, the caller can obtain the array of object pointers
17936320377fSOlaf Kirch  * by passing in a non-NULL @items pointer
17946320377fSOlaf Kirch  */
17957996a778SMike Christie int
17966320377fSOlaf Kirch iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
17977996a778SMike Christie {
17986320377fSOlaf Kirch 	int i, num_arrays = 1;
17997996a778SMike Christie 
18006320377fSOlaf Kirch 	memset(q, 0, sizeof(*q));
18017996a778SMike Christie 
18027996a778SMike Christie 	q->max = max;
18036320377fSOlaf Kirch 
18046320377fSOlaf Kirch 	/* If the user passed an items pointer, he wants a copy of
18056320377fSOlaf Kirch 	 * the array. */
18066320377fSOlaf Kirch 	if (items)
18076320377fSOlaf Kirch 		num_arrays++;
18086320377fSOlaf Kirch 	q->pool = kzalloc(num_arrays * max * sizeof(void*), GFP_KERNEL);
18096320377fSOlaf Kirch 	if (q->pool == NULL)
18106320377fSOlaf Kirch 		goto enomem;
18117996a778SMike Christie 
18127996a778SMike Christie 	q->queue = kfifo_init((void*)q->pool, max * sizeof(void*),
18137996a778SMike Christie 			      GFP_KERNEL, NULL);
18146320377fSOlaf Kirch 	if (q->queue == ERR_PTR(-ENOMEM))
18156320377fSOlaf Kirch 		goto enomem;
18167996a778SMike Christie 
18177996a778SMike Christie 	for (i = 0; i < max; i++) {
18186320377fSOlaf Kirch 		q->pool[i] = kzalloc(item_size, GFP_KERNEL);
18197996a778SMike Christie 		if (q->pool[i] == NULL) {
18206320377fSOlaf Kirch 			q->max = i;
18216320377fSOlaf Kirch 			goto enomem;
18227996a778SMike Christie 		}
18237996a778SMike Christie 		__kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*));
18247996a778SMike Christie 	}
18256320377fSOlaf Kirch 
18266320377fSOlaf Kirch 	if (items) {
18276320377fSOlaf Kirch 		*items = q->pool + max;
18286320377fSOlaf Kirch 		memcpy(*items, q->pool, max * sizeof(void *));
18296320377fSOlaf Kirch 	}
18306320377fSOlaf Kirch 
18317996a778SMike Christie 	return 0;
18326320377fSOlaf Kirch 
18336320377fSOlaf Kirch enomem:
18346320377fSOlaf Kirch 	iscsi_pool_free(q);
18356320377fSOlaf Kirch 	return -ENOMEM;
18367996a778SMike Christie }
18377996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_pool_init);
18387996a778SMike Christie 
18396320377fSOlaf Kirch void iscsi_pool_free(struct iscsi_pool *q)
18407996a778SMike Christie {
18417996a778SMike Christie 	int i;
18427996a778SMike Christie 
18437996a778SMike Christie 	for (i = 0; i < q->max; i++)
18446320377fSOlaf Kirch 		kfree(q->pool[i]);
18456320377fSOlaf Kirch 	if (q->pool)
18467996a778SMike Christie 		kfree(q->pool);
18477996a778SMike Christie }
18487996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_pool_free);
18497996a778SMike Christie 
1850a4804cd6SMike Christie /**
1851a4804cd6SMike Christie  * iscsi_host_add - add host to system
1852a4804cd6SMike Christie  * @shost: scsi host
1853a4804cd6SMike Christie  * @pdev: parent device
1854a4804cd6SMike Christie  *
1855a4804cd6SMike Christie  * This should be called by partial offload and software iscsi drivers
1856a4804cd6SMike Christie  * to add a host to the system.
1857a4804cd6SMike Christie  */
1858a4804cd6SMike Christie int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev)
18597996a778SMike Christie {
18608e9a20ceSMike Christie 	if (!shost->can_queue)
18618e9a20ceSMike Christie 		shost->can_queue = ISCSI_DEF_XMIT_CMDS_MAX;
18628e9a20ceSMike Christie 
1863a4804cd6SMike Christie 	return scsi_add_host(shost, pdev);
1864a4804cd6SMike Christie }
1865a4804cd6SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_add);
1866a4804cd6SMike Christie 
1867a4804cd6SMike Christie /**
1868a4804cd6SMike Christie  * iscsi_host_alloc - allocate a host and driver data
1869a4804cd6SMike Christie  * @sht: scsi host template
1870a4804cd6SMike Christie  * @dd_data_size: driver host data size
1871a4804cd6SMike Christie  * @qdepth: default device queue depth
1872a4804cd6SMike Christie  *
1873a4804cd6SMike Christie  * This should be called by partial offload and software iscsi drivers.
1874a4804cd6SMike Christie  * To access the driver specific memory use the iscsi_host_priv() macro.
1875a4804cd6SMike Christie  */
1876a4804cd6SMike Christie struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
1877a4804cd6SMike Christie 				   int dd_data_size, uint16_t qdepth)
1878a4804cd6SMike Christie {
1879a4804cd6SMike Christie 	struct Scsi_Host *shost;
1880a4804cd6SMike Christie 
1881a4804cd6SMike Christie 	shost = scsi_host_alloc(sht, sizeof(struct iscsi_host) + dd_data_size);
1882a4804cd6SMike Christie 	if (!shost)
1883a4804cd6SMike Christie 		return NULL;
1884a4804cd6SMike Christie 	shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
1885a4804cd6SMike Christie 
18861548271eSMike Christie 	if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) {
18871548271eSMike Christie 		if (qdepth != 0)
18881548271eSMike Christie 			printk(KERN_ERR "iscsi: invalid queue depth of %d. "
18891548271eSMike Christie 			       "Queue depth must be between 1 and %d.\n",
18901548271eSMike Christie 			       qdepth, ISCSI_MAX_CMD_PER_LUN);
18911548271eSMike Christie 		qdepth = ISCSI_DEF_CMD_PER_LUN;
18921548271eSMike Christie 	}
189375613521SMike Christie 	shost->cmd_per_lun = qdepth;
1894a4804cd6SMike Christie 	return shost;
189575613521SMike Christie }
1896a4804cd6SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_alloc);
189775613521SMike Christie 
1898a4804cd6SMike Christie /**
1899a4804cd6SMike Christie  * iscsi_host_remove - remove host and sessions
1900a4804cd6SMike Christie  * @shost: scsi host
1901a4804cd6SMike Christie  *
1902a4804cd6SMike Christie  * This will also remove any sessions attached to the host, but if userspace
1903a4804cd6SMike Christie  * is managing the session at the same time this will break. TODO: add
1904a4804cd6SMike Christie  * refcounting to the netlink iscsi interface so a rmmod or host hot unplug
1905a4804cd6SMike Christie  * does not remove the memory from under us.
1906a4804cd6SMike Christie  */
1907a4804cd6SMike Christie void iscsi_host_remove(struct Scsi_Host *shost)
1908a4804cd6SMike Christie {
1909a4804cd6SMike Christie 	iscsi_host_for_each_session(shost, iscsi_session_teardown);
1910a4804cd6SMike Christie 	scsi_remove_host(shost);
1911a4804cd6SMike Christie }
1912a4804cd6SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_remove);
1913a4804cd6SMike Christie 
1914a4804cd6SMike Christie void iscsi_host_free(struct Scsi_Host *shost)
191575613521SMike Christie {
191675613521SMike Christie 	struct iscsi_host *ihost = shost_priv(shost);
191775613521SMike Christie 
191875613521SMike Christie 	kfree(ihost->netdev);
191975613521SMike Christie 	kfree(ihost->hwaddress);
192075613521SMike Christie 	kfree(ihost->initiatorname);
1921a4804cd6SMike Christie 	scsi_host_put(shost);
192275613521SMike Christie }
1923a4804cd6SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_free);
192475613521SMike Christie 
192575613521SMike Christie /**
192675613521SMike Christie  * iscsi_session_setup - create iscsi cls session and host and session
192775613521SMike Christie  * @iscsit: iscsi transport template
192875613521SMike Christie  * @shost: scsi host
192975613521SMike Christie  * @cmds_max: session can queue
19309c19a7d0SMike Christie  * @cmd_task_size: LLD task private data size
193175613521SMike Christie  * @initial_cmdsn: initial CmdSN
193275613521SMike Christie  *
193375613521SMike Christie  * This can be used by software iscsi_transports that allocate
193475613521SMike Christie  * a session per scsi host.
19353cf7b233SMike Christie  *
19363cf7b233SMike Christie  * Callers should set cmds_max to the largest total numer (mgmt + scsi) of
19373cf7b233SMike Christie  * tasks they support. The iscsi layer reserves ISCSI_MGMT_CMDS_MAX tasks
19383cf7b233SMike Christie  * for nop handling and login/logout requests.
193975613521SMike Christie  */
194075613521SMike Christie struct iscsi_cls_session *
194175613521SMike Christie iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
19423cf7b233SMike Christie 		    uint16_t cmds_max, int cmd_task_size,
19437970634bSMike Christie 		    uint32_t initial_cmdsn, unsigned int id)
194475613521SMike Christie {
194575613521SMike Christie 	struct iscsi_session *session;
194675613521SMike Christie 	struct iscsi_cls_session *cls_session;
19473cf7b233SMike Christie 	int cmd_i, scsi_cmds, total_cmds = cmds_max;
19488e9a20ceSMike Christie 
19498e9a20ceSMike Christie 	if (!total_cmds)
19508e9a20ceSMike Christie 		total_cmds = ISCSI_DEF_XMIT_CMDS_MAX;
19513e5c28adSMike Christie 	/*
19523cf7b233SMike Christie 	 * The iscsi layer needs some tasks for nop handling and tmfs,
19533cf7b233SMike Christie 	 * so the cmds_max must at least be greater than ISCSI_MGMT_CMDS_MAX
19543cf7b233SMike Christie 	 * + 1 command for scsi IO.
19553e5c28adSMike Christie 	 */
19563cf7b233SMike Christie 	if (total_cmds < ISCSI_TOTAL_CMDS_MIN) {
19573cf7b233SMike Christie 		printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue "
19583cf7b233SMike Christie 		       "must be a power of two that is at least %d.\n",
19593cf7b233SMike Christie 		       total_cmds, ISCSI_TOTAL_CMDS_MIN);
19603cf7b233SMike Christie 		return NULL;
19611548271eSMike Christie 	}
19623cf7b233SMike Christie 
19633cf7b233SMike Christie 	if (total_cmds > ISCSI_TOTAL_CMDS_MAX) {
19643cf7b233SMike Christie 		printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue "
19653cf7b233SMike Christie 		       "must be a power of 2 less than or equal to %d.\n",
19663cf7b233SMike Christie 		       cmds_max, ISCSI_TOTAL_CMDS_MAX);
19673cf7b233SMike Christie 		total_cmds = ISCSI_TOTAL_CMDS_MAX;
19683cf7b233SMike Christie 	}
19693cf7b233SMike Christie 
19703cf7b233SMike Christie 	if (!is_power_of_2(total_cmds)) {
19713cf7b233SMike Christie 		printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue "
19723cf7b233SMike Christie 		       "must be a power of 2.\n", total_cmds);
19733cf7b233SMike Christie 		total_cmds = rounddown_pow_of_two(total_cmds);
19743cf7b233SMike Christie 		if (total_cmds < ISCSI_TOTAL_CMDS_MIN)
19753cf7b233SMike Christie 			return NULL;
19763cf7b233SMike Christie 		printk(KERN_INFO "iscsi: Rounding can_queue to %d.\n",
19773cf7b233SMike Christie 		       total_cmds);
19783cf7b233SMike Christie 	}
19793cf7b233SMike Christie 	scsi_cmds = total_cmds - ISCSI_MGMT_CMDS_MAX;
19801548271eSMike Christie 
19815d91e209SMike Christie 	cls_session = iscsi_alloc_session(shost, iscsit,
19825d91e209SMike Christie 					  sizeof(struct iscsi_session));
198375613521SMike Christie 	if (!cls_session)
19847996a778SMike Christie 		return NULL;
198575613521SMike Christie 	session = cls_session->dd_data;
198675613521SMike Christie 	session->cls_session = cls_session;
19877996a778SMike Christie 	session->host = shost;
19887996a778SMike Christie 	session->state = ISCSI_STATE_FREE;
1989f6d5180cSMike Christie 	session->fast_abort = 1;
19904cd49ea1SMike Christie 	session->lu_reset_timeout = 15;
19914cd49ea1SMike Christie 	session->abort_timeout = 10;
19923cf7b233SMike Christie 	session->scsi_cmds_max = scsi_cmds;
19933cf7b233SMike Christie 	session->cmds_max = total_cmds;
1994e0726407SMike Christie 	session->queued_cmdsn = session->cmdsn = initial_cmdsn;
19957996a778SMike Christie 	session->exp_cmdsn = initial_cmdsn + 1;
19967996a778SMike Christie 	session->max_cmdsn = initial_cmdsn + 1;
19977996a778SMike Christie 	session->max_r2t = 1;
19987996a778SMike Christie 	session->tt = iscsit;
19996724add1SMike Christie 	mutex_init(&session->eh_mutex);
200075613521SMike Christie 	spin_lock_init(&session->lock);
20017996a778SMike Christie 
20027996a778SMike Christie 	/* initialize SCSI PDU commands pool */
20037996a778SMike Christie 	if (iscsi_pool_init(&session->cmdpool, session->cmds_max,
20047996a778SMike Christie 			    (void***)&session->cmds,
20059c19a7d0SMike Christie 			    cmd_task_size + sizeof(struct iscsi_task)))
20067996a778SMike Christie 		goto cmdpool_alloc_fail;
20077996a778SMike Christie 
20087996a778SMike Christie 	/* pre-format cmds pool with ITT */
20097996a778SMike Christie 	for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
20109c19a7d0SMike Christie 		struct iscsi_task *task = session->cmds[cmd_i];
20117996a778SMike Christie 
20129c19a7d0SMike Christie 		if (cmd_task_size)
20139c19a7d0SMike Christie 			task->dd_data = &task[1];
20149c19a7d0SMike Christie 		task->itt = cmd_i;
20159c19a7d0SMike Christie 		INIT_LIST_HEAD(&task->running);
20167996a778SMike Christie 	}
20177996a778SMike Christie 
2018f53a88daSMike Christie 	if (!try_module_get(iscsit->owner))
201975613521SMike Christie 		goto module_get_fail;
202075613521SMike Christie 
20217970634bSMike Christie 	if (iscsi_add_session(cls_session, id))
2022f53a88daSMike Christie 		goto cls_session_fail;
20237996a778SMike Christie 	return cls_session;
20247996a778SMike Christie 
20257996a778SMike Christie cls_session_fail:
202675613521SMike Christie 	module_put(iscsit->owner);
202775613521SMike Christie module_get_fail:
20286320377fSOlaf Kirch 	iscsi_pool_free(&session->cmdpool);
20297996a778SMike Christie cmdpool_alloc_fail:
203075613521SMike Christie 	iscsi_free_session(cls_session);
20317996a778SMike Christie 	return NULL;
20327996a778SMike Christie }
20337996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_session_setup);
20347996a778SMike Christie 
20357996a778SMike Christie /**
20367996a778SMike Christie  * iscsi_session_teardown - destroy session, host, and cls_session
203775613521SMike Christie  * @cls_session: iscsi session
20387996a778SMike Christie  *
203975613521SMike Christie  * The driver must have called iscsi_remove_session before
204075613521SMike Christie  * calling this.
204175613521SMike Christie  */
20427996a778SMike Christie void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
20437996a778SMike Christie {
204475613521SMike Christie 	struct iscsi_session *session = cls_session->dd_data;
204563f75cc8SMike Christie 	struct module *owner = cls_session->transport->owner;
20467996a778SMike Christie 
20476320377fSOlaf Kirch 	iscsi_pool_free(&session->cmdpool);
20487996a778SMike Christie 
2049b2c64167SMike Christie 	kfree(session->password);
2050b2c64167SMike Christie 	kfree(session->password_in);
2051b2c64167SMike Christie 	kfree(session->username);
2052b2c64167SMike Christie 	kfree(session->username_in);
2053f3ff0c36SMike Christie 	kfree(session->targetname);
205488dfd340SMike Christie 	kfree(session->initiatorname);
205588dfd340SMike Christie 	kfree(session->ifacename);
2056f3ff0c36SMike Christie 
205775613521SMike Christie 	iscsi_destroy_session(cls_session);
205863f75cc8SMike Christie 	module_put(owner);
20597996a778SMike Christie }
20607996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_session_teardown);
20617996a778SMike Christie 
20627996a778SMike Christie /**
20637996a778SMike Christie  * iscsi_conn_setup - create iscsi_cls_conn and iscsi_conn
20647996a778SMike Christie  * @cls_session: iscsi_cls_session
20655d91e209SMike Christie  * @dd_size: private driver data size
20667996a778SMike Christie  * @conn_idx: cid
20675d91e209SMike Christie  */
20687996a778SMike Christie struct iscsi_cls_conn *
20695d91e209SMike Christie iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
20705d91e209SMike Christie 		 uint32_t conn_idx)
20717996a778SMike Christie {
207275613521SMike Christie 	struct iscsi_session *session = cls_session->dd_data;
20737996a778SMike Christie 	struct iscsi_conn *conn;
20747996a778SMike Christie 	struct iscsi_cls_conn *cls_conn;
2075d36ab6f3SMike Christie 	char *data;
20767996a778SMike Christie 
20775d91e209SMike Christie 	cls_conn = iscsi_create_conn(cls_session, sizeof(*conn) + dd_size,
20785d91e209SMike Christie 				     conn_idx);
20797996a778SMike Christie 	if (!cls_conn)
20807996a778SMike Christie 		return NULL;
20817996a778SMike Christie 	conn = cls_conn->dd_data;
20825d91e209SMike Christie 	memset(conn, 0, sizeof(*conn) + dd_size);
20837996a778SMike Christie 
20845d91e209SMike Christie 	conn->dd_data = cls_conn->dd_data + sizeof(*conn);
20857996a778SMike Christie 	conn->session = session;
20867996a778SMike Christie 	conn->cls_conn = cls_conn;
20877996a778SMike Christie 	conn->c_stage = ISCSI_CONN_INITIAL_STAGE;
20887996a778SMike Christie 	conn->id = conn_idx;
20897996a778SMike Christie 	conn->exp_statsn = 0;
2090843c0a8aSMike Christie 	conn->tmf_state = TMF_INITIAL;
2091f6d5180cSMike Christie 
2092f6d5180cSMike Christie 	init_timer(&conn->transport_timer);
2093f6d5180cSMike Christie 	conn->transport_timer.data = (unsigned long)conn;
2094f6d5180cSMike Christie 	conn->transport_timer.function = iscsi_check_transport_timeouts;
2095f6d5180cSMike Christie 
20967996a778SMike Christie 	INIT_LIST_HEAD(&conn->run_list);
20977996a778SMike Christie 	INIT_LIST_HEAD(&conn->mgmt_run_list);
2098843c0a8aSMike Christie 	INIT_LIST_HEAD(&conn->mgmtqueue);
2099b6c395edSMike Christie 	INIT_LIST_HEAD(&conn->xmitqueue);
2100843c0a8aSMike Christie 	INIT_LIST_HEAD(&conn->requeue);
2101c4028958SDavid Howells 	INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
21027996a778SMike Christie 
21039c19a7d0SMike Christie 	/* allocate login_task used for the login/text sequences */
21047996a778SMike Christie 	spin_lock_bh(&session->lock);
21053e5c28adSMike Christie 	if (!__kfifo_get(session->cmdpool.queue,
21069c19a7d0SMike Christie                          (void*)&conn->login_task,
21077996a778SMike Christie 			 sizeof(void*))) {
21087996a778SMike Christie 		spin_unlock_bh(&session->lock);
21099c19a7d0SMike Christie 		goto login_task_alloc_fail;
21107996a778SMike Christie 	}
21117996a778SMike Christie 	spin_unlock_bh(&session->lock);
21127996a778SMike Christie 
2113bf32ed33SMike Christie 	data = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN, GFP_KERNEL);
2114d36ab6f3SMike Christie 	if (!data)
21159c19a7d0SMike Christie 		goto login_task_data_alloc_fail;
21169c19a7d0SMike Christie 	conn->login_task->data = conn->data = data;
2117d36ab6f3SMike Christie 
2118843c0a8aSMike Christie 	init_timer(&conn->tmf_timer);
21197996a778SMike Christie 	init_waitqueue_head(&conn->ehwait);
21207996a778SMike Christie 
21217996a778SMike Christie 	return cls_conn;
21227996a778SMike Christie 
21239c19a7d0SMike Christie login_task_data_alloc_fail:
21249c19a7d0SMike Christie 	__kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
2125d36ab6f3SMike Christie 		    sizeof(void*));
21269c19a7d0SMike Christie login_task_alloc_fail:
21277996a778SMike Christie 	iscsi_destroy_conn(cls_conn);
21287996a778SMike Christie 	return NULL;
21297996a778SMike Christie }
21307996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_setup);
21317996a778SMike Christie 
21327996a778SMike Christie /**
21337996a778SMike Christie  * iscsi_conn_teardown - teardown iscsi connection
21347996a778SMike Christie  * cls_conn: iscsi class connection
21357996a778SMike Christie  *
21367996a778SMike Christie  * TODO: we may need to make this into a two step process
21377996a778SMike Christie  * like scsi-mls remove + put host
21387996a778SMike Christie  */
21397996a778SMike Christie void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
21407996a778SMike Christie {
21417996a778SMike Christie 	struct iscsi_conn *conn = cls_conn->dd_data;
21427996a778SMike Christie 	struct iscsi_session *session = conn->session;
21437996a778SMike Christie 	unsigned long flags;
21447996a778SMike Christie 
2145f6d5180cSMike Christie 	del_timer_sync(&conn->transport_timer);
2146f6d5180cSMike Christie 
21477996a778SMike Christie 	spin_lock_bh(&session->lock);
21487996a778SMike Christie 	conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
21497996a778SMike Christie 	if (session->leadconn == conn) {
21507996a778SMike Christie 		/*
21517996a778SMike Christie 		 * leading connection? then give up on recovery.
21527996a778SMike Christie 		 */
21537996a778SMike Christie 		session->state = ISCSI_STATE_TERMINATE;
21547996a778SMike Christie 		wake_up(&conn->ehwait);
21557996a778SMike Christie 	}
21567996a778SMike Christie 	spin_unlock_bh(&session->lock);
21577996a778SMike Christie 
21587996a778SMike Christie 	/*
21597996a778SMike Christie 	 * Block until all in-progress commands for this connection
21607996a778SMike Christie 	 * time out or fail.
21617996a778SMike Christie 	 */
21627996a778SMike Christie 	for (;;) {
21637996a778SMike Christie 		spin_lock_irqsave(session->host->host_lock, flags);
21647996a778SMike Christie 		if (!session->host->host_busy) { /* OK for ERL == 0 */
21657996a778SMike Christie 			spin_unlock_irqrestore(session->host->host_lock, flags);
21667996a778SMike Christie 			break;
21677996a778SMike Christie 		}
21687996a778SMike Christie 		spin_unlock_irqrestore(session->host->host_lock, flags);
21697996a778SMike Christie 		msleep_interruptible(500);
2170322d739dSMike Christie 		iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): "
2171322d739dSMike Christie 				  "host_busy %d host_failed %d\n",
2172322d739dSMike Christie 				  session->host->host_busy,
2173be2df72eSOr Gerlitz 				  session->host->host_failed);
21747996a778SMike Christie 		/*
21757996a778SMike Christie 		 * force eh_abort() to unblock
21767996a778SMike Christie 		 */
21777996a778SMike Christie 		wake_up(&conn->ehwait);
21787996a778SMike Christie 	}
21797996a778SMike Christie 
2180779ea120SMike Christie 	/* flush queued up work because we free the connection below */
2181843c0a8aSMike Christie 	iscsi_suspend_tx(conn);
2182779ea120SMike Christie 
21837996a778SMike Christie 	spin_lock_bh(&session->lock);
2184c8dc1e52SMike Christie 	kfree(conn->data);
2185f3ff0c36SMike Christie 	kfree(conn->persistent_address);
21869c19a7d0SMike Christie 	__kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
21877996a778SMike Christie 		    sizeof(void*));
2188e0726407SMike Christie 	if (session->leadconn == conn)
21897996a778SMike Christie 		session->leadconn = NULL;
21907996a778SMike Christie 	spin_unlock_bh(&session->lock);
21917996a778SMike Christie 
21927996a778SMike Christie 	iscsi_destroy_conn(cls_conn);
21937996a778SMike Christie }
21947996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_teardown);
21957996a778SMike Christie 
21967996a778SMike Christie int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
21977996a778SMike Christie {
21987996a778SMike Christie 	struct iscsi_conn *conn = cls_conn->dd_data;
21997996a778SMike Christie 	struct iscsi_session *session = conn->session;
22007996a778SMike Christie 
2201ffd0436eSMike Christie 	if (!session) {
2202322d739dSMike Christie 		iscsi_conn_printk(KERN_ERR, conn,
2203322d739dSMike Christie 				  "can't start unbound connection\n");
22047996a778SMike Christie 		return -EPERM;
22057996a778SMike Christie 	}
22067996a778SMike Christie 
2207db98ccdeSMike Christie 	if ((session->imm_data_en || !session->initial_r2t_en) &&
2208db98ccdeSMike Christie 	     session->first_burst > session->max_burst) {
2209322d739dSMike Christie 		iscsi_conn_printk(KERN_INFO, conn, "invalid burst lengths: "
2210ffd0436eSMike Christie 				  "first_burst %d max_burst %d\n",
2211ffd0436eSMike Christie 				  session->first_burst, session->max_burst);
2212ffd0436eSMike Christie 		return -EINVAL;
2213ffd0436eSMike Christie 	}
2214ffd0436eSMike Christie 
2215f6d5180cSMike Christie 	if (conn->ping_timeout && !conn->recv_timeout) {
2216322d739dSMike Christie 		iscsi_conn_printk(KERN_ERR, conn, "invalid recv timeout of "
2217322d739dSMike Christie 				  "zero. Using 5 seconds\n.");
2218f6d5180cSMike Christie 		conn->recv_timeout = 5;
2219f6d5180cSMike Christie 	}
2220f6d5180cSMike Christie 
2221f6d5180cSMike Christie 	if (conn->recv_timeout && !conn->ping_timeout) {
2222322d739dSMike Christie 		iscsi_conn_printk(KERN_ERR, conn, "invalid ping timeout of "
2223322d739dSMike Christie 				  "zero. Using 5 seconds.\n");
2224f6d5180cSMike Christie 		conn->ping_timeout = 5;
2225f6d5180cSMike Christie 	}
2226f6d5180cSMike Christie 
22277996a778SMike Christie 	spin_lock_bh(&session->lock);
22287996a778SMike Christie 	conn->c_stage = ISCSI_CONN_STARTED;
22297996a778SMike Christie 	session->state = ISCSI_STATE_LOGGED_IN;
2230e0726407SMike Christie 	session->queued_cmdsn = session->cmdsn;
22317996a778SMike Christie 
2232f6d5180cSMike Christie 	conn->last_recv = jiffies;
2233f6d5180cSMike Christie 	conn->last_ping = jiffies;
2234f6d5180cSMike Christie 	if (conn->recv_timeout && conn->ping_timeout)
2235f6d5180cSMike Christie 		mod_timer(&conn->transport_timer,
2236f6d5180cSMike Christie 			  jiffies + (conn->recv_timeout * HZ));
2237f6d5180cSMike Christie 
22387996a778SMike Christie 	switch(conn->stop_stage) {
22397996a778SMike Christie 	case STOP_CONN_RECOVER:
22407996a778SMike Christie 		/*
22417996a778SMike Christie 		 * unblock eh_abort() if it is blocked. re-try all
22427996a778SMike Christie 		 * commands after successful recovery
22437996a778SMike Christie 		 */
22447996a778SMike Christie 		conn->stop_stage = 0;
2245843c0a8aSMike Christie 		conn->tmf_state = TMF_INITIAL;
22467996a778SMike Christie 		session->age++;
22478b1d0343SMike Christie 		if (session->age == 16)
22488b1d0343SMike Christie 			session->age = 0;
22496eabafbeSMike Christie 		break;
22507996a778SMike Christie 	case STOP_CONN_TERM:
22517996a778SMike Christie 		conn->stop_stage = 0;
22527996a778SMike Christie 		break;
22537996a778SMike Christie 	default:
22547996a778SMike Christie 		break;
22557996a778SMike Christie 	}
22567996a778SMike Christie 	spin_unlock_bh(&session->lock);
22577996a778SMike Christie 
225875613521SMike Christie 	iscsi_unblock_session(session->cls_session);
22596eabafbeSMike Christie 	wake_up(&conn->ehwait);
22607996a778SMike Christie 	return 0;
22617996a778SMike Christie }
22627996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_start);
22637996a778SMike Christie 
22647996a778SMike Christie static void
22657996a778SMike Christie flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn)
22667996a778SMike Christie {
22679c19a7d0SMike Christie 	struct iscsi_task *task, *tmp;
22687996a778SMike Christie 
22697996a778SMike Christie 	/* handle pending */
22709c19a7d0SMike Christie 	list_for_each_entry_safe(task, tmp, &conn->mgmtqueue, running) {
22719c19a7d0SMike Christie 		debug_scsi("flushing pending mgmt task itt 0x%x\n", task->itt);
22729c19a7d0SMike Christie 		/* release ref from prep task */
22739c19a7d0SMike Christie 		__iscsi_put_task(task);
22747996a778SMike Christie 	}
22757996a778SMike Christie 
22767996a778SMike Christie 	/* handle running */
22779c19a7d0SMike Christie 	list_for_each_entry_safe(task, tmp, &conn->mgmt_run_list, running) {
22789c19a7d0SMike Christie 		debug_scsi("flushing running mgmt task itt 0x%x\n", task->itt);
22799c19a7d0SMike Christie 		/* release ref from prep task */
22809c19a7d0SMike Christie 		__iscsi_put_task(task);
22817996a778SMike Christie 	}
22827996a778SMike Christie 
22839c19a7d0SMike Christie 	conn->task = NULL;
22847996a778SMike Christie }
22857996a778SMike Christie 
2286656cffc9SMike Christie static void iscsi_start_session_recovery(struct iscsi_session *session,
22877996a778SMike Christie 					 struct iscsi_conn *conn, int flag)
22887996a778SMike Christie {
2289ed2abc7fSMike Christie 	int old_stop_stage;
2290ed2abc7fSMike Christie 
2291f6d5180cSMike Christie 	del_timer_sync(&conn->transport_timer);
2292f6d5180cSMike Christie 
22936724add1SMike Christie 	mutex_lock(&session->eh_mutex);
22947996a778SMike Christie 	spin_lock_bh(&session->lock);
2295ed2abc7fSMike Christie 	if (conn->stop_stage == STOP_CONN_TERM) {
22967996a778SMike Christie 		spin_unlock_bh(&session->lock);
22976724add1SMike Christie 		mutex_unlock(&session->eh_mutex);
22986724add1SMike Christie 		return;
22996724add1SMike Christie 	}
23006724add1SMike Christie 
23016724add1SMike Christie 	/*
2302ed2abc7fSMike Christie 	 * When this is called for the in_login state, we only want to clean
23039c19a7d0SMike Christie 	 * up the login task and connection. We do not need to block and set
230467a61114SMike Christie 	 * the recovery state again
2305ed2abc7fSMike Christie 	 */
230667a61114SMike Christie 	if (flag == STOP_CONN_TERM)
230767a61114SMike Christie 		session->state = ISCSI_STATE_TERMINATE;
230867a61114SMike Christie 	else if (conn->stop_stage != STOP_CONN_RECOVER)
230967a61114SMike Christie 		session->state = ISCSI_STATE_IN_RECOVERY;
2310ed2abc7fSMike Christie 
2311ed2abc7fSMike Christie 	old_stop_stage = conn->stop_stage;
23127996a778SMike Christie 	conn->stop_stage = flag;
231367a61114SMike Christie 	conn->c_stage = ISCSI_CONN_STOPPED;
23147996a778SMike Christie 	spin_unlock_bh(&session->lock);
23156724add1SMike Christie 
23166724add1SMike Christie 	iscsi_suspend_tx(conn);
23177996a778SMike Christie 	/*
23187996a778SMike Christie 	 * for connection level recovery we should not calculate
23197996a778SMike Christie 	 * header digest. conn->hdr_size used for optimization
23207996a778SMike Christie 	 * in hdr_extract() and will be re-negotiated at
23217996a778SMike Christie 	 * set_param() time.
23227996a778SMike Christie 	 */
23237996a778SMike Christie 	if (flag == STOP_CONN_RECOVER) {
23247996a778SMike Christie 		conn->hdrdgst_en = 0;
23257996a778SMike Christie 		conn->datadgst_en = 0;
2326656cffc9SMike Christie 		if (session->state == ISCSI_STATE_IN_RECOVERY &&
232767a61114SMike Christie 		    old_stop_stage != STOP_CONN_RECOVER) {
232867a61114SMike Christie 			debug_scsi("blocking session\n");
232975613521SMike Christie 			iscsi_block_session(session->cls_session);
23307996a778SMike Christie 		}
233167a61114SMike Christie 	}
2332656cffc9SMike Christie 
2333656cffc9SMike Christie 	/*
2334656cffc9SMike Christie 	 * flush queues.
2335656cffc9SMike Christie 	 */
2336656cffc9SMike Christie 	spin_lock_bh(&session->lock);
23376eabafbeSMike Christie 	fail_all_commands(conn, -1,
23386eabafbeSMike Christie 			STOP_CONN_RECOVER ? DID_BUS_BUSY : DID_ERROR);
2339656cffc9SMike Christie 	flush_control_queues(session, conn);
2340656cffc9SMike Christie 	spin_unlock_bh(&session->lock);
23416724add1SMike Christie 	mutex_unlock(&session->eh_mutex);
23427996a778SMike Christie }
23437996a778SMike Christie 
23447996a778SMike Christie void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
23457996a778SMike Christie {
23467996a778SMike Christie 	struct iscsi_conn *conn = cls_conn->dd_data;
23477996a778SMike Christie 	struct iscsi_session *session = conn->session;
23487996a778SMike Christie 
23497996a778SMike Christie 	switch (flag) {
23507996a778SMike Christie 	case STOP_CONN_RECOVER:
23517996a778SMike Christie 	case STOP_CONN_TERM:
23527996a778SMike Christie 		iscsi_start_session_recovery(session, conn, flag);
23538d2860b3SMike Christie 		break;
23547996a778SMike Christie 	default:
2355322d739dSMike Christie 		iscsi_conn_printk(KERN_ERR, conn,
2356322d739dSMike Christie 				  "invalid stop flag %d\n", flag);
23577996a778SMike Christie 	}
23587996a778SMike Christie }
23597996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_stop);
23607996a778SMike Christie 
23617996a778SMike Christie int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
23627996a778SMike Christie 		    struct iscsi_cls_conn *cls_conn, int is_leading)
23637996a778SMike Christie {
236475613521SMike Christie 	struct iscsi_session *session = cls_session->dd_data;
236598644047SMike Christie 	struct iscsi_conn *conn = cls_conn->dd_data;
23667996a778SMike Christie 
23677996a778SMike Christie 	spin_lock_bh(&session->lock);
23687996a778SMike Christie 	if (is_leading)
23697996a778SMike Christie 		session->leadconn = conn;
237098644047SMike Christie 	spin_unlock_bh(&session->lock);
23717996a778SMike Christie 
23727996a778SMike Christie 	/*
23737996a778SMike Christie 	 * Unblock xmitworker(), Login Phase will pass through.
23747996a778SMike Christie 	 */
23757996a778SMike Christie 	clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
23767996a778SMike Christie 	clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
23777996a778SMike Christie 	return 0;
23787996a778SMike Christie }
23797996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_bind);
23807996a778SMike Christie 
2381a54a52caSMike Christie 
2382a54a52caSMike Christie int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
2383a54a52caSMike Christie 		    enum iscsi_param param, char *buf, int buflen)
2384a54a52caSMike Christie {
2385a54a52caSMike Christie 	struct iscsi_conn *conn = cls_conn->dd_data;
2386a54a52caSMike Christie 	struct iscsi_session *session = conn->session;
2387a54a52caSMike Christie 	uint32_t value;
2388a54a52caSMike Christie 
2389a54a52caSMike Christie 	switch(param) {
2390843c0a8aSMike Christie 	case ISCSI_PARAM_FAST_ABORT:
2391843c0a8aSMike Christie 		sscanf(buf, "%d", &session->fast_abort);
2392843c0a8aSMike Christie 		break;
2393f6d5180cSMike Christie 	case ISCSI_PARAM_ABORT_TMO:
2394f6d5180cSMike Christie 		sscanf(buf, "%d", &session->abort_timeout);
2395f6d5180cSMike Christie 		break;
2396f6d5180cSMike Christie 	case ISCSI_PARAM_LU_RESET_TMO:
2397f6d5180cSMike Christie 		sscanf(buf, "%d", &session->lu_reset_timeout);
2398f6d5180cSMike Christie 		break;
2399f6d5180cSMike Christie 	case ISCSI_PARAM_PING_TMO:
2400f6d5180cSMike Christie 		sscanf(buf, "%d", &conn->ping_timeout);
2401f6d5180cSMike Christie 		break;
2402f6d5180cSMike Christie 	case ISCSI_PARAM_RECV_TMO:
2403f6d5180cSMike Christie 		sscanf(buf, "%d", &conn->recv_timeout);
2404f6d5180cSMike Christie 		break;
2405a54a52caSMike Christie 	case ISCSI_PARAM_MAX_RECV_DLENGTH:
2406a54a52caSMike Christie 		sscanf(buf, "%d", &conn->max_recv_dlength);
2407a54a52caSMike Christie 		break;
2408a54a52caSMike Christie 	case ISCSI_PARAM_MAX_XMIT_DLENGTH:
2409a54a52caSMike Christie 		sscanf(buf, "%d", &conn->max_xmit_dlength);
2410a54a52caSMike Christie 		break;
2411a54a52caSMike Christie 	case ISCSI_PARAM_HDRDGST_EN:
2412a54a52caSMike Christie 		sscanf(buf, "%d", &conn->hdrdgst_en);
2413a54a52caSMike Christie 		break;
2414a54a52caSMike Christie 	case ISCSI_PARAM_DATADGST_EN:
2415a54a52caSMike Christie 		sscanf(buf, "%d", &conn->datadgst_en);
2416a54a52caSMike Christie 		break;
2417a54a52caSMike Christie 	case ISCSI_PARAM_INITIAL_R2T_EN:
2418a54a52caSMike Christie 		sscanf(buf, "%d", &session->initial_r2t_en);
2419a54a52caSMike Christie 		break;
2420a54a52caSMike Christie 	case ISCSI_PARAM_MAX_R2T:
2421a54a52caSMike Christie 		sscanf(buf, "%d", &session->max_r2t);
2422a54a52caSMike Christie 		break;
2423a54a52caSMike Christie 	case ISCSI_PARAM_IMM_DATA_EN:
2424a54a52caSMike Christie 		sscanf(buf, "%d", &session->imm_data_en);
2425a54a52caSMike Christie 		break;
2426a54a52caSMike Christie 	case ISCSI_PARAM_FIRST_BURST:
2427a54a52caSMike Christie 		sscanf(buf, "%d", &session->first_burst);
2428a54a52caSMike Christie 		break;
2429a54a52caSMike Christie 	case ISCSI_PARAM_MAX_BURST:
2430a54a52caSMike Christie 		sscanf(buf, "%d", &session->max_burst);
2431a54a52caSMike Christie 		break;
2432a54a52caSMike Christie 	case ISCSI_PARAM_PDU_INORDER_EN:
2433a54a52caSMike Christie 		sscanf(buf, "%d", &session->pdu_inorder_en);
2434a54a52caSMike Christie 		break;
2435a54a52caSMike Christie 	case ISCSI_PARAM_DATASEQ_INORDER_EN:
2436a54a52caSMike Christie 		sscanf(buf, "%d", &session->dataseq_inorder_en);
2437a54a52caSMike Christie 		break;
2438a54a52caSMike Christie 	case ISCSI_PARAM_ERL:
2439a54a52caSMike Christie 		sscanf(buf, "%d", &session->erl);
2440a54a52caSMike Christie 		break;
2441a54a52caSMike Christie 	case ISCSI_PARAM_IFMARKER_EN:
2442a54a52caSMike Christie 		sscanf(buf, "%d", &value);
2443a54a52caSMike Christie 		BUG_ON(value);
2444a54a52caSMike Christie 		break;
2445a54a52caSMike Christie 	case ISCSI_PARAM_OFMARKER_EN:
2446a54a52caSMike Christie 		sscanf(buf, "%d", &value);
2447a54a52caSMike Christie 		BUG_ON(value);
2448a54a52caSMike Christie 		break;
2449a54a52caSMike Christie 	case ISCSI_PARAM_EXP_STATSN:
2450a54a52caSMike Christie 		sscanf(buf, "%u", &conn->exp_statsn);
2451a54a52caSMike Christie 		break;
2452b2c64167SMike Christie 	case ISCSI_PARAM_USERNAME:
2453b2c64167SMike Christie 		kfree(session->username);
2454b2c64167SMike Christie 		session->username = kstrdup(buf, GFP_KERNEL);
2455b2c64167SMike Christie 		if (!session->username)
2456b2c64167SMike Christie 			return -ENOMEM;
2457b2c64167SMike Christie 		break;
2458b2c64167SMike Christie 	case ISCSI_PARAM_USERNAME_IN:
2459b2c64167SMike Christie 		kfree(session->username_in);
2460b2c64167SMike Christie 		session->username_in = kstrdup(buf, GFP_KERNEL);
2461b2c64167SMike Christie 		if (!session->username_in)
2462b2c64167SMike Christie 			return -ENOMEM;
2463b2c64167SMike Christie 		break;
2464b2c64167SMike Christie 	case ISCSI_PARAM_PASSWORD:
2465b2c64167SMike Christie 		kfree(session->password);
2466b2c64167SMike Christie 		session->password = kstrdup(buf, GFP_KERNEL);
2467b2c64167SMike Christie 		if (!session->password)
2468b2c64167SMike Christie 			return -ENOMEM;
2469b2c64167SMike Christie 		break;
2470b2c64167SMike Christie 	case ISCSI_PARAM_PASSWORD_IN:
2471b2c64167SMike Christie 		kfree(session->password_in);
2472b2c64167SMike Christie 		session->password_in = kstrdup(buf, GFP_KERNEL);
2473b2c64167SMike Christie 		if (!session->password_in)
2474b2c64167SMike Christie 			return -ENOMEM;
2475b2c64167SMike Christie 		break;
2476a54a52caSMike Christie 	case ISCSI_PARAM_TARGET_NAME:
2477a54a52caSMike Christie 		/* this should not change between logins */
2478a54a52caSMike Christie 		if (session->targetname)
2479a54a52caSMike Christie 			break;
2480a54a52caSMike Christie 
2481a54a52caSMike Christie 		session->targetname = kstrdup(buf, GFP_KERNEL);
2482a54a52caSMike Christie 		if (!session->targetname)
2483a54a52caSMike Christie 			return -ENOMEM;
2484a54a52caSMike Christie 		break;
2485a54a52caSMike Christie 	case ISCSI_PARAM_TPGT:
2486a54a52caSMike Christie 		sscanf(buf, "%d", &session->tpgt);
2487a54a52caSMike Christie 		break;
2488a54a52caSMike Christie 	case ISCSI_PARAM_PERSISTENT_PORT:
2489a54a52caSMike Christie 		sscanf(buf, "%d", &conn->persistent_port);
2490a54a52caSMike Christie 		break;
2491a54a52caSMike Christie 	case ISCSI_PARAM_PERSISTENT_ADDRESS:
2492a54a52caSMike Christie 		/*
2493a54a52caSMike Christie 		 * this is the address returned in discovery so it should
2494a54a52caSMike Christie 		 * not change between logins.
2495a54a52caSMike Christie 		 */
2496a54a52caSMike Christie 		if (conn->persistent_address)
2497a54a52caSMike Christie 			break;
2498a54a52caSMike Christie 
2499a54a52caSMike Christie 		conn->persistent_address = kstrdup(buf, GFP_KERNEL);
2500a54a52caSMike Christie 		if (!conn->persistent_address)
2501a54a52caSMike Christie 			return -ENOMEM;
2502a54a52caSMike Christie 		break;
250388dfd340SMike Christie 	case ISCSI_PARAM_IFACE_NAME:
250488dfd340SMike Christie 		if (!session->ifacename)
250588dfd340SMike Christie 			session->ifacename = kstrdup(buf, GFP_KERNEL);
250688dfd340SMike Christie 		break;
250788dfd340SMike Christie 	case ISCSI_PARAM_INITIATOR_NAME:
250888dfd340SMike Christie 		if (!session->initiatorname)
250988dfd340SMike Christie 			session->initiatorname = kstrdup(buf, GFP_KERNEL);
251088dfd340SMike Christie 		break;
2511a54a52caSMike Christie 	default:
2512a54a52caSMike Christie 		return -ENOSYS;
2513a54a52caSMike Christie 	}
2514a54a52caSMike Christie 
2515a54a52caSMike Christie 	return 0;
2516a54a52caSMike Christie }
2517a54a52caSMike Christie EXPORT_SYMBOL_GPL(iscsi_set_param);
2518a54a52caSMike Christie 
2519a54a52caSMike Christie int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
2520a54a52caSMike Christie 			    enum iscsi_param param, char *buf)
2521a54a52caSMike Christie {
252275613521SMike Christie 	struct iscsi_session *session = cls_session->dd_data;
2523a54a52caSMike Christie 	int len;
2524a54a52caSMike Christie 
2525a54a52caSMike Christie 	switch(param) {
2526843c0a8aSMike Christie 	case ISCSI_PARAM_FAST_ABORT:
2527843c0a8aSMike Christie 		len = sprintf(buf, "%d\n", session->fast_abort);
2528843c0a8aSMike Christie 		break;
2529f6d5180cSMike Christie 	case ISCSI_PARAM_ABORT_TMO:
2530f6d5180cSMike Christie 		len = sprintf(buf, "%d\n", session->abort_timeout);
2531f6d5180cSMike Christie 		break;
2532f6d5180cSMike Christie 	case ISCSI_PARAM_LU_RESET_TMO:
2533f6d5180cSMike Christie 		len = sprintf(buf, "%d\n", session->lu_reset_timeout);
2534f6d5180cSMike Christie 		break;
2535a54a52caSMike Christie 	case ISCSI_PARAM_INITIAL_R2T_EN:
2536a54a52caSMike Christie 		len = sprintf(buf, "%d\n", session->initial_r2t_en);
2537a54a52caSMike Christie 		break;
2538a54a52caSMike Christie 	case ISCSI_PARAM_MAX_R2T:
2539a54a52caSMike Christie 		len = sprintf(buf, "%hu\n", session->max_r2t);
2540a54a52caSMike Christie 		break;
2541a54a52caSMike Christie 	case ISCSI_PARAM_IMM_DATA_EN:
2542a54a52caSMike Christie 		len = sprintf(buf, "%d\n", session->imm_data_en);
2543a54a52caSMike Christie 		break;
2544a54a52caSMike Christie 	case ISCSI_PARAM_FIRST_BURST:
2545a54a52caSMike Christie 		len = sprintf(buf, "%u\n", session->first_burst);
2546a54a52caSMike Christie 		break;
2547a54a52caSMike Christie 	case ISCSI_PARAM_MAX_BURST:
2548a54a52caSMike Christie 		len = sprintf(buf, "%u\n", session->max_burst);
2549a54a52caSMike Christie 		break;
2550a54a52caSMike Christie 	case ISCSI_PARAM_PDU_INORDER_EN:
2551a54a52caSMike Christie 		len = sprintf(buf, "%d\n", session->pdu_inorder_en);
2552a54a52caSMike Christie 		break;
2553a54a52caSMike Christie 	case ISCSI_PARAM_DATASEQ_INORDER_EN:
2554a54a52caSMike Christie 		len = sprintf(buf, "%d\n", session->dataseq_inorder_en);
2555a54a52caSMike Christie 		break;
2556a54a52caSMike Christie 	case ISCSI_PARAM_ERL:
2557a54a52caSMike Christie 		len = sprintf(buf, "%d\n", session->erl);
2558a54a52caSMike Christie 		break;
2559a54a52caSMike Christie 	case ISCSI_PARAM_TARGET_NAME:
2560a54a52caSMike Christie 		len = sprintf(buf, "%s\n", session->targetname);
2561a54a52caSMike Christie 		break;
2562a54a52caSMike Christie 	case ISCSI_PARAM_TPGT:
2563a54a52caSMike Christie 		len = sprintf(buf, "%d\n", session->tpgt);
2564a54a52caSMike Christie 		break;
2565b2c64167SMike Christie 	case ISCSI_PARAM_USERNAME:
2566b2c64167SMike Christie 		len = sprintf(buf, "%s\n", session->username);
2567b2c64167SMike Christie 		break;
2568b2c64167SMike Christie 	case ISCSI_PARAM_USERNAME_IN:
2569b2c64167SMike Christie 		len = sprintf(buf, "%s\n", session->username_in);
2570b2c64167SMike Christie 		break;
2571b2c64167SMike Christie 	case ISCSI_PARAM_PASSWORD:
2572b2c64167SMike Christie 		len = sprintf(buf, "%s\n", session->password);
2573b2c64167SMike Christie 		break;
2574b2c64167SMike Christie 	case ISCSI_PARAM_PASSWORD_IN:
2575b2c64167SMike Christie 		len = sprintf(buf, "%s\n", session->password_in);
2576b2c64167SMike Christie 		break;
257788dfd340SMike Christie 	case ISCSI_PARAM_IFACE_NAME:
257888dfd340SMike Christie 		len = sprintf(buf, "%s\n", session->ifacename);
257988dfd340SMike Christie 		break;
258088dfd340SMike Christie 	case ISCSI_PARAM_INITIATOR_NAME:
258188dfd340SMike Christie 		if (!session->initiatorname)
258288dfd340SMike Christie 			len = sprintf(buf, "%s\n", "unknown");
258388dfd340SMike Christie 		else
258488dfd340SMike Christie 			len = sprintf(buf, "%s\n", session->initiatorname);
258588dfd340SMike Christie 		break;
2586a54a52caSMike Christie 	default:
2587a54a52caSMike Christie 		return -ENOSYS;
2588a54a52caSMike Christie 	}
2589a54a52caSMike Christie 
2590a54a52caSMike Christie 	return len;
2591a54a52caSMike Christie }
2592a54a52caSMike Christie EXPORT_SYMBOL_GPL(iscsi_session_get_param);
2593a54a52caSMike Christie 
2594a54a52caSMike Christie int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
2595a54a52caSMike Christie 			 enum iscsi_param param, char *buf)
2596a54a52caSMike Christie {
2597a54a52caSMike Christie 	struct iscsi_conn *conn = cls_conn->dd_data;
2598a54a52caSMike Christie 	int len;
2599a54a52caSMike Christie 
2600a54a52caSMike Christie 	switch(param) {
2601f6d5180cSMike Christie 	case ISCSI_PARAM_PING_TMO:
2602f6d5180cSMike Christie 		len = sprintf(buf, "%u\n", conn->ping_timeout);
2603f6d5180cSMike Christie 		break;
2604f6d5180cSMike Christie 	case ISCSI_PARAM_RECV_TMO:
2605f6d5180cSMike Christie 		len = sprintf(buf, "%u\n", conn->recv_timeout);
2606f6d5180cSMike Christie 		break;
2607a54a52caSMike Christie 	case ISCSI_PARAM_MAX_RECV_DLENGTH:
2608a54a52caSMike Christie 		len = sprintf(buf, "%u\n", conn->max_recv_dlength);
2609a54a52caSMike Christie 		break;
2610a54a52caSMike Christie 	case ISCSI_PARAM_MAX_XMIT_DLENGTH:
2611a54a52caSMike Christie 		len = sprintf(buf, "%u\n", conn->max_xmit_dlength);
2612a54a52caSMike Christie 		break;
2613a54a52caSMike Christie 	case ISCSI_PARAM_HDRDGST_EN:
2614a54a52caSMike Christie 		len = sprintf(buf, "%d\n", conn->hdrdgst_en);
2615a54a52caSMike Christie 		break;
2616a54a52caSMike Christie 	case ISCSI_PARAM_DATADGST_EN:
2617a54a52caSMike Christie 		len = sprintf(buf, "%d\n", conn->datadgst_en);
2618a54a52caSMike Christie 		break;
2619a54a52caSMike Christie 	case ISCSI_PARAM_IFMARKER_EN:
2620a54a52caSMike Christie 		len = sprintf(buf, "%d\n", conn->ifmarker_en);
2621a54a52caSMike Christie 		break;
2622a54a52caSMike Christie 	case ISCSI_PARAM_OFMARKER_EN:
2623a54a52caSMike Christie 		len = sprintf(buf, "%d\n", conn->ofmarker_en);
2624a54a52caSMike Christie 		break;
2625a54a52caSMike Christie 	case ISCSI_PARAM_EXP_STATSN:
2626a54a52caSMike Christie 		len = sprintf(buf, "%u\n", conn->exp_statsn);
2627a54a52caSMike Christie 		break;
2628a54a52caSMike Christie 	case ISCSI_PARAM_PERSISTENT_PORT:
2629a54a52caSMike Christie 		len = sprintf(buf, "%d\n", conn->persistent_port);
2630a54a52caSMike Christie 		break;
2631a54a52caSMike Christie 	case ISCSI_PARAM_PERSISTENT_ADDRESS:
2632a54a52caSMike Christie 		len = sprintf(buf, "%s\n", conn->persistent_address);
2633a54a52caSMike Christie 		break;
2634a54a52caSMike Christie 	default:
2635a54a52caSMike Christie 		return -ENOSYS;
2636a54a52caSMike Christie 	}
2637a54a52caSMike Christie 
2638a54a52caSMike Christie 	return len;
2639a54a52caSMike Christie }
2640a54a52caSMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_get_param);
2641a54a52caSMike Christie 
26420801c242SMike Christie int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param,
26430801c242SMike Christie 			 char *buf)
26440801c242SMike Christie {
264575613521SMike Christie 	struct iscsi_host *ihost = shost_priv(shost);
26460801c242SMike Christie 	int len;
26470801c242SMike Christie 
26480801c242SMike Christie 	switch (param) {
2649d8196ed2SMike Christie 	case ISCSI_HOST_PARAM_NETDEV_NAME:
265075613521SMike Christie 		if (!ihost->netdev)
2651d8196ed2SMike Christie 			len = sprintf(buf, "%s\n", "default");
2652d8196ed2SMike Christie 		else
265375613521SMike Christie 			len = sprintf(buf, "%s\n", ihost->netdev);
2654d8196ed2SMike Christie 		break;
26550801c242SMike Christie 	case ISCSI_HOST_PARAM_HWADDRESS:
265675613521SMike Christie 		if (!ihost->hwaddress)
26570801c242SMike Christie 			len = sprintf(buf, "%s\n", "default");
26580801c242SMike Christie 		else
265975613521SMike Christie 			len = sprintf(buf, "%s\n", ihost->hwaddress);
26600801c242SMike Christie 		break;
26618ad5781aSMike Christie 	case ISCSI_HOST_PARAM_INITIATOR_NAME:
266275613521SMike Christie 		if (!ihost->initiatorname)
26638ad5781aSMike Christie 			len = sprintf(buf, "%s\n", "unknown");
26648ad5781aSMike Christie 		else
266575613521SMike Christie 			len = sprintf(buf, "%s\n", ihost->initiatorname);
26668ad5781aSMike Christie 		break;
266775613521SMike Christie 	case ISCSI_HOST_PARAM_IPADDRESS:
266875613521SMike Christie 		if (!strlen(ihost->local_address))
266975613521SMike Christie 			len = sprintf(buf, "%s\n", "unknown");
267075613521SMike Christie 		else
267175613521SMike Christie 			len = sprintf(buf, "%s\n",
267275613521SMike Christie 				      ihost->local_address);
267388dfd340SMike Christie 		break;
26740801c242SMike Christie 	default:
26750801c242SMike Christie 		return -ENOSYS;
26760801c242SMike Christie 	}
26770801c242SMike Christie 
26780801c242SMike Christie 	return len;
26790801c242SMike Christie }
26800801c242SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_get_param);
26810801c242SMike Christie 
26820801c242SMike Christie int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param,
26830801c242SMike Christie 			 char *buf, int buflen)
26840801c242SMike Christie {
268575613521SMike Christie 	struct iscsi_host *ihost = shost_priv(shost);
26860801c242SMike Christie 
26870801c242SMike Christie 	switch (param) {
2688d8196ed2SMike Christie 	case ISCSI_HOST_PARAM_NETDEV_NAME:
268975613521SMike Christie 		if (!ihost->netdev)
269075613521SMike Christie 			ihost->netdev = kstrdup(buf, GFP_KERNEL);
2691d8196ed2SMike Christie 		break;
26920801c242SMike Christie 	case ISCSI_HOST_PARAM_HWADDRESS:
269375613521SMike Christie 		if (!ihost->hwaddress)
269475613521SMike Christie 			ihost->hwaddress = kstrdup(buf, GFP_KERNEL);
26950801c242SMike Christie 		break;
26968ad5781aSMike Christie 	case ISCSI_HOST_PARAM_INITIATOR_NAME:
269775613521SMike Christie 		if (!ihost->initiatorname)
269875613521SMike Christie 			ihost->initiatorname = kstrdup(buf, GFP_KERNEL);
26998ad5781aSMike Christie 		break;
27000801c242SMike Christie 	default:
27010801c242SMike Christie 		return -ENOSYS;
27020801c242SMike Christie 	}
27030801c242SMike Christie 
27040801c242SMike Christie 	return 0;
27050801c242SMike Christie }
27060801c242SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_set_param);
27070801c242SMike Christie 
27087996a778SMike Christie MODULE_AUTHOR("Mike Christie");
27097996a778SMike Christie MODULE_DESCRIPTION("iSCSI library functions");
27107996a778SMike Christie MODULE_LICENSE("GPL");
2711