aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2006-04-06 22:13:41 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-04-14 15:09:00 -0400
commit7996a778ff8c717cb1a7a294475c59cc8f1e9fb8 (patch)
tree3d7ee67ad547a65ad10f5c7e41e20f6124ee249b
parent30a6c65236f9d26e3325cae468f330b833a3878c (diff)
[SCSI] iscsi: add libiscsi
There is a lot of code duplcited between iscsi_tcp and the upcoming iscsi_iser driver. This patch puts the duplicated code in a lib. There is more code to move around but this takes care of the basics. For iscsi_offload if they use the lib we will probably move some things around. For example in the queuecommand we will not assume that the LLD wants to do queue_work, but it is better to handle that later when we know for sure what iscsi_offload looks like (we could probably do this for iscsi_iser though to). Ideally I would like to get the iscsi_transports modules to a place where all they really have to do is put data on the wire, but how to do that will hopefully be more clear when we see other modules like iscsi_offload. Or maybe iscsi_offload will not use the lib and it will just be iscsi_iser and iscsi_tcp and maybe the iscsi_tcp_tgt if that is allowed in mainline. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r--drivers/scsi/Makefile2
-rw-r--r--drivers/scsi/libiscsi.c1697
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c116
-rw-r--r--include/scsi/iscsi_if.h3
-rw-r--r--include/scsi/libiscsi.h286
-rw-r--r--include/scsi/scsi_transport_iscsi.h59
6 files changed, 2045 insertions, 118 deletions
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index e513c3158ad9..efdff61c5808 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -33,7 +33,7 @@ obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o
33obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o 33obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o
34obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o 34obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o
35 35
36obj-$(CONFIG_ISCSI_TCP) += iscsi_tcp.o 36obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o
37obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o 37obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o
38obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o 38obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o
39obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o 39obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
new file mode 100644
index 000000000000..274a1374ab64
--- /dev/null
+++ b/drivers/scsi/libiscsi.c
@@ -0,0 +1,1697 @@
1/*
2 * iSCSI lib functions
3 *
4 * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
5 * Copyright (C) 2004 - 2006 Mike Christie
6 * Copyright (C) 2004 - 2005 Dmitry Yusupov
7 * Copyright (C) 2004 - 2005 Alex Aizman
8 * maintained by open-iscsi@googlegroups.com
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 */
24#include <linux/types.h>
25#include <linux/mutex.h>
26#include <linux/kfifo.h>
27#include <linux/delay.h>
28#include <net/tcp.h>
29#include <scsi/scsi_cmnd.h>
30#include <scsi/scsi_device.h>
31#include <scsi/scsi_eh.h>
32#include <scsi/scsi_tcq.h>
33#include <scsi/scsi_host.h>
34#include <scsi/scsi.h>
35#include <scsi/iscsi_proto.h>
36#include <scsi/scsi_transport.h>
37#include <scsi/scsi_transport_iscsi.h>
38#include <scsi/libiscsi.h>
39
40struct iscsi_session *
41class_to_transport_session(struct iscsi_cls_session *cls_session)
42{
43 struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
44 return iscsi_hostdata(shost->hostdata);
45}
46EXPORT_SYMBOL_GPL(class_to_transport_session);
47
48#define INVALID_SN_DELTA 0xffff
49
50int
51iscsi_check_assign_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
52{
53 uint32_t max_cmdsn = be32_to_cpu(hdr->max_cmdsn);
54 uint32_t exp_cmdsn = be32_to_cpu(hdr->exp_cmdsn);
55
56 if (max_cmdsn < exp_cmdsn -1 &&
57 max_cmdsn > exp_cmdsn - INVALID_SN_DELTA)
58 return ISCSI_ERR_MAX_CMDSN;
59 if (max_cmdsn > session->max_cmdsn ||
60 max_cmdsn < session->max_cmdsn - INVALID_SN_DELTA)
61 session->max_cmdsn = max_cmdsn;
62 if (exp_cmdsn > session->exp_cmdsn ||
63 exp_cmdsn < session->exp_cmdsn - INVALID_SN_DELTA)
64 session->exp_cmdsn = exp_cmdsn;
65
66 return 0;
67}
68EXPORT_SYMBOL_GPL(iscsi_check_assign_cmdsn);
69
70void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask,
71 struct iscsi_data *hdr,
72 int transport_data_cnt)
73{
74 struct iscsi_conn *conn = ctask->conn;
75
76 memset(hdr, 0, sizeof(struct iscsi_data));
77 hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG);
78 hdr->datasn = cpu_to_be32(ctask->unsol_datasn);
79 ctask->unsol_datasn++;
80 hdr->opcode = ISCSI_OP_SCSI_DATA_OUT;
81 memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun));
82
83 hdr->itt = ctask->hdr->itt;
84 hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
85
86 hdr->offset = cpu_to_be32(ctask->total_length -
87 transport_data_cnt -
88 ctask->unsol_count);
89
90 if (ctask->unsol_count > conn->max_xmit_dlength) {
91 hton24(hdr->dlength, conn->max_xmit_dlength);
92 ctask->data_count = conn->max_xmit_dlength;
93 hdr->flags = 0;
94 } else {
95 hton24(hdr->dlength, ctask->unsol_count);
96 ctask->data_count = ctask->unsol_count;
97 hdr->flags = ISCSI_FLAG_CMD_FINAL;
98 }
99}
100EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu);
101
102/**
103 * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
104 * @ctask: iscsi cmd task
105 *
106 * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set
107 * fields like dlength or final based on how much data it sends
108 */
109static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
110{
111 struct iscsi_conn *conn = ctask->conn;
112 struct iscsi_session *session = conn->session;
113 struct iscsi_cmd *hdr = ctask->hdr;
114 struct scsi_cmnd *sc = ctask->sc;
115
116 hdr->opcode = ISCSI_OP_SCSI_CMD;
117 hdr->flags = ISCSI_ATTR_SIMPLE;
118 int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
119 hdr->itt = ctask->itt | (conn->id << ISCSI_CID_SHIFT) |
120 (session->age << ISCSI_AGE_SHIFT);
121 hdr->data_length = cpu_to_be32(sc->request_bufflen);
122 hdr->cmdsn = cpu_to_be32(session->cmdsn);
123 session->cmdsn++;
124 hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
125 memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
126 memset(&hdr->cdb[sc->cmd_len], 0, MAX_COMMAND_SIZE - sc->cmd_len);
127
128 if (sc->sc_data_direction == DMA_TO_DEVICE) {
129 hdr->flags |= ISCSI_FLAG_CMD_WRITE;
130 /*
131 * Write counters:
132 *
133 * imm_count bytes to be sent right after
134 * SCSI PDU Header
135 *
136 * unsol_count bytes(as Data-Out) to be sent
137 * without R2T ack right after
138 * immediate data
139 *
140 * r2t_data_count bytes to be sent via R2T ack's
141 *
142 * pad_count bytes to be sent as zero-padding
143 */
144 ctask->imm_count = 0;
145 ctask->unsol_count = 0;
146 ctask->unsol_datasn = 0;
147
148 if (session->imm_data_en) {
149 if (ctask->total_length >= session->first_burst)
150 ctask->imm_count = min(session->first_burst,
151 conn->max_xmit_dlength);
152 else
153 ctask->imm_count = min(ctask->total_length,
154 conn->max_xmit_dlength);
155 hton24(ctask->hdr->dlength, ctask->imm_count);
156 } else
157 zero_data(ctask->hdr->dlength);
158
159 if (!session->initial_r2t_en)
160 ctask->unsol_count = min(session->first_burst,
161 ctask->total_length) - ctask->imm_count;
162 if (!ctask->unsol_count)
163 /* No unsolicit Data-Out's */
164 ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL;
165 } else {
166 ctask->datasn = 0;
167 hdr->flags |= ISCSI_FLAG_CMD_FINAL;
168 zero_data(hdr->dlength);
169
170 if (sc->sc_data_direction == DMA_FROM_DEVICE)
171 hdr->flags |= ISCSI_FLAG_CMD_READ;
172 }
173
174 conn->scsicmd_pdus_cnt++;
175}
176EXPORT_SYMBOL_GPL(iscsi_prep_scsi_cmd_pdu);
177
178/**
179 * iscsi_complete_command - return command back to scsi-ml
180 * @session: iscsi session
181 * @ctask: iscsi cmd task
182 *
183 * Must be called with session lock.
184 * This function returns the scsi command to scsi-ml and returns
185 * the cmd task to the pool of available cmd tasks.
186 */
187static void iscsi_complete_command(struct iscsi_session *session,
188 struct iscsi_cmd_task *ctask)
189{
190 struct scsi_cmnd *sc = ctask->sc;
191
192 ctask->sc = NULL;
193 list_del_init(&ctask->running);
194 __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*));
195 sc->scsi_done(sc);
196}
197
198/**
199 * iscsi_cmd_rsp - SCSI Command Response processing
200 * @conn: iscsi connection
201 * @hdr: iscsi header
202 * @ctask: scsi command task
203 * @data: cmd data buffer
204 * @datalen: len of buffer
205 *
206 * iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and
207 * then completes the command and task.
208 **/
209static int iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
210 struct iscsi_cmd_task *ctask, char *data,
211 int datalen)
212{
213 int rc;
214 struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr;
215 struct iscsi_session *session = conn->session;
216 struct scsi_cmnd *sc = ctask->sc;
217
218 rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr);
219 if (rc) {
220 sc->result = DID_ERROR << 16;
221 goto out;
222 }
223
224 conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
225
226 sc->result = (DID_OK << 16) | rhdr->cmd_status;
227
228 if (rhdr->response != ISCSI_STATUS_CMD_COMPLETED) {
229 sc->result = DID_ERROR << 16;
230 goto out;
231 }
232
233 if (rhdr->cmd_status == SAM_STAT_CHECK_CONDITION) {
234 int senselen;
235
236 if (datalen < 2) {
237invalid_datalen:
238 printk(KERN_ERR "Got CHECK_CONDITION but invalid "
239 "data buffer size of %d\n", datalen);
240 sc->result = DID_BAD_TARGET << 16;
241 goto out;
242 }
243
244 senselen = (data[0] << 8) | data[1];
245 if (datalen < senselen)
246 goto invalid_datalen;
247
248 memcpy(sc->sense_buffer, data + 2,
249 min(senselen, SCSI_SENSE_BUFFERSIZE));
250 debug_scsi("copied %d bytes of sense\n",
251 min(senselen, SCSI_SENSE_BUFFERSIZE));
252 }
253
254 if (sc->sc_data_direction == DMA_TO_DEVICE)
255 goto out;
256
257 if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
258 int res_count = be32_to_cpu(rhdr->residual_count);
259
260 if (res_count > 0 && res_count <= sc->request_bufflen)
261 sc->resid = res_count;
262 else
263 sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
264 } else if (rhdr->flags & ISCSI_FLAG_CMD_BIDI_UNDERFLOW)
265 sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
266 else if (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW)
267 sc->resid = be32_to_cpu(rhdr->residual_count);
268
269out:
270 debug_scsi("done [sc %lx res %d itt 0x%x]\n",
271 (long)sc, sc->result, ctask->itt);
272 conn->scsirsp_pdus_cnt++;
273
274 iscsi_complete_command(conn->session, ctask);
275 return rc;
276}
277
278/**
279 * __iscsi_complete_pdu - complete pdu
280 * @conn: iscsi conn
281 * @hdr: iscsi header
282 * @data: data buffer
283 * @datalen: len of data buffer
284 *
285 * Completes pdu processing by freeing any resources allocated at
286 * queuecommand or send generic. session lock must be held and verify
287 * itt must have been called.
288 */
289int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
290 char *data, int datalen)
291{
292 struct iscsi_session *session = conn->session;
293 int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0;
294 struct iscsi_cmd_task *ctask;
295 struct iscsi_mgmt_task *mtask;
296 uint32_t itt;
297
298 if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG))
299 itt = hdr->itt & ISCSI_ITT_MASK;
300 else
301 itt = hdr->itt;
302
303 if (itt < session->cmds_max) {
304 ctask = session->cmds[itt];
305
306 debug_scsi("cmdrsp [op 0x%x cid %d itt 0x%x len %d]\n",
307 opcode, conn->id, ctask->itt, datalen);
308
309 switch(opcode) {
310 case ISCSI_OP_SCSI_CMD_RSP:
311 BUG_ON((void*)ctask != ctask->sc->SCp.ptr);
312 rc = iscsi_scsi_cmd_rsp(conn, hdr, ctask, data,
313 datalen);
314 break;
315 case ISCSI_OP_SCSI_DATA_IN:
316 BUG_ON((void*)ctask != ctask->sc->SCp.ptr);
317 if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
318 conn->scsirsp_pdus_cnt++;
319 iscsi_complete_command(session, ctask);
320 }
321 break;
322 case ISCSI_OP_R2T:
323 /* LLD handles this for now */
324 break;
325 default:
326 rc = ISCSI_ERR_BAD_OPCODE;
327 break;
328 }
329 } else if (itt >= ISCSI_MGMT_ITT_OFFSET &&
330 itt < ISCSI_MGMT_ITT_OFFSET + session->mgmtpool_max) {
331 mtask = session->mgmt_cmds[itt - ISCSI_MGMT_ITT_OFFSET];
332
333 debug_scsi("immrsp [op 0x%x cid %d itt 0x%x len %d]\n",
334 opcode, conn->id, mtask->itt, datalen);
335
336 switch(opcode) {
337 case ISCSI_OP_LOGIN_RSP:
338 case ISCSI_OP_TEXT_RSP:
339 case ISCSI_OP_LOGOUT_RSP:
340 rc = iscsi_check_assign_cmdsn(session,
341 (struct iscsi_nopin*)hdr);
342 if (rc)
343 break;
344
345 rc = iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen);
346 list_del(&mtask->running);
347 if (conn->login_mtask != mtask)
348 __kfifo_put(session->mgmtpool.queue,
349 (void*)&mtask, sizeof(void*));
350 break;
351 case ISCSI_OP_SCSI_TMFUNC_RSP:
352 rc = iscsi_check_assign_cmdsn(session,
353 (struct iscsi_nopin*)hdr);
354 if (rc)
355 break;
356
357 if (datalen) {
358 rc = ISCSI_ERR_PROTO;
359 break;
360 }
361 conn->tmfrsp_pdus_cnt++;
362 if (conn->tmabort_state == TMABORT_INITIAL) {
363 conn->tmabort_state =
364 ((struct iscsi_tm_rsp *)hdr)->
365 response == ISCSI_TMF_RSP_COMPLETE ?
366 TMABORT_SUCCESS:TMABORT_FAILED;
367 /* unblock eh_abort() */
368 wake_up(&conn->ehwait);
369 }
370 break;
371 case ISCSI_OP_NOOP_IN:
372 if (hdr->ttt != ISCSI_RESERVED_TAG) {
373 rc = ISCSI_ERR_PROTO;
374 break;
375 }
376 rc = iscsi_check_assign_cmdsn(session,
377 (struct iscsi_nopin*)hdr);
378 if (rc)
379 break;
380 conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
381
382 rc = iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen);
383 list_del(&mtask->running);
384 if (conn->login_mtask != mtask)
385 __kfifo_put(session->mgmtpool.queue,
386 (void*)&mtask, sizeof(void*));
387 break;
388 default:
389 rc = ISCSI_ERR_BAD_OPCODE;
390 break;
391 }
392 } else if (itt == ISCSI_RESERVED_TAG) {
393 switch(opcode) {
394 case ISCSI_OP_NOOP_IN:
395 if (!datalen) {
396 rc = iscsi_check_assign_cmdsn(session,
397 (struct iscsi_nopin*)hdr);
398 if (!rc && hdr->ttt != ISCSI_RESERVED_TAG)
399 rc = iscsi_recv_pdu(conn->cls_conn,
400 hdr, NULL, 0);
401 } else
402 rc = ISCSI_ERR_PROTO;
403 break;
404 case ISCSI_OP_REJECT:
405 /* we need sth like iscsi_reject_rsp()*/
406 case ISCSI_OP_ASYNC_EVENT:
407 /* we need sth like iscsi_async_event_rsp() */
408 rc = ISCSI_ERR_BAD_OPCODE;
409 break;
410 default:
411 rc = ISCSI_ERR_BAD_OPCODE;
412 break;
413 }
414 } else
415 rc = ISCSI_ERR_BAD_ITT;
416
417 return rc;
418}
419EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
420
421int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
422 char *data, int datalen)
423{
424 int rc;
425
426 spin_lock(&conn->session->lock);
427 rc = __iscsi_complete_pdu(conn, hdr, data, datalen);
428 spin_unlock(&conn->session->lock);
429 return rc;
430}
431EXPORT_SYMBOL_GPL(iscsi_complete_pdu);
432
433/* verify itt (itt encoding: age+cid+itt) */
434int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
435 uint32_t *ret_itt)
436{
437 struct iscsi_session *session = conn->session;
438 struct iscsi_cmd_task *ctask;
439 uint32_t itt;
440
441 if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) {
442 if ((hdr->itt & ISCSI_AGE_MASK) !=
443 (session->age << ISCSI_AGE_SHIFT)) {
444 printk(KERN_ERR "iscsi_tcp: received itt %x expected "
445 "session age (%x)\n", hdr->itt,
446 session->age & ISCSI_AGE_MASK);
447 return ISCSI_ERR_BAD_ITT;
448 }
449
450 if ((hdr->itt & ISCSI_CID_MASK) !=
451 (conn->id << ISCSI_CID_SHIFT)) {
452 printk(KERN_ERR "iscsi_tcp: received itt %x, expected "
453 "CID (%x)\n", hdr->itt, conn->id);
454 return ISCSI_ERR_BAD_ITT;
455 }
456 itt = hdr->itt & ISCSI_ITT_MASK;
457 } else
458 itt = hdr->itt;
459
460 if (itt < session->cmds_max) {
461 ctask = session->cmds[itt];
462
463 if (!ctask->sc) {
464 printk(KERN_INFO "iscsi_tcp: dropping ctask with "
465 "itt 0x%x\n", ctask->itt);
466 /* force drop */
467 return ISCSI_ERR_NO_SCSI_CMD;
468 }
469
470 if (ctask->sc->SCp.phase != session->age) {
471 printk(KERN_ERR "iscsi_tcp: ctask's session age %d, "
472 "expected %d\n", ctask->sc->SCp.phase,
473 session->age);
474 return ISCSI_ERR_SESSION_FAILED;
475 }
476 }
477
478 *ret_itt = itt;
479 return 0;
480}
481EXPORT_SYMBOL_GPL(iscsi_verify_itt);
482
483void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
484{
485 struct iscsi_session *session = conn->session;
486 unsigned long flags;
487
488 spin_lock_irqsave(&session->lock, flags);
489 if (session->conn_cnt == 1 || session->leadconn == conn)
490 session->state = ISCSI_STATE_FAILED;
491 spin_unlock_irqrestore(&session->lock, flags);
492 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
493 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
494 iscsi_conn_error(conn->cls_conn, err);
495}
496EXPORT_SYMBOL_GPL(iscsi_conn_failure);
497
498/**
499 * iscsi_data_xmit - xmit any command into the scheduled connection
500 * @conn: iscsi connection
501 *
502 * Notes:
503 * The function can return -EAGAIN in which case the caller must
504 * re-schedule it again later or recover. '0' return code means
505 * successful xmit.
506 **/
507static int iscsi_data_xmit(struct iscsi_conn *conn)
508{
509 struct iscsi_transport *tt;
510
511 if (unlikely(conn->suspend_tx)) {
512 debug_scsi("conn %d Tx suspended!\n", conn->id);
513 return 0;
514 }
515 tt = conn->session->tt;
516
517 /*
518 * Transmit in the following order:
519 *
520 * 1) un-finished xmit (ctask or mtask)
521 * 2) immediate control PDUs
522 * 3) write data
523 * 4) SCSI commands
524 * 5) non-immediate control PDUs
525 *
526 * No need to lock around __kfifo_get as long as
527 * there's one producer and one consumer.
528 */
529
530 BUG_ON(conn->ctask && conn->mtask);
531
532 if (conn->ctask) {
533 if (tt->xmit_cmd_task(conn, conn->ctask))
534 goto again;
535 /* done with this in-progress ctask */
536 conn->ctask = NULL;
537 }
538 if (conn->mtask) {
539 if (tt->xmit_mgmt_task(conn, conn->mtask))
540 goto again;
541 /* done with this in-progress mtask */
542 conn->mtask = NULL;
543 }
544
545 /* process immediate first */
546 if (unlikely(__kfifo_len(conn->immqueue))) {
547 while (__kfifo_get(conn->immqueue, (void*)&conn->mtask,
548 sizeof(void*))) {
549 list_add_tail(&conn->mtask->running,
550 &conn->mgmt_run_list);
551 if (tt->xmit_mgmt_task(conn, conn->mtask))
552 goto again;
553 }
554 /* done with this mtask */
555 conn->mtask = NULL;
556 }
557
558 /* process command queue */
559 while (__kfifo_get(conn->xmitqueue, (void*)&conn->ctask,
560 sizeof(void*))) {
561 /*
562 * iscsi tcp may readd the task to the xmitqueue to send
563 * write data
564 */
565 if (list_empty(&conn->ctask->running))
566 list_add_tail(&conn->ctask->running, &conn->run_list);
567 if (tt->xmit_cmd_task(conn, conn->ctask))
568 goto again;
569 }
570 /* done with this ctask */
571 conn->ctask = NULL;
572
573 /* process the rest control plane PDUs, if any */
574 if (unlikely(__kfifo_len(conn->mgmtqueue))) {
575 while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask,
576 sizeof(void*))) {
577 list_add_tail(&conn->mtask->running,
578 &conn->mgmt_run_list);
579 if (tt->xmit_mgmt_task(conn, conn->mtask))
580 goto again;
581 }
582 /* done with this mtask */
583 conn->mtask = NULL;
584 }
585
586 return 0;
587
588again:
589 if (unlikely(conn->suspend_tx))
590 return 0;
591
592 return -EAGAIN;
593}
594
595static void iscsi_xmitworker(void *data)
596{
597 struct iscsi_conn *conn = data;
598
599 /*
600 * serialize Xmit worker on a per-connection basis.
601 */
602 mutex_lock(&conn->xmitmutex);
603 if (iscsi_data_xmit(conn))
604 scsi_queue_work(conn->session->host, &conn->xmitwork);
605 mutex_unlock(&conn->xmitmutex);
606}
607
608enum {
609 FAILURE_BAD_HOST = 1,
610 FAILURE_SESSION_FAILED,
611 FAILURE_SESSION_FREED,
612 FAILURE_WINDOW_CLOSED,
613 FAILURE_SESSION_TERMINATE,
614 FAILURE_SESSION_RECOVERY_TIMEOUT,
615};
616
617int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
618{
619 struct Scsi_Host *host;
620 int reason = 0;
621 struct iscsi_session *session;
622 struct iscsi_conn *conn;
623 struct iscsi_cmd_task *ctask = NULL;
624
625 sc->scsi_done = done;
626 sc->result = 0;
627
628 host = sc->device->host;
629 session = iscsi_hostdata(host->hostdata);
630
631 spin_lock(&session->lock);
632
633 if (session->state != ISCSI_STATE_LOGGED_IN) {
634 if (session->recovery_failed) {
635 reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
636 goto fault;
637 } else if (session->state == ISCSI_STATE_FAILED) {
638 reason = FAILURE_SESSION_FAILED;
639 goto reject;
640 } else if (session->state == ISCSI_STATE_TERMINATE) {
641 reason = FAILURE_SESSION_TERMINATE;
642 goto fault;
643 }
644 reason = FAILURE_SESSION_FREED;
645 goto fault;
646 }
647
648 /*
649 * Check for iSCSI window and take care of CmdSN wrap-around
650 */
651 if ((int)(session->max_cmdsn - session->cmdsn) < 0) {
652 reason = FAILURE_WINDOW_CLOSED;
653 goto reject;
654 }
655
656 conn = session->leadconn;
657
658 __kfifo_get(session->cmdpool.queue, (void*)&ctask, sizeof(void*));
659 sc->SCp.phase = session->age;
660 sc->SCp.ptr = (char *)ctask;
661
662 ctask->mtask = NULL;
663 ctask->conn = conn;
664 ctask->sc = sc;
665 INIT_LIST_HEAD(&ctask->running);
666 ctask->total_length = sc->request_bufflen;
667 iscsi_prep_scsi_cmd_pdu(ctask);
668
669 session->tt->init_cmd_task(ctask);
670
671 __kfifo_put(conn->xmitqueue, (void*)&ctask, sizeof(void*));
672 debug_scsi(
673 "ctask enq [%s cid %d sc %lx itt 0x%x len %d cmdsn %d win %d]\n",
674 sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
675 conn->id, (long)sc, ctask->itt, sc->request_bufflen,
676 session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
677 spin_unlock(&session->lock);
678
679 scsi_queue_work(host, &conn->xmitwork);
680 return 0;
681
682reject:
683 spin_unlock(&session->lock);
684 debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason);
685 return SCSI_MLQUEUE_HOST_BUSY;
686
687fault:
688 spin_unlock(&session->lock);
689 printk(KERN_ERR "iscsi_tcp: cmd 0x%x is not queued (%d)\n",
690 sc->cmnd[0], reason);
691 sc->result = (DID_NO_CONNECT << 16);
692 sc->resid = sc->request_bufflen;
693 sc->scsi_done(sc);
694 return 0;
695}
696EXPORT_SYMBOL_GPL(iscsi_queuecommand);
697
698int iscsi_change_queue_depth(struct scsi_device *sdev, int depth)
699{
700 if (depth > ISCSI_MAX_CMD_PER_LUN)
701 depth = ISCSI_MAX_CMD_PER_LUN;
702 scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
703 return sdev->queue_depth;
704}
705EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
706
707static int
708iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
709 char *data, uint32_t data_size)
710{
711 struct iscsi_session *session = conn->session;
712 struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr;
713 struct iscsi_mgmt_task *mtask;
714
715 spin_lock_bh(&session->lock);
716 if (session->state == ISCSI_STATE_TERMINATE) {
717 spin_unlock_bh(&session->lock);
718 return -EPERM;
719 }
720 if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) ||
721 hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
722 /*
723 * Login and Text are sent serially, in
724 * request-followed-by-response sequence.
725 * Same mtask can be used. Same ITT must be used.
726 * Note that login_mtask is preallocated at conn_create().
727 */
728 mtask = conn->login_mtask;
729 else {
730 BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
731 BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
732
733 if (!__kfifo_get(session->mgmtpool.queue,
734 (void*)&mtask, sizeof(void*))) {
735 spin_unlock_bh(&session->lock);
736 return -ENOSPC;
737 }
738 }
739
740 /*
741 * pre-format CmdSN and ExpStatSN for outgoing PDU.
742 */
743 if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) {
744 hdr->itt = mtask->itt | (conn->id << ISCSI_CID_SHIFT) |
745 (session->age << ISCSI_AGE_SHIFT);
746 nop->cmdsn = cpu_to_be32(session->cmdsn);
747 if (conn->c_stage == ISCSI_CONN_STARTED &&
748 !(hdr->opcode & ISCSI_OP_IMMEDIATE))
749 session->cmdsn++;
750 } else
751 /* do not advance CmdSN */
752 nop->cmdsn = cpu_to_be32(session->cmdsn);
753
754 nop->exp_statsn = cpu_to_be32(conn->exp_statsn);
755
756 if (data_size) {
757 memcpy(mtask->data, data, data_size);
758 mtask->data_count = data_size;
759 } else
760 mtask->data_count = 0;
761
762 INIT_LIST_HEAD(&mtask->running);
763 memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr));
764 if (session->tt->init_mgmt_task)
765 session->tt->init_mgmt_task(conn, mtask, data, data_size);
766 spin_unlock_bh(&session->lock);
767
768 debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n",
769 hdr->opcode, hdr->itt, data_size);
770
771 /*
772 * since send_pdu() could be called at least from two contexts,
773 * we need to serialize __kfifo_put, so we don't have to take
774 * additional lock on fast data-path
775 */
776 if (hdr->opcode & ISCSI_OP_IMMEDIATE)
777 __kfifo_put(conn->immqueue, (void*)&mtask, sizeof(void*));
778 else
779 __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*));
780
781 scsi_queue_work(session->host, &conn->xmitwork);
782 return 0;
783}
784
785int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
786 char *data, uint32_t data_size)
787{
788 struct iscsi_conn *conn = cls_conn->dd_data;
789 int rc;
790
791 mutex_lock(&conn->xmitmutex);
792 rc = iscsi_conn_send_generic(conn, hdr, data, data_size);
793 mutex_unlock(&conn->xmitmutex);
794
795 return rc;
796}
797EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
798
799void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
800{
801 struct iscsi_session *session = class_to_transport_session(cls_session);
802 struct iscsi_conn *conn = session->leadconn;
803
804 spin_lock_bh(&session->lock);
805 if (session->state != ISCSI_STATE_LOGGED_IN) {
806 session->recovery_failed = 1;
807 if (conn)
808 wake_up(&conn->ehwait);
809 }
810 spin_unlock_bh(&session->lock);
811}
812EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout);
813
814int iscsi_eh_host_reset(struct scsi_cmnd *sc)
815{
816 struct Scsi_Host *host = sc->device->host;
817 struct iscsi_session *session = iscsi_hostdata(host->hostdata);
818 struct iscsi_conn *conn = session->leadconn;
819 int fail_session = 0;
820
821 spin_lock_bh(&session->lock);
822 if (session->state == ISCSI_STATE_TERMINATE) {
823failed:
824 debug_scsi("failing host reset: session terminated "
825 "[CID %d age %d]", conn->id, session->age);
826 spin_unlock_bh(&session->lock);
827 return FAILED;
828 }
829
830 if (sc->SCp.phase == session->age) {
831 debug_scsi("failing connection CID %d due to SCSI host reset",
832 conn->id);
833 fail_session = 1;
834 }
835 spin_unlock_bh(&session->lock);
836
837 /*
838 * we drop the lock here but the leadconn cannot be destoyed while
839 * we are in the scsi eh
840 */
841 if (fail_session) {
842 iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
843 /*
844 * if userspace cannot respond then we must kick this off
845 * here for it
846 */
847 iscsi_start_session_recovery(session, conn, STOP_CONN_RECOVER);
848 }
849
850 debug_scsi("iscsi_eh_host_reset wait for relogin\n");
851 wait_event_interruptible(conn->ehwait,
852 session->state == ISCSI_STATE_TERMINATE ||
853 session->state == ISCSI_STATE_LOGGED_IN ||
854 session->recovery_failed);
855 if (signal_pending(current))
856 flush_signals(current);
857
858 spin_lock_bh(&session->lock);
859 if (session->state == ISCSI_STATE_LOGGED_IN)
860 printk(KERN_INFO "host reset succeeded\n");
861 else
862 goto failed;
863 spin_unlock_bh(&session->lock);
864
865 return SUCCESS;
866}
867EXPORT_SYMBOL_GPL(iscsi_eh_host_reset);
868
869static void iscsi_tmabort_timedout(unsigned long data)
870{
871 struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)data;
872 struct iscsi_conn *conn = ctask->conn;
873 struct iscsi_session *session = conn->session;
874
875 spin_lock(&session->lock);
876 if (conn->tmabort_state == TMABORT_INITIAL) {
877 conn->tmabort_state = TMABORT_TIMEDOUT;
878 debug_scsi("tmabort timedout [sc %p itt 0x%x]\n",
879 ctask->sc, ctask->itt);
880 /* unblock eh_abort() */
881 wake_up(&conn->ehwait);
882 }
883 spin_unlock(&session->lock);
884}
885
886/* must be called with the mutex lock */
887static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
888 struct iscsi_cmd_task *ctask)
889{
890 struct iscsi_conn *conn = ctask->conn;
891 struct iscsi_session *session = conn->session;
892 struct iscsi_tm *hdr = &conn->tmhdr;
893 int rc;
894
895 /*
896 * ctask timed out but session is OK requests must be serialized.
897 */
898 memset(hdr, 0, sizeof(struct iscsi_tm));
899 hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
900 hdr->flags = ISCSI_TM_FUNC_ABORT_TASK;
901 hdr->flags |= ISCSI_FLAG_CMD_FINAL;
902 memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun));
903 hdr->rtt = ctask->hdr->itt;
904 hdr->refcmdsn = ctask->hdr->cmdsn;
905
906 rc = iscsi_conn_send_generic(conn, (struct iscsi_hdr *)hdr,
907 NULL, 0);
908 if (rc) {
909 iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
910 debug_scsi("abort sent failure [itt 0x%x] %d", ctask->itt, rc);
911 return rc;
912 }
913
914 debug_scsi("abort sent [itt 0x%x]\n", ctask->itt);
915
916 spin_lock_bh(&session->lock);
917 ctask->mtask = (struct iscsi_mgmt_task *)
918 session->mgmt_cmds[(hdr->itt & ISCSI_ITT_MASK) -
919 ISCSI_MGMT_ITT_OFFSET];
920
921 if (conn->tmabort_state == TMABORT_INITIAL) {
922 conn->tmfcmd_pdus_cnt++;
923 conn->tmabort_timer.expires = 10*HZ + jiffies;
924 conn->tmabort_timer.function = iscsi_tmabort_timedout;
925 conn->tmabort_timer.data = (unsigned long)ctask;
926 add_timer(&conn->tmabort_timer);
927 debug_scsi("abort set timeout [itt 0x%x]", ctask->itt);
928 }
929 spin_unlock_bh(&session->lock);
930 mutex_unlock(&conn->xmitmutex);
931
932 /*
933 * block eh thread until:
934 *
935 * 1) abort response
936 * 2) abort timeout
937 * 3) session is terminated or restarted or userspace has
938 * given up on recovery
939 */
940 wait_event_interruptible(conn->ehwait,
941 sc->SCp.phase != session->age ||
942 session->state != ISCSI_STATE_LOGGED_IN ||
943 conn->tmabort_state != TMABORT_INITIAL ||
944 session->recovery_failed);
945 if (signal_pending(current))
946 flush_signals(current);
947 del_timer_sync(&conn->tmabort_timer);
948
949 mutex_lock(&conn->xmitmutex);
950 return 0;
951}
952
953/*
954 * xmit mutex and session lock must be held
955 */
956#define iscsi_remove_task(tasktype) \
957static struct iscsi_##tasktype * \
958iscsi_remove_##tasktype(struct kfifo *fifo, uint32_t itt) \
959{ \
960 int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*); \
961 struct iscsi_##tasktype *task; \
962 \
963 debug_scsi("searching %d tasks\n", nr_tasks); \
964 \
965 for (i = 0; i < nr_tasks; i++) { \
966 __kfifo_get(fifo, (void*)&task, sizeof(void*)); \
967 debug_scsi("check task %u\n", task->itt); \
968 \
969 if (task->itt == itt) { \
970 debug_scsi("matched task\n"); \
971 break; \
972 } \
973 \
974 __kfifo_put(fifo, (void*)&task, sizeof(void*)); \
975 } \
976 return NULL; \
977}
978
979iscsi_remove_task(mgmt_task);
980iscsi_remove_task(cmd_task);
981
982static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask)
983{
984 struct iscsi_conn *conn = ctask->conn;
985 struct iscsi_session *session = conn->session;
986
987 if (!ctask->mtask)
988 return -EINVAL;
989
990 if (!iscsi_remove_mgmt_task(conn->immqueue, ctask->mtask->itt))
991 list_del(&ctask->mtask->running);
992 __kfifo_put(session->mgmtpool.queue, (void*)&ctask->mtask,
993 sizeof(void*));
994 ctask->mtask = NULL;
995 return 0;
996}
997
998/*
999 * session lock and xmitmutex must be held
1000 */
1001static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
1002 int err)
1003{
1004 struct scsi_cmnd *sc;
1005
1006 conn->session->tt->cleanup_cmd_task(conn, ctask);
1007 iscsi_ctask_mtask_cleanup(ctask);
1008
1009 sc = ctask->sc;
1010 if (!sc)
1011 return;
1012 sc->result = err;
1013 sc->resid = sc->request_bufflen;
1014 iscsi_complete_command(conn->session, ctask);
1015}
1016
1017int iscsi_eh_abort(struct scsi_cmnd *sc)
1018{
1019 struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
1020 struct iscsi_conn *conn = ctask->conn;
1021 struct iscsi_session *session = conn->session;
1022 struct iscsi_cmd_task *pending_ctask;
1023 int rc;
1024
1025 conn->eh_abort_cnt++;
1026 debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
1027
1028 mutex_lock(&conn->xmitmutex);
1029 spin_lock_bh(&session->lock);
1030
1031 /*
1032 * If we are not logged in or we have started a new session
1033 * then let the host reset code handle this
1034 */
1035 if (session->state != ISCSI_STATE_LOGGED_IN ||
1036 sc->SCp.phase != session->age)
1037 goto failed;
1038
1039 /* ctask completed before time out */
1040 if (!ctask->sc)
1041 goto success;
1042
1043 /* what should we do here ? */
1044 if (conn->ctask == ctask) {
1045 printk(KERN_INFO "sc %p itt 0x%x partially sent. Failing "
1046 "abort\n", sc, ctask->itt);
1047 goto failed;
1048 }
1049
1050 /* check for the easy pending cmd abort */
1051 pending_ctask = iscsi_remove_cmd_task(conn->xmitqueue, ctask->itt);
1052 if (pending_ctask) {
1053 /* iscsi_tcp queues write transfers on the xmitqueue */
1054 if (list_empty(&pending_ctask->running)) {
1055 debug_scsi("found pending task\n");
1056 goto success;
1057 } else
1058 __kfifo_put(conn->xmitqueue, (void*)&pending_ctask,
1059 sizeof(void*));
1060 }
1061
1062 conn->tmabort_state = TMABORT_INITIAL;
1063
1064 spin_unlock_bh(&session->lock);
1065 rc = iscsi_exec_abort_task(sc, ctask);
1066 spin_lock_bh(&session->lock);
1067
1068 iscsi_ctask_mtask_cleanup(ctask);
1069 if (rc || sc->SCp.phase != session->age ||
1070 session->state != ISCSI_STATE_LOGGED_IN)
1071 goto failed;
1072
1073 /* ctask completed before tmf abort response */
1074 if (!ctask->sc) {
1075 debug_scsi("sc completed while abort in progress\n");
1076 goto success;
1077 }
1078
1079 if (conn->tmabort_state != TMABORT_SUCCESS) {
1080 spin_unlock_bh(&session->lock);
1081 iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
1082 spin_lock_bh(&session->lock);
1083 goto failed;
1084 }
1085
1086success:
1087 debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
1088 spin_unlock_bh(&session->lock);
1089
1090 /*
1091 * clean up task if aborted. we have the xmitmutex so grab
1092 * the recv lock as a writer
1093 */
1094 write_lock_bh(conn->recv_lock);
1095 spin_lock(&session->lock);
1096 fail_command(conn, ctask, DID_ABORT << 16);
1097 spin_unlock(&session->lock);
1098 write_unlock_bh(conn->recv_lock);
1099
1100 mutex_unlock(&conn->xmitmutex);
1101 return SUCCESS;
1102
1103failed:
1104 spin_unlock_bh(&session->lock);
1105 mutex_unlock(&conn->xmitmutex);
1106
1107 debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
1108 return FAILED;
1109}
1110EXPORT_SYMBOL_GPL(iscsi_eh_abort);
1111
1112int
1113iscsi_pool_init(struct iscsi_queue *q, int max, void ***items, int item_size)
1114{
1115 int i;
1116
1117 *items = kmalloc(max * sizeof(void*), GFP_KERNEL);
1118 if (*items == NULL)
1119 return -ENOMEM;
1120
1121 q->max = max;
1122 q->pool = kmalloc(max * sizeof(void*), GFP_KERNEL);
1123 if (q->pool == NULL) {
1124 kfree(*items);
1125 return -ENOMEM;
1126 }
1127
1128 q->queue = kfifo_init((void*)q->pool, max * sizeof(void*),
1129 GFP_KERNEL, NULL);
1130 if (q->queue == ERR_PTR(-ENOMEM)) {
1131 kfree(q->pool);
1132 kfree(*items);
1133 return -ENOMEM;
1134 }
1135
1136 for (i = 0; i < max; i++) {
1137 q->pool[i] = kmalloc(item_size, GFP_KERNEL);
1138 if (q->pool[i] == NULL) {
1139 int j;
1140
1141 for (j = 0; j < i; j++)
1142 kfree(q->pool[j]);
1143
1144 kfifo_free(q->queue);
1145 kfree(q->pool);
1146 kfree(*items);
1147 return -ENOMEM;
1148 }
1149 memset(q->pool[i], 0, item_size);
1150 (*items)[i] = q->pool[i];
1151 __kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*));
1152 }
1153 return 0;
1154}
1155EXPORT_SYMBOL_GPL(iscsi_pool_init);
1156
1157void iscsi_pool_free(struct iscsi_queue *q, void **items)
1158{
1159 int i;
1160
1161 for (i = 0; i < q->max; i++)
1162 kfree(items[i]);
1163 kfree(q->pool);
1164 kfree(items);
1165}
1166EXPORT_SYMBOL_GPL(iscsi_pool_free);
1167
1168/*
1169 * iSCSI Session's hostdata organization:
1170 *
1171 * *------------------* <== hostdata_session(host->hostdata)
1172 * | ptr to class sess|
1173 * |------------------| <== iscsi_hostdata(host->hostdata)
1174 * | iscsi_session |
1175 * *------------------*
1176 */
1177
1178#define hostdata_privsize(_sz) (sizeof(unsigned long) + _sz + \
1179 _sz % sizeof(unsigned long))
1180
1181#define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata))
1182
1183/**
1184 * iscsi_session_setup - create iscsi cls session and host and session
1185 * @scsit: scsi transport template
1186 * @iscsit: iscsi transport template
1187 * @initial_cmdsn: initial CmdSN
1188 * @hostno: host no allocated
1189 *
1190 * This can be used by software iscsi_transports that allocate
1191 * a session per scsi host.
1192 **/
1193struct iscsi_cls_session *
1194iscsi_session_setup(struct iscsi_transport *iscsit,
1195 struct scsi_transport_template *scsit,
1196 int cmd_task_size, int mgmt_task_size,
1197 uint32_t initial_cmdsn, uint32_t *hostno)
1198{
1199 struct Scsi_Host *shost;
1200 struct iscsi_session *session;
1201 struct iscsi_cls_session *cls_session;
1202 int cmd_i;
1203
1204 shost = scsi_host_alloc(iscsit->host_template,
1205 hostdata_privsize(sizeof(*session)));
1206 if (!shost)
1207 return NULL;
1208
1209 shost->max_id = 1;
1210 shost->max_channel = 0;
1211 shost->max_lun = iscsit->max_lun;
1212 shost->max_cmd_len = iscsit->max_cmd_len;
1213 shost->transportt = scsit;
1214 shost->transportt->create_work_queue = 1;
1215 *hostno = shost->host_no;
1216
1217 session = iscsi_hostdata(shost->hostdata);
1218 memset(session, 0, sizeof(struct iscsi_session));
1219 session->host = shost;
1220 session->state = ISCSI_STATE_FREE;
1221 session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX;
1222 session->cmds_max = ISCSI_XMIT_CMDS_MAX;
1223 session->cmdsn = initial_cmdsn;
1224 session->exp_cmdsn = initial_cmdsn + 1;
1225 session->max_cmdsn = initial_cmdsn + 1;
1226 session->max_r2t = 1;
1227 session->tt = iscsit;
1228
1229 /* initialize SCSI PDU commands pool */
1230 if (iscsi_pool_init(&session->cmdpool, session->cmds_max,
1231 (void***)&session->cmds,
1232 cmd_task_size + sizeof(struct iscsi_cmd_task)))
1233 goto cmdpool_alloc_fail;
1234
1235 /* pre-format cmds pool with ITT */
1236 for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
1237 struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
1238
1239 if (cmd_task_size)
1240 ctask->dd_data = &ctask[1];
1241 ctask->itt = cmd_i;
1242 }
1243
1244 spin_lock_init(&session->lock);
1245 INIT_LIST_HEAD(&session->connections);
1246
1247 /* initialize immediate command pool */
1248 if (iscsi_pool_init(&session->mgmtpool, session->mgmtpool_max,
1249 (void***)&session->mgmt_cmds,
1250 mgmt_task_size + sizeof(struct iscsi_mgmt_task)))
1251 goto mgmtpool_alloc_fail;
1252
1253
1254 /* pre-format immediate cmds pool with ITT */
1255 for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) {
1256 struct iscsi_mgmt_task *mtask = session->mgmt_cmds[cmd_i];
1257
1258 if (mgmt_task_size)
1259 mtask->dd_data = &mtask[1];
1260 mtask->itt = ISCSI_MGMT_ITT_OFFSET + cmd_i;
1261 mtask->data = kmalloc(DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH,
1262 GFP_KERNEL);
1263 if (!mtask->data) {
1264 int j;
1265
1266 for (j = 0; j < cmd_i; j++)
1267 kfree(session->mgmt_cmds[j]->data);
1268 goto immdata_alloc_fail;
1269 }
1270 }
1271
1272 if (scsi_add_host(shost, NULL))
1273 goto add_host_fail;
1274
1275 cls_session = iscsi_create_session(shost, iscsit, 0);
1276 if (!cls_session)
1277 goto cls_session_fail;
1278 *(unsigned long*)shost->hostdata = (unsigned long)cls_session;
1279
1280 return cls_session;
1281
1282cls_session_fail:
1283 scsi_remove_host(shost);
1284add_host_fail:
1285 for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++)
1286 kfree(session->mgmt_cmds[cmd_i]->data);
1287immdata_alloc_fail:
1288 iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
1289mgmtpool_alloc_fail:
1290 iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
1291cmdpool_alloc_fail:
1292 scsi_host_put(shost);
1293 return NULL;
1294}
1295EXPORT_SYMBOL_GPL(iscsi_session_setup);
1296
1297/**
1298 * iscsi_session_teardown - destroy session, host, and cls_session
1299 * shost: scsi host
1300 *
1301 * This can be used by software iscsi_transports that allocate
1302 * a session per scsi host.
1303 **/
1304void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
1305{
1306 struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
1307 struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
1308 int cmd_i;
1309
1310 scsi_remove_host(shost);
1311
1312 for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++)
1313 kfree(session->mgmt_cmds[cmd_i]->data);
1314
1315 iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
1316 iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
1317
1318 iscsi_destroy_session(cls_session);
1319 scsi_host_put(shost);
1320}
1321EXPORT_SYMBOL_GPL(iscsi_session_teardown);
1322
1323/**
1324 * iscsi_conn_setup - create iscsi_cls_conn and iscsi_conn
1325 * @cls_session: iscsi_cls_session
1326 * @conn_idx: cid
1327 **/
1328struct iscsi_cls_conn *
1329iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
1330{
1331 struct iscsi_session *session = class_to_transport_session(cls_session);
1332 struct iscsi_conn *conn;
1333 struct iscsi_cls_conn *cls_conn;
1334
1335 cls_conn = iscsi_create_conn(cls_session, conn_idx);
1336 if (!cls_conn)
1337 return NULL;
1338 conn = cls_conn->dd_data;
1339 memset(conn, 0, sizeof(*conn));
1340
1341 conn->session = session;
1342 conn->cls_conn = cls_conn;
1343 conn->c_stage = ISCSI_CONN_INITIAL_STAGE;
1344 conn->id = conn_idx;
1345 conn->exp_statsn = 0;
1346 conn->tmabort_state = TMABORT_INITIAL;
1347 INIT_LIST_HEAD(&conn->run_list);
1348 INIT_LIST_HEAD(&conn->mgmt_run_list);
1349
1350 /* initialize general xmit PDU commands queue */
1351 conn->xmitqueue = kfifo_alloc(session->cmds_max * sizeof(void*),
1352 GFP_KERNEL, NULL);
1353 if (conn->xmitqueue == ERR_PTR(-ENOMEM))
1354 goto xmitqueue_alloc_fail;
1355
1356 /* initialize general immediate & non-immediate PDU commands queue */
1357 conn->immqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*),
1358 GFP_KERNEL, NULL);
1359 if (conn->immqueue == ERR_PTR(-ENOMEM))
1360 goto immqueue_alloc_fail;
1361
1362 conn->mgmtqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*),
1363 GFP_KERNEL, NULL);
1364 if (conn->mgmtqueue == ERR_PTR(-ENOMEM))
1365 goto mgmtqueue_alloc_fail;
1366
1367 INIT_WORK(&conn->xmitwork, iscsi_xmitworker, conn);
1368
1369 /* allocate login_mtask used for the login/text sequences */
1370 spin_lock_bh(&session->lock);
1371 if (!__kfifo_get(session->mgmtpool.queue,
1372 (void*)&conn->login_mtask,
1373 sizeof(void*))) {
1374 spin_unlock_bh(&session->lock);
1375 goto login_mtask_alloc_fail;
1376 }
1377 spin_unlock_bh(&session->lock);
1378
1379 init_timer(&conn->tmabort_timer);
1380 mutex_init(&conn->xmitmutex);
1381 init_waitqueue_head(&conn->ehwait);
1382
1383 return cls_conn;
1384
1385login_mtask_alloc_fail:
1386 kfifo_free(conn->mgmtqueue);
1387mgmtqueue_alloc_fail:
1388 kfifo_free(conn->immqueue);
1389immqueue_alloc_fail:
1390 kfifo_free(conn->xmitqueue);
1391xmitqueue_alloc_fail:
1392 iscsi_destroy_conn(cls_conn);
1393 return NULL;
1394}
1395EXPORT_SYMBOL_GPL(iscsi_conn_setup);
1396
1397/**
1398 * iscsi_conn_teardown - teardown iscsi connection
1399 * cls_conn: iscsi class connection
1400 *
1401 * TODO: we may need to make this into a two step process
1402 * like scsi-mls remove + put host
1403 */
1404void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
1405{
1406 struct iscsi_conn *conn = cls_conn->dd_data;
1407 struct iscsi_session *session = conn->session;
1408 unsigned long flags;
1409
1410 mutex_lock(&conn->xmitmutex);
1411 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
1412 if (conn->c_stage == ISCSI_CONN_INITIAL_STAGE) {
1413 if (session->tt->suspend_conn_recv)
1414 session->tt->suspend_conn_recv(conn);
1415
1416 session->tt->terminate_conn(conn);
1417 }
1418
1419 spin_lock_bh(&session->lock);
1420 conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
1421 if (session->leadconn == conn) {
1422 /*
1423 * leading connection? then give up on recovery.
1424 */
1425 session->state = ISCSI_STATE_TERMINATE;
1426 wake_up(&conn->ehwait);
1427 }
1428 spin_unlock_bh(&session->lock);
1429
1430 mutex_unlock(&conn->xmitmutex);
1431
1432 /*
1433 * Block until all in-progress commands for this connection
1434 * time out or fail.
1435 */
1436 for (;;) {
1437 spin_lock_irqsave(session->host->host_lock, flags);
1438 if (!session->host->host_busy) { /* OK for ERL == 0 */
1439 spin_unlock_irqrestore(session->host->host_lock, flags);
1440 break;
1441 }
1442 spin_unlock_irqrestore(session->host->host_lock, flags);
1443 msleep_interruptible(500);
1444 printk("conn_destroy(): host_busy %d host_failed %d\n",
1445 session->host->host_busy, session->host->host_failed);
1446 /*
1447 * force eh_abort() to unblock
1448 */
1449 wake_up(&conn->ehwait);
1450 }
1451
1452 spin_lock_bh(&session->lock);
1453 __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask,
1454 sizeof(void*));
1455 list_del(&conn->item);
1456 if (list_empty(&session->connections))
1457 session->leadconn = NULL;
1458 if (session->leadconn && session->leadconn == conn)
1459 session->leadconn = container_of(session->connections.next,
1460 struct iscsi_conn, item);
1461
1462 if (session->leadconn == NULL)
1463 /* no connections exits.. reset sequencing */
1464 session->cmdsn = session->max_cmdsn = session->exp_cmdsn = 1;
1465 spin_unlock_bh(&session->lock);
1466
1467 kfifo_free(conn->xmitqueue);
1468 kfifo_free(conn->immqueue);
1469 kfifo_free(conn->mgmtqueue);
1470
1471 iscsi_destroy_conn(cls_conn);
1472}
1473EXPORT_SYMBOL_GPL(iscsi_conn_teardown);
1474
1475int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
1476{
1477 struct iscsi_conn *conn = cls_conn->dd_data;
1478 struct iscsi_session *session = conn->session;
1479
1480 if (session == NULL) {
1481 printk(KERN_ERR "iscsi: can't start unbound connection\n");
1482 return -EPERM;
1483 }
1484
1485 spin_lock_bh(&session->lock);
1486 conn->c_stage = ISCSI_CONN_STARTED;
1487 session->state = ISCSI_STATE_LOGGED_IN;
1488
1489 switch(conn->stop_stage) {
1490 case STOP_CONN_RECOVER:
1491 /*
1492 * unblock eh_abort() if it is blocked. re-try all
1493 * commands after successful recovery
1494 */
1495 session->conn_cnt++;
1496 conn->stop_stage = 0;
1497 conn->tmabort_state = TMABORT_INITIAL;
1498 session->age++;
1499 session->recovery_failed = 0;
1500 spin_unlock_bh(&session->lock);
1501
1502 iscsi_unblock_session(session_to_cls(session));
1503 wake_up(&conn->ehwait);
1504 return 0;
1505 case STOP_CONN_TERM:
1506 session->conn_cnt++;
1507 conn->stop_stage = 0;
1508 break;
1509 case STOP_CONN_SUSPEND:
1510 conn->stop_stage = 0;
1511 clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
1512 clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
1513 break;
1514 default:
1515 break;
1516 }
1517 spin_unlock_bh(&session->lock);
1518
1519 return 0;
1520}
1521EXPORT_SYMBOL_GPL(iscsi_conn_start);
1522
1523static void
1524flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn)
1525{
1526 struct iscsi_mgmt_task *mtask, *tmp;
1527
1528 /* handle pending */
1529 while (__kfifo_get(conn->immqueue, (void*)&mtask, sizeof(void*)) ||
1530 __kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) {
1531 if (mtask == conn->login_mtask)
1532 continue;
1533 debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt);
1534 __kfifo_put(session->mgmtpool.queue, (void*)&mtask,
1535 sizeof(void*));
1536 }
1537
1538 /* handle running */
1539 list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) {
1540 debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt);
1541 if (mtask == conn->login_mtask)
1542 continue;
1543 list_del(&mtask->running);
1544 __kfifo_put(session->mgmtpool.queue, (void*)&conn->mtask,
1545 sizeof(void*));
1546 }
1547
1548 conn->mtask = NULL;
1549}
1550
1551/* Fail commands. Mutex and session lock held and recv side suspended */
1552static void fail_all_commands(struct iscsi_conn *conn)
1553{
1554 struct iscsi_cmd_task *ctask, *tmp;
1555
1556 /* flush pending */
1557 while (__kfifo_get(conn->xmitqueue, (void*)&ctask, sizeof(void*))) {
1558 debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc,
1559 ctask->itt);
1560 fail_command(conn, ctask, DID_BUS_BUSY << 16);
1561 }
1562
1563 /* fail all other running */
1564 list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) {
1565 debug_scsi("failing in progress sc %p itt 0x%x\n",
1566 ctask->sc, ctask->itt);
1567 fail_command(conn, ctask, DID_BUS_BUSY << 16);
1568 }
1569
1570 conn->ctask = NULL;
1571}
1572
1573void iscsi_start_session_recovery(struct iscsi_session *session,
1574 struct iscsi_conn *conn, int flag)
1575{
1576 spin_lock_bh(&session->lock);
1577 if (conn->stop_stage == STOP_CONN_RECOVER ||
1578 conn->stop_stage == STOP_CONN_TERM) {
1579 spin_unlock_bh(&session->lock);
1580 return;
1581 }
1582 conn->stop_stage = flag;
1583 spin_unlock_bh(&session->lock);
1584
1585 if (session->tt->suspend_conn_recv)
1586 session->tt->suspend_conn_recv(conn);
1587
1588 mutex_lock(&conn->xmitmutex);
1589 spin_lock_bh(&session->lock);
1590 conn->c_stage = ISCSI_CONN_STOPPED;
1591 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
1592
1593 session->conn_cnt--;
1594 if (session->conn_cnt == 0 || session->leadconn == conn)
1595 session->state = ISCSI_STATE_FAILED;
1596
1597 spin_unlock_bh(&session->lock);
1598
1599 session->tt->terminate_conn(conn);
1600 /*
1601 * flush queues.
1602 */
1603 spin_lock_bh(&session->lock);
1604 fail_all_commands(conn);
1605 flush_control_queues(session, conn);
1606 spin_unlock_bh(&session->lock);
1607
1608 /*
1609 * for connection level recovery we should not calculate
1610 * header digest. conn->hdr_size used for optimization
1611 * in hdr_extract() and will be re-negotiated at
1612 * set_param() time.
1613 */
1614 if (flag == STOP_CONN_RECOVER) {
1615 conn->hdrdgst_en = 0;
1616 conn->datadgst_en = 0;
1617
1618 if (session->state == ISCSI_STATE_FAILED)
1619 iscsi_block_session(session_to_cls(session));
1620 }
1621 mutex_unlock(&conn->xmitmutex);
1622}
1623EXPORT_SYMBOL_GPL(iscsi_start_session_recovery);
1624
1625void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
1626{
1627 struct iscsi_conn *conn = cls_conn->dd_data;
1628 struct iscsi_session *session = conn->session;
1629
1630 switch (flag) {
1631 case STOP_CONN_RECOVER:
1632 case STOP_CONN_TERM:
1633 iscsi_start_session_recovery(session, conn, flag);
1634 return;
1635 case STOP_CONN_SUSPEND:
1636 if (session->tt->suspend_conn_recv)
1637 session->tt->suspend_conn_recv(conn);
1638
1639 mutex_lock(&conn->xmitmutex);
1640 spin_lock_bh(&session->lock);
1641
1642 conn->stop_stage = flag;
1643 conn->c_stage = ISCSI_CONN_STOPPED;
1644 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
1645
1646 spin_unlock_bh(&session->lock);
1647 mutex_unlock(&conn->xmitmutex);
1648 break;
1649 default:
1650 printk(KERN_ERR "invalid stop flag %d\n", flag);
1651 }
1652}
1653EXPORT_SYMBOL_GPL(iscsi_conn_stop);
1654
1655int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
1656 struct iscsi_cls_conn *cls_conn, int is_leading)
1657{
1658 struct iscsi_session *session = class_to_transport_session(cls_session);
1659 struct iscsi_conn *tmp = ERR_PTR(-EEXIST), *conn = cls_conn->dd_data;
1660
1661 /* lookup for existing connection */
1662 spin_lock_bh(&session->lock);
1663 list_for_each_entry(tmp, &session->connections, item) {
1664 if (tmp == conn) {
1665 if (conn->c_stage != ISCSI_CONN_STOPPED ||
1666 conn->stop_stage == STOP_CONN_TERM) {
1667 printk(KERN_ERR "iscsi_tcp: can't bind "
1668 "non-stopped connection (%d:%d)\n",
1669 conn->c_stage, conn->stop_stage);
1670 spin_unlock_bh(&session->lock);
1671 return -EIO;
1672 }
1673 break;
1674 }
1675 }
1676 if (tmp != conn) {
1677 /* bind new iSCSI connection to session */
1678 conn->session = session;
1679 list_add(&conn->item, &session->connections);
1680 }
1681 spin_unlock_bh(&session->lock);
1682
1683 if (is_leading)
1684 session->leadconn = conn;
1685
1686 /*
1687 * Unblock xmitworker(), Login Phase will pass through.
1688 */
1689 clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
1690 clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
1691 return 0;
1692}
1693EXPORT_SYMBOL_GPL(iscsi_conn_bind);
1694
1695MODULE_AUTHOR("Mike Christie");
1696MODULE_DESCRIPTION("iSCSI library functions");
1697MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index e2b67e34d92e..bc9071d2d212 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -472,106 +472,6 @@ int iscsi_destroy_conn(struct iscsi_cls_conn *conn)
472EXPORT_SYMBOL_GPL(iscsi_destroy_conn); 472EXPORT_SYMBOL_GPL(iscsi_destroy_conn);
473 473
474/* 474/*
475 * These functions are used only by software iscsi_transports
476 * which do not allocate and more their scsi_hosts since this
477 * is initiated from userspace.
478 */
479
480/*
481 * iSCSI Session's hostdata organization:
482 *
483 * *------------------* <== hostdata_session(host->hostdata)
484 * | ptr to class sess|
485 * |------------------| <== iscsi_hostdata(host->hostdata)
486 * | transport's data |
487 * *------------------*
488 */
489
490#define hostdata_privsize(_t) (sizeof(unsigned long) + _t->hostdata_size + \
491 _t->hostdata_size % sizeof(unsigned long))
492
493#define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata))
494
495/**
496 * iscsi_transport_create_session - create iscsi cls session and host
497 * scsit: scsi transport template
498 * transport: iscsi transport template
499 *
500 * This can be used by software iscsi_transports that allocate
501 * a session per scsi host.
502 **/
503struct Scsi_Host *
504iscsi_transport_create_session(struct scsi_transport_template *scsit,
505 struct iscsi_transport *transport)
506{
507 struct iscsi_cls_session *session;
508 struct Scsi_Host *shost;
509 unsigned long flags;
510
511 shost = scsi_host_alloc(transport->host_template,
512 hostdata_privsize(transport));
513 if (!shost) {
514 printk(KERN_ERR "iscsi: can not allocate SCSI host for "
515 "session\n");
516 return NULL;
517 }
518
519 shost->max_id = 1;
520 shost->max_channel = 0;
521 shost->max_lun = transport->max_lun;
522 shost->max_cmd_len = transport->max_cmd_len;
523 shost->transportt = scsit;
524 shost->transportt->create_work_queue = 1;
525
526 if (scsi_add_host(shost, NULL))
527 goto free_host;
528
529 session = iscsi_create_session(shost, transport, 0);
530 if (!session)
531 goto remove_host;
532
533 *(unsigned long*)shost->hostdata = (unsigned long)session;
534 spin_lock_irqsave(&sesslock, flags);
535 list_add(&session->sess_list, &sesslist);
536 spin_unlock_irqrestore(&sesslock, flags);
537 return shost;
538
539remove_host:
540 scsi_remove_host(shost);
541free_host:
542 scsi_host_put(shost);
543 return NULL;
544}
545
546EXPORT_SYMBOL_GPL(iscsi_transport_create_session);
547
548/**
549 * iscsi_transport_destroy_session - destroy session and scsi host
550 * shost: scsi host
551 *
552 * This can be used by software iscsi_transports that allocate
553 * a session per scsi host.
554 **/
555int iscsi_transport_destroy_session(struct Scsi_Host *shost)
556{
557 struct iscsi_cls_session *session;
558 unsigned long flags;
559
560 session = hostdata_session(shost->hostdata);
561 spin_lock_irqsave(&sesslock, flags);
562 list_del(&session->sess_list);
563 spin_unlock_irqrestore(&sesslock, flags);
564 iscsi_destroy_session(session);
565
566 scsi_remove_host(shost);
567 /* ref from host alloc */
568 scsi_host_put(shost);
569 return 0;
570}
571
572EXPORT_SYMBOL_GPL(iscsi_transport_destroy_session);
573
574/*
575 * iscsi interface functions 475 * iscsi interface functions
576 */ 476 */
577static struct iscsi_internal * 477static struct iscsi_internal *
@@ -857,14 +757,19 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
857{ 757{
858 struct iscsi_transport *transport = priv->iscsi_transport; 758 struct iscsi_transport *transport = priv->iscsi_transport;
859 struct iscsi_cls_session *session; 759 struct iscsi_cls_session *session;
760 unsigned long flags;
860 uint32_t hostno; 761 uint32_t hostno;
861 762
862 session = transport->create_session(&priv->t, 763 session = transport->create_session(transport, &priv->t,
863 ev->u.c_session.initial_cmdsn, 764 ev->u.c_session.initial_cmdsn,
864 &hostno); 765 &hostno);
865 if (!session) 766 if (!session)
866 return -ENOMEM; 767 return -ENOMEM;
867 768
769 spin_lock_irqsave(&sesslock, flags);
770 list_add(&session->sess_list, &sesslist);
771 spin_unlock_irqrestore(&sesslock, flags);
772
868 ev->r.c_session_ret.host_no = hostno; 773 ev->r.c_session_ret.host_no = hostno;
869 ev->r.c_session_ret.sid = session->sid; 774 ev->r.c_session_ret.sid = session->sid;
870 return 0; 775 return 0;
@@ -1032,6 +937,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
1032 struct iscsi_internal *priv; 937 struct iscsi_internal *priv;
1033 struct iscsi_cls_session *session; 938 struct iscsi_cls_session *session;
1034 struct iscsi_cls_conn *conn; 939 struct iscsi_cls_conn *conn;
940 unsigned long flags;
1035 941
1036 priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle)); 942 priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle));
1037 if (!priv) 943 if (!priv)
@@ -1047,9 +953,13 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
1047 break; 953 break;
1048 case ISCSI_UEVENT_DESTROY_SESSION: 954 case ISCSI_UEVENT_DESTROY_SESSION:
1049 session = iscsi_session_lookup(ev->u.d_session.sid); 955 session = iscsi_session_lookup(ev->u.d_session.sid);
1050 if (session) 956 if (session) {
957 spin_lock_irqsave(&sesslock, flags);
958 list_del(&session->sess_list);
959 spin_unlock_irqrestore(&sesslock, flags);
960
1051 transport->destroy_session(session); 961 transport->destroy_session(session);
1052 else 962 } else
1053 err = -EINVAL; 963 err = -EINVAL;
1054 break; 964 break;
1055 case ISCSI_UEVENT_CREATE_CONN: 965 case ISCSI_UEVENT_CREATE_CONN:
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index eebe2b15161b..47524c726ee8 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -148,7 +148,8 @@ enum iscsi_err {
148 ISCSI_ERR_SESSION_FAILED = ISCSI_ERR_BASE + 13, 148 ISCSI_ERR_SESSION_FAILED = ISCSI_ERR_BASE + 13,
149 ISCSI_ERR_HDR_DGST = ISCSI_ERR_BASE + 14, 149 ISCSI_ERR_HDR_DGST = ISCSI_ERR_BASE + 14,
150 ISCSI_ERR_DATA_DGST = ISCSI_ERR_BASE + 15, 150 ISCSI_ERR_DATA_DGST = ISCSI_ERR_BASE + 15,
151 ISCSI_ERR_PARAM_NOT_FOUND = ISCSI_ERR_BASE + 16 151 ISCSI_ERR_PARAM_NOT_FOUND = ISCSI_ERR_BASE + 16,
152 ISCSI_ERR_NO_SCSI_CMD = ISCSI_ERR_BASE + 17,
152}; 153};
153 154
154/* 155/*
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
new file mode 100644
index 000000000000..830700a4ed69
--- /dev/null
+++ b/include/scsi/libiscsi.h
@@ -0,0 +1,286 @@
1/*
2 * iSCSI lib definitions
3 *
4 * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
5 * Copyright (C) 2004 - 2006 Mike Christie
6 * Copyright (C) 2004 - 2005 Dmitry Yusupov
7 * Copyright (C) 2004 - 2005 Alex Aizman
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23#ifndef LIBISCSI_H
24#define LIBISCSI_H
25
26#include <linux/types.h>
27#include <linux/mutex.h>
28#include <scsi/iscsi_proto.h>
29#include <scsi/iscsi_if.h>
30
31struct scsi_transport_template;
32struct scsi_device;
33struct Scsi_Host;
34struct scsi_cmnd;
35struct socket;
36struct iscsi_transport;
37struct iscsi_cls_session;
38struct iscsi_cls_conn;
39struct iscsi_session;
40struct iscsi_nopin;
41
42/* #define DEBUG_SCSI */
43#ifdef DEBUG_SCSI
44#define debug_scsi(fmt...) printk(KERN_INFO "scsi: " fmt)
45#else
46#define debug_scsi(fmt...)
47#endif
48
49#define ISCSI_XMIT_CMDS_MAX 128 /* must be power of 2 */
50#define ISCSI_MGMT_CMDS_MAX 32 /* must be power of 2 */
51#define ISCSI_CONN_MAX 1
52
53#define ISCSI_MGMT_ITT_OFFSET 0xa00
54
55#define ISCSI_DEF_CMD_PER_LUN 32
56#define ISCSI_MAX_CMD_PER_LUN 128
57
58/* Task Mgmt states */
59#define TMABORT_INITIAL 0x0
60#define TMABORT_SUCCESS 0x1
61#define TMABORT_FAILED 0x2
62#define TMABORT_TIMEDOUT 0x3
63
64/* Connection suspend "bit" */
65#define ISCSI_SUSPEND_BIT 1
66
67#define ISCSI_ITT_MASK (0xfff)
68#define ISCSI_CID_SHIFT 12
69#define ISCSI_CID_MASK (0xffff << ISCSI_CID_SHIFT)
70#define ISCSI_AGE_SHIFT 28
71#define ISCSI_AGE_MASK (0xf << ISCSI_AGE_SHIFT)
72
73struct iscsi_mgmt_task {
74 /*
75 * Becuae LLDs allocate their hdr differently, this is a pointer to
76 * that storage. It must be setup at session creation time.
77 */
78 struct iscsi_hdr *hdr;
79 char *data; /* mgmt payload */
80 int data_count; /* counts data to be sent */
81 uint32_t itt; /* this ITT */
82 void *dd_data; /* driver/transport data */
83 struct list_head running;
84};
85
86struct iscsi_cmd_task {
87 /*
88 * Becuae LLDs allocate their hdr differently, this is a pointer to
89 * that storage. It must be setup at session creation time.
90 */
91 struct iscsi_cmd *hdr;
92 int itt; /* this ITT */
93 int datasn; /* DataSN */
94
95 uint32_t unsol_datasn;
96 int imm_count; /* imm-data (bytes) */
97 int unsol_count; /* unsolicited (bytes)*/
98 int data_count; /* remaining Data-Out */
99 struct scsi_cmnd *sc; /* associated SCSI cmd*/
100 int total_length;
101 struct iscsi_conn *conn; /* used connection */
102 struct iscsi_mgmt_task *mtask; /* tmf mtask in progr */
103
104 struct list_head running; /* running cmd list */
105 void *dd_data; /* driver/transport data */
106};
107
108struct iscsi_conn {
109 struct iscsi_cls_conn *cls_conn; /* ptr to class connection */
110 void *dd_data; /* iscsi_transport data */
111 struct iscsi_session *session; /* parent session */
112 /*
113 * LLDs should set this lock. It protects the transport recv
114 * code
115 */
116 rwlock_t *recv_lock;
117 /*
118 * conn_stop() flag: stop to recover, stop to terminate
119 */
120 int stop_stage;
121
122 /* iSCSI connection-wide sequencing */
123 uint32_t exp_statsn;
124
125 /* control data */
126 int id; /* CID */
127 struct list_head item; /* maintains list of conns */
128 int c_stage; /* connection state */
129 struct iscsi_mgmt_task *login_mtask; /* mtask used for login/text */
130 struct iscsi_mgmt_task *mtask; /* xmit mtask in progress */
131 struct iscsi_cmd_task *ctask; /* xmit ctask in progress */
132
133 /* xmit */
134 struct kfifo *immqueue; /* immediate xmit queue */
135 struct kfifo *mgmtqueue; /* mgmt (control) xmit queue */
136 struct list_head mgmt_run_list; /* list of control tasks */
137 struct kfifo *xmitqueue; /* data-path cmd queue */
138 struct list_head run_list; /* list of cmds in progress */
139 struct work_struct xmitwork; /* per-conn. xmit workqueue */
140 /*
141 * serializes connection xmit, access to kfifos:
142 * xmitqueue, immqueue, mgmtqueue
143 */
144 struct mutex xmitmutex;
145
146 unsigned long suspend_tx; /* suspend Tx */
147 unsigned long suspend_rx; /* suspend Rx */
148
149 /* abort */
150 wait_queue_head_t ehwait; /* used in eh_abort() */
151 struct iscsi_tm tmhdr;
152 struct timer_list tmabort_timer;
153 int tmabort_state; /* see TMABORT_INITIAL, etc.*/
154
155 /* negotiated params */
156 int max_recv_dlength; /* initiator_max_recv_dsl*/
157 int max_xmit_dlength; /* target_max_recv_dsl */
158 int hdrdgst_en;
159 int datadgst_en;
160
161 /* MIB-statistics */
162 uint64_t txdata_octets;
163 uint64_t rxdata_octets;
164 uint32_t scsicmd_pdus_cnt;
165 uint32_t dataout_pdus_cnt;
166 uint32_t scsirsp_pdus_cnt;
167 uint32_t datain_pdus_cnt;
168 uint32_t r2t_pdus_cnt;
169 uint32_t tmfcmd_pdus_cnt;
170 int32_t tmfrsp_pdus_cnt;
171
172 /* custom statistics */
173 uint32_t eh_abort_cnt;
174};
175
176struct iscsi_queue {
177 struct kfifo *queue; /* FIFO Queue */
178 void **pool; /* Pool of elements */
179 int max; /* Max number of elements */
180};
181
182struct iscsi_session {
183 /* iSCSI session-wide sequencing */
184 uint32_t cmdsn;
185 uint32_t exp_cmdsn;
186 uint32_t max_cmdsn;
187
188 /* configuration */
189 int initial_r2t_en;
190 int max_r2t;
191 int imm_data_en;
192 int first_burst;
193 int max_burst;
194 int time2wait;
195 int time2retain;
196 int pdu_inorder_en;
197 int dataseq_inorder_en;
198 int erl;
199 int ifmarker_en;
200 int ofmarker_en;
201
202 /* control data */
203 struct iscsi_transport *tt;
204 struct Scsi_Host *host;
205 struct iscsi_conn *leadconn; /* leading connection */
206 spinlock_t lock; /* protects session state, *
207 * sequence numbers, *
208 * session resources: *
209 * - cmdpool, *
210 * - mgmtpool, *
211 * - r2tpool */
212 int state; /* session state */
213 int recovery_failed;
214 struct list_head item;
215 int conn_cnt;
216 int age; /* counts session re-opens */
217
218 struct list_head connections; /* list of connections */
219 int cmds_max; /* size of cmds array */
220 struct iscsi_cmd_task **cmds; /* Original Cmds arr */
221 struct iscsi_queue cmdpool; /* PDU's pool */
222 int mgmtpool_max; /* size of mgmt array */
223 struct iscsi_mgmt_task **mgmt_cmds; /* Original mgmt arr */
224 struct iscsi_queue mgmtpool; /* Mgmt PDU's pool */
225};
226
227/*
228 * scsi host template
229 */
230extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth);
231extern int iscsi_eh_abort(struct scsi_cmnd *sc);
232extern int iscsi_eh_host_reset(struct scsi_cmnd *sc);
233extern int iscsi_queuecommand(struct scsi_cmnd *sc,
234 void (*done)(struct scsi_cmnd *));
235
236/*
237 * session management
238 */
239extern struct iscsi_cls_session *
240iscsi_session_setup(struct iscsi_transport *, struct scsi_transport_template *,
241 int, int, uint32_t, uint32_t *);
242extern void iscsi_session_teardown(struct iscsi_cls_session *);
243extern struct iscsi_session *class_to_transport_session(struct iscsi_cls_session *);
244extern void iscsi_start_session_recovery(struct iscsi_session *,
245 struct iscsi_conn *, int);
246extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *);
247
248#define session_to_cls(_sess) \
249 hostdata_session(_sess->host->hostdata)
250
251/*
252 * connection management
253 */
254extern struct iscsi_cls_conn *iscsi_conn_setup(struct iscsi_cls_session *,
255 uint32_t);
256extern void iscsi_conn_teardown(struct iscsi_cls_conn *);
257extern int iscsi_conn_start(struct iscsi_cls_conn *);
258extern void iscsi_conn_stop(struct iscsi_cls_conn *, int);
259extern int iscsi_conn_bind(struct iscsi_cls_session *, struct iscsi_cls_conn *,
260 int);
261extern void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err);
262
263/*
264 * pdu and task processing
265 */
266extern int iscsi_check_assign_cmdsn(struct iscsi_session *,
267 struct iscsi_nopin *);
268extern void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *,
269 struct iscsi_data *hdr,
270 int transport_data_cnt);
271extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *,
272 char *, uint32_t);
273extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,
274 char *, int);
275extern int __iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,
276 char *, int);
277extern int iscsi_verify_itt(struct iscsi_conn *, struct iscsi_hdr *,
278 uint32_t *);
279
280/*
281 * generic helpers
282 */
283extern void iscsi_pool_free(struct iscsi_queue *, void **);
284extern int iscsi_pool_init(struct iscsi_queue *, int, void ***, int);
285
286#endif
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index 9d2b99159ee7..b332d6e839fe 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -2,7 +2,7 @@
2 * iSCSI transport class definitions 2 * iSCSI transport class definitions
3 * 3 *
4 * Copyright (C) IBM Corporation, 2004 4 * Copyright (C) IBM Corporation, 2004
5 * Copyright (C) Mike Christie, 2004 - 2005 5 * Copyright (C) Mike Christie, 2004 - 2006
6 * Copyright (C) Dmitry Yusupov, 2004 - 2005 6 * Copyright (C) Dmitry Yusupov, 2004 - 2005
7 * Copyright (C) Alex Aizman, 2004 - 2005 7 * Copyright (C) Alex Aizman, 2004 - 2005
8 * 8 *
@@ -27,9 +27,13 @@
27#include <scsi/iscsi_if.h> 27#include <scsi/iscsi_if.h>
28 28
29struct scsi_transport_template; 29struct scsi_transport_template;
30struct iscsi_transport;
30struct Scsi_Host; 31struct Scsi_Host;
31struct mempool_zone; 32struct mempool_zone;
32struct iscsi_cls_conn; 33struct iscsi_cls_conn;
34struct iscsi_conn;
35struct iscsi_cmd_task;
36struct iscsi_mgmt_task;
33 37
34/** 38/**
35 * struct iscsi_transport - iSCSI Transport template 39 * struct iscsi_transport - iSCSI Transport template
@@ -46,6 +50,20 @@ struct iscsi_cls_conn;
46 * @start_conn: set connection to be operational 50 * @start_conn: set connection to be operational
47 * @stop_conn: suspend/recover/terminate connection 51 * @stop_conn: suspend/recover/terminate connection
48 * @send_pdu: send iSCSI PDU, Login, Logout, NOP-Out, Reject, Text. 52 * @send_pdu: send iSCSI PDU, Login, Logout, NOP-Out, Reject, Text.
53 * @session_recovery_timedout: notify LLD a block during recovery timed out
54 * @suspend_conn_recv: susepend the recv side of the connection
55 * @termincate_conn: destroy socket connection. Called with mutex lock.
56 * @init_cmd_task: Initialize a iscsi_cmd_task and any internal structs.
57 * Called from queuecommand with session lock held.
58 * @init_mgmt_task: Initialize a iscsi_mgmt_task and any internal structs.
59 * Called from iscsi_conn_send_generic with xmitmutex.
60 * @xmit_cmd_task: requests LLD to transfer cmd task
61 * @xmit_mgmt_task: requests LLD to transfer mgmt task
62 * @cleanup_cmd_task: requests LLD to fail cmd task. Called with xmitmutex
63 * and session->lock after the connection has been
64 * suspended and terminated during recovery. If called
65 * from abort task then connection is not suspended
66 * or terminated but sk_callback_lock is held
49 * 67 *
50 * Template API provided by iSCSI Transport 68 * Template API provided by iSCSI Transport
51 */ 69 */
@@ -56,8 +74,6 @@ struct iscsi_transport {
56 /* LLD sets this to indicate what values it can export to sysfs */ 74 /* LLD sets this to indicate what values it can export to sysfs */
57 unsigned int param_mask; 75 unsigned int param_mask;
58 struct scsi_host_template *host_template; 76 struct scsi_host_template *host_template;
59 /* LLD session/scsi_host data size */
60 int hostdata_size;
61 /* LLD connection data size */ 77 /* LLD connection data size */
62 int conndata_size; 78 int conndata_size;
63 /* LLD session data size */ 79 /* LLD session data size */
@@ -65,8 +81,8 @@ struct iscsi_transport {
65 int max_lun; 81 int max_lun;
66 unsigned int max_conn; 82 unsigned int max_conn;
67 unsigned int max_cmd_len; 83 unsigned int max_cmd_len;
68 struct iscsi_cls_session *(*create_session) 84 struct iscsi_cls_session *(*create_session) (struct iscsi_transport *it,
69 (struct scsi_transport_template *t, uint32_t sn, uint32_t *hn); 85 struct scsi_transport_template *t, uint32_t sn, uint32_t *hn);
70 void (*destroy_session) (struct iscsi_cls_session *session); 86 void (*destroy_session) (struct iscsi_cls_session *session);
71 struct iscsi_cls_conn *(*create_conn) (struct iscsi_cls_session *sess, 87 struct iscsi_cls_conn *(*create_conn) (struct iscsi_cls_session *sess,
72 uint32_t cid); 88 uint32_t cid);
@@ -90,6 +106,18 @@ struct iscsi_transport {
90 char *data, uint32_t data_size); 106 char *data, uint32_t data_size);
91 void (*get_stats) (struct iscsi_cls_conn *conn, 107 void (*get_stats) (struct iscsi_cls_conn *conn,
92 struct iscsi_stats *stats); 108 struct iscsi_stats *stats);
109 void (*suspend_conn_recv) (struct iscsi_conn *conn);
110 void (*terminate_conn) (struct iscsi_conn *conn);
111 void (*init_cmd_task) (struct iscsi_cmd_task *ctask);
112 void (*init_mgmt_task) (struct iscsi_conn *conn,
113 struct iscsi_mgmt_task *mtask,
114 char *data, uint32_t data_size);
115 int (*xmit_cmd_task) (struct iscsi_conn *conn,
116 struct iscsi_cmd_task *ctask);
117 void (*cleanup_cmd_task) (struct iscsi_conn *conn,
118 struct iscsi_cmd_task *ctask);
119 int (*xmit_mgmt_task) (struct iscsi_conn *conn,
120 struct iscsi_mgmt_task *mtask);
93 void (*session_recovery_timedout) (struct iscsi_cls_session *session); 121 void (*session_recovery_timedout) (struct iscsi_cls_session *session);
94}; 122};
95 123
@@ -106,6 +134,13 @@ extern void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error);
106extern int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, 134extern int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
107 char *data, uint32_t data_size); 135 char *data, uint32_t data_size);
108 136
137
138/* Connection's states */
139#define ISCSI_CONN_INITIAL_STAGE 0
140#define ISCSI_CONN_STARTED 1
141#define ISCSI_CONN_STOPPED 2
142#define ISCSI_CONN_CLEANUP_WAIT 3
143
109struct iscsi_cls_conn { 144struct iscsi_cls_conn {
110 struct list_head conn_list; /* item in connlist */ 145 struct list_head conn_list; /* item in connlist */
111 void *dd_data; /* LLD private data */ 146 void *dd_data; /* LLD private data */
@@ -129,6 +164,12 @@ struct iscsi_cls_conn {
129#define iscsi_dev_to_conn(_dev) \ 164#define iscsi_dev_to_conn(_dev) \
130 container_of(_dev, struct iscsi_cls_conn, dev) 165 container_of(_dev, struct iscsi_cls_conn, dev)
131 166
167/* Session's states */
168#define ISCSI_STATE_FREE 1
169#define ISCSI_STATE_LOGGED_IN 2
170#define ISCSI_STATE_FAILED 3
171#define ISCSI_STATE_TERMINATE 4
172
132struct iscsi_cls_session { 173struct iscsi_cls_session {
133 struct list_head sess_list; /* item in session_list */ 174 struct list_head sess_list; /* item in session_list */
134 struct list_head host_list; 175 struct list_head host_list;
@@ -174,12 +215,4 @@ extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn);
174extern void iscsi_unblock_session(struct iscsi_cls_session *session); 215extern void iscsi_unblock_session(struct iscsi_cls_session *session);
175extern void iscsi_block_session(struct iscsi_cls_session *session); 216extern void iscsi_block_session(struct iscsi_cls_session *session);
176 217
177/*
178 * session functions used by software iscsi
179 */
180extern struct Scsi_Host *
181iscsi_transport_create_session(struct scsi_transport_template *scsit,
182 struct iscsi_transport *transport);
183extern int iscsi_transport_destroy_session(struct Scsi_Host *shost);
184
185#endif 218#endif