diff options
Diffstat (limited to 'drivers/scsi/libiscsi.c')
-rw-r--r-- | drivers/scsi/libiscsi.c | 533 |
1 files changed, 414 insertions, 119 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 2673a11a949..c542d0e95e6 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -68,8 +68,7 @@ iscsi_check_assign_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) | |||
68 | EXPORT_SYMBOL_GPL(iscsi_check_assign_cmdsn); | 68 | EXPORT_SYMBOL_GPL(iscsi_check_assign_cmdsn); |
69 | 69 | ||
70 | void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, | 70 | void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, |
71 | struct iscsi_data *hdr, | 71 | struct iscsi_data *hdr) |
72 | int transport_data_cnt) | ||
73 | { | 72 | { |
74 | struct iscsi_conn *conn = ctask->conn; | 73 | struct iscsi_conn *conn = ctask->conn; |
75 | 74 | ||
@@ -82,14 +81,12 @@ void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, | |||
82 | 81 | ||
83 | hdr->itt = ctask->hdr->itt; | 82 | hdr->itt = ctask->hdr->itt; |
84 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); | 83 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); |
85 | 84 | hdr->offset = cpu_to_be32(ctask->unsol_offset); | |
86 | hdr->offset = cpu_to_be32(ctask->total_length - | ||
87 | transport_data_cnt - | ||
88 | ctask->unsol_count); | ||
89 | 85 | ||
90 | if (ctask->unsol_count > conn->max_xmit_dlength) { | 86 | if (ctask->unsol_count > conn->max_xmit_dlength) { |
91 | hton24(hdr->dlength, conn->max_xmit_dlength); | 87 | hton24(hdr->dlength, conn->max_xmit_dlength); |
92 | ctask->data_count = conn->max_xmit_dlength; | 88 | ctask->data_count = conn->max_xmit_dlength; |
89 | ctask->unsol_offset += ctask->data_count; | ||
93 | hdr->flags = 0; | 90 | hdr->flags = 0; |
94 | } else { | 91 | } else { |
95 | hton24(hdr->dlength, ctask->unsol_count); | 92 | hton24(hdr->dlength, ctask->unsol_count); |
@@ -125,6 +122,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
125 | memcpy(hdr->cdb, sc->cmnd, sc->cmd_len); | 122 | memcpy(hdr->cdb, sc->cmnd, sc->cmd_len); |
126 | memset(&hdr->cdb[sc->cmd_len], 0, MAX_COMMAND_SIZE - sc->cmd_len); | 123 | memset(&hdr->cdb[sc->cmd_len], 0, MAX_COMMAND_SIZE - sc->cmd_len); |
127 | 124 | ||
125 | ctask->data_count = 0; | ||
128 | if (sc->sc_data_direction == DMA_TO_DEVICE) { | 126 | if (sc->sc_data_direction == DMA_TO_DEVICE) { |
129 | hdr->flags |= ISCSI_FLAG_CMD_WRITE; | 127 | hdr->flags |= ISCSI_FLAG_CMD_WRITE; |
130 | /* | 128 | /* |
@@ -143,6 +141,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
143 | */ | 141 | */ |
144 | ctask->imm_count = 0; | 142 | ctask->imm_count = 0; |
145 | ctask->unsol_count = 0; | 143 | ctask->unsol_count = 0; |
144 | ctask->unsol_offset = 0; | ||
146 | ctask->unsol_datasn = 0; | 145 | ctask->unsol_datasn = 0; |
147 | 146 | ||
148 | if (session->imm_data_en) { | 147 | if (session->imm_data_en) { |
@@ -156,9 +155,12 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
156 | } else | 155 | } else |
157 | zero_data(ctask->hdr->dlength); | 156 | zero_data(ctask->hdr->dlength); |
158 | 157 | ||
159 | if (!session->initial_r2t_en) | 158 | if (!session->initial_r2t_en) { |
160 | ctask->unsol_count = min(session->first_burst, | 159 | ctask->unsol_count = min(session->first_burst, |
161 | ctask->total_length) - ctask->imm_count; | 160 | ctask->total_length) - ctask->imm_count; |
161 | ctask->unsol_offset = ctask->imm_count; | ||
162 | } | ||
163 | |||
162 | if (!ctask->unsol_count) | 164 | if (!ctask->unsol_count) |
163 | /* No unsolicit Data-Out's */ | 165 | /* No unsolicit Data-Out's */ |
164 | ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL; | 166 | ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL; |
@@ -177,24 +179,51 @@ EXPORT_SYMBOL_GPL(iscsi_prep_scsi_cmd_pdu); | |||
177 | 179 | ||
178 | /** | 180 | /** |
179 | * iscsi_complete_command - return command back to scsi-ml | 181 | * iscsi_complete_command - return command back to scsi-ml |
180 | * @session: iscsi session | ||
181 | * @ctask: iscsi cmd task | 182 | * @ctask: iscsi cmd task |
182 | * | 183 | * |
183 | * Must be called with session lock. | 184 | * Must be called with session lock. |
184 | * This function returns the scsi command to scsi-ml and returns | 185 | * This function returns the scsi command to scsi-ml and returns |
185 | * the cmd task to the pool of available cmd tasks. | 186 | * the cmd task to the pool of available cmd tasks. |
186 | */ | 187 | */ |
187 | static void iscsi_complete_command(struct iscsi_session *session, | 188 | static void iscsi_complete_command(struct iscsi_cmd_task *ctask) |
188 | struct iscsi_cmd_task *ctask) | ||
189 | { | 189 | { |
190 | struct iscsi_session *session = ctask->conn->session; | ||
190 | struct scsi_cmnd *sc = ctask->sc; | 191 | struct scsi_cmnd *sc = ctask->sc; |
191 | 192 | ||
193 | ctask->state = ISCSI_TASK_COMPLETED; | ||
192 | ctask->sc = NULL; | 194 | ctask->sc = NULL; |
195 | /* SCSI eh reuses commands to verify us */ | ||
196 | sc->SCp.ptr = NULL; | ||
193 | list_del_init(&ctask->running); | 197 | list_del_init(&ctask->running); |
194 | __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); | 198 | __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); |
195 | sc->scsi_done(sc); | 199 | sc->scsi_done(sc); |
196 | } | 200 | } |
197 | 201 | ||
202 | static void __iscsi_get_ctask(struct iscsi_cmd_task *ctask) | ||
203 | { | ||
204 | atomic_inc(&ctask->refcount); | ||
205 | } | ||
206 | |||
207 | static void iscsi_get_ctask(struct iscsi_cmd_task *ctask) | ||
208 | { | ||
209 | spin_lock_bh(&ctask->conn->session->lock); | ||
210 | __iscsi_get_ctask(ctask); | ||
211 | spin_unlock_bh(&ctask->conn->session->lock); | ||
212 | } | ||
213 | |||
214 | static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask) | ||
215 | { | ||
216 | if (atomic_dec_and_test(&ctask->refcount)) | ||
217 | iscsi_complete_command(ctask); | ||
218 | } | ||
219 | |||
220 | static void iscsi_put_ctask(struct iscsi_cmd_task *ctask) | ||
221 | { | ||
222 | spin_lock_bh(&ctask->conn->session->lock); | ||
223 | __iscsi_put_ctask(ctask); | ||
224 | spin_unlock_bh(&ctask->conn->session->lock); | ||
225 | } | ||
226 | |||
198 | /** | 227 | /** |
199 | * iscsi_cmd_rsp - SCSI Command Response processing | 228 | * iscsi_cmd_rsp - SCSI Command Response processing |
200 | * @conn: iscsi connection | 229 | * @conn: iscsi connection |
@@ -271,10 +300,53 @@ out: | |||
271 | (long)sc, sc->result, ctask->itt); | 300 | (long)sc, sc->result, ctask->itt); |
272 | conn->scsirsp_pdus_cnt++; | 301 | conn->scsirsp_pdus_cnt++; |
273 | 302 | ||
274 | iscsi_complete_command(conn->session, ctask); | 303 | __iscsi_put_ctask(ctask); |
275 | return rc; | 304 | return rc; |
276 | } | 305 | } |
277 | 306 | ||
307 | static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | ||
308 | { | ||
309 | struct iscsi_tm_rsp *tmf = (struct iscsi_tm_rsp *)hdr; | ||
310 | |||
311 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; | ||
312 | conn->tmfrsp_pdus_cnt++; | ||
313 | |||
314 | if (conn->tmabort_state != TMABORT_INITIAL) | ||
315 | return; | ||
316 | |||
317 | if (tmf->response == ISCSI_TMF_RSP_COMPLETE) | ||
318 | conn->tmabort_state = TMABORT_SUCCESS; | ||
319 | else if (tmf->response == ISCSI_TMF_RSP_NO_TASK) | ||
320 | conn->tmabort_state = TMABORT_NOT_FOUND; | ||
321 | else | ||
322 | conn->tmabort_state = TMABORT_FAILED; | ||
323 | wake_up(&conn->ehwait); | ||
324 | } | ||
325 | |||
326 | static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | ||
327 | char *data, int datalen) | ||
328 | { | ||
329 | struct iscsi_reject *reject = (struct iscsi_reject *)hdr; | ||
330 | struct iscsi_hdr rejected_pdu; | ||
331 | uint32_t itt; | ||
332 | |||
333 | conn->exp_statsn = be32_to_cpu(reject->statsn) + 1; | ||
334 | |||
335 | if (reject->reason == ISCSI_REASON_DATA_DIGEST_ERROR) { | ||
336 | if (ntoh24(reject->dlength) > datalen) | ||
337 | return ISCSI_ERR_PROTO; | ||
338 | |||
339 | if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) { | ||
340 | memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr)); | ||
341 | itt = rejected_pdu.itt & ISCSI_ITT_MASK; | ||
342 | printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected " | ||
343 | "due to DataDigest error.\n", itt, | ||
344 | rejected_pdu.opcode); | ||
345 | } | ||
346 | } | ||
347 | return 0; | ||
348 | } | ||
349 | |||
278 | /** | 350 | /** |
279 | * __iscsi_complete_pdu - complete pdu | 351 | * __iscsi_complete_pdu - complete pdu |
280 | * @conn: iscsi conn | 352 | * @conn: iscsi conn |
@@ -316,7 +388,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
316 | BUG_ON((void*)ctask != ctask->sc->SCp.ptr); | 388 | BUG_ON((void*)ctask != ctask->sc->SCp.ptr); |
317 | if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { | 389 | if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { |
318 | conn->scsirsp_pdus_cnt++; | 390 | conn->scsirsp_pdus_cnt++; |
319 | iscsi_complete_command(session, ctask); | 391 | __iscsi_put_ctask(ctask); |
320 | } | 392 | } |
321 | break; | 393 | break; |
322 | case ISCSI_OP_R2T: | 394 | case ISCSI_OP_R2T: |
@@ -340,6 +412,10 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
340 | 412 | ||
341 | switch(opcode) { | 413 | switch(opcode) { |
342 | case ISCSI_OP_LOGOUT_RSP: | 414 | case ISCSI_OP_LOGOUT_RSP: |
415 | if (datalen) { | ||
416 | rc = ISCSI_ERR_PROTO; | ||
417 | break; | ||
418 | } | ||
343 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; | 419 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; |
344 | /* fall through */ | 420 | /* fall through */ |
345 | case ISCSI_OP_LOGIN_RSP: | 421 | case ISCSI_OP_LOGIN_RSP: |
@@ -348,7 +424,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
348 | * login related PDU's exp_statsn is handled in | 424 | * login related PDU's exp_statsn is handled in |
349 | * userspace | 425 | * userspace |
350 | */ | 426 | */ |
351 | rc = iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen); | 427 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) |
428 | rc = ISCSI_ERR_CONN_FAILED; | ||
352 | list_del(&mtask->running); | 429 | list_del(&mtask->running); |
353 | if (conn->login_mtask != mtask) | 430 | if (conn->login_mtask != mtask) |
354 | __kfifo_put(session->mgmtpool.queue, | 431 | __kfifo_put(session->mgmtpool.queue, |
@@ -360,25 +437,17 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
360 | break; | 437 | break; |
361 | } | 438 | } |
362 | 439 | ||
363 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; | 440 | iscsi_tmf_rsp(conn, hdr); |
364 | conn->tmfrsp_pdus_cnt++; | ||
365 | if (conn->tmabort_state == TMABORT_INITIAL) { | ||
366 | conn->tmabort_state = | ||
367 | ((struct iscsi_tm_rsp *)hdr)-> | ||
368 | response == ISCSI_TMF_RSP_COMPLETE ? | ||
369 | TMABORT_SUCCESS:TMABORT_FAILED; | ||
370 | /* unblock eh_abort() */ | ||
371 | wake_up(&conn->ehwait); | ||
372 | } | ||
373 | break; | 441 | break; |
374 | case ISCSI_OP_NOOP_IN: | 442 | case ISCSI_OP_NOOP_IN: |
375 | if (hdr->ttt != ISCSI_RESERVED_TAG) { | 443 | if (hdr->ttt != ISCSI_RESERVED_TAG || datalen) { |
376 | rc = ISCSI_ERR_PROTO; | 444 | rc = ISCSI_ERR_PROTO; |
377 | break; | 445 | break; |
378 | } | 446 | } |
379 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; | 447 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; |
380 | 448 | ||
381 | rc = iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen); | 449 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) |
450 | rc = ISCSI_ERR_CONN_FAILED; | ||
382 | list_del(&mtask->running); | 451 | list_del(&mtask->running); |
383 | if (conn->login_mtask != mtask) | 452 | if (conn->login_mtask != mtask) |
384 | __kfifo_put(session->mgmtpool.queue, | 453 | __kfifo_put(session->mgmtpool.queue, |
@@ -389,19 +458,27 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
389 | break; | 458 | break; |
390 | } | 459 | } |
391 | } else if (itt == ISCSI_RESERVED_TAG) { | 460 | } else if (itt == ISCSI_RESERVED_TAG) { |
461 | rc = iscsi_check_assign_cmdsn(session, | ||
462 | (struct iscsi_nopin*)hdr); | ||
463 | if (rc) | ||
464 | goto done; | ||
465 | |||
392 | switch(opcode) { | 466 | switch(opcode) { |
393 | case ISCSI_OP_NOOP_IN: | 467 | case ISCSI_OP_NOOP_IN: |
394 | if (!datalen) { | 468 | if (datalen) { |
395 | rc = iscsi_check_assign_cmdsn(session, | ||
396 | (struct iscsi_nopin*)hdr); | ||
397 | if (!rc && hdr->ttt != ISCSI_RESERVED_TAG) | ||
398 | rc = iscsi_recv_pdu(conn->cls_conn, | ||
399 | hdr, NULL, 0); | ||
400 | } else | ||
401 | rc = ISCSI_ERR_PROTO; | 469 | rc = ISCSI_ERR_PROTO; |
470 | break; | ||
471 | } | ||
472 | |||
473 | if (hdr->ttt == ISCSI_RESERVED_TAG) | ||
474 | break; | ||
475 | |||
476 | if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0)) | ||
477 | rc = ISCSI_ERR_CONN_FAILED; | ||
402 | break; | 478 | break; |
403 | case ISCSI_OP_REJECT: | 479 | case ISCSI_OP_REJECT: |
404 | /* we need sth like iscsi_reject_rsp()*/ | 480 | rc = iscsi_handle_reject(conn, hdr, data, datalen); |
481 | break; | ||
405 | case ISCSI_OP_ASYNC_EVENT: | 482 | case ISCSI_OP_ASYNC_EVENT: |
406 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; | 483 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; |
407 | /* we need sth like iscsi_async_event_rsp() */ | 484 | /* we need sth like iscsi_async_event_rsp() */ |
@@ -537,7 +614,9 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
537 | BUG_ON(conn->ctask && conn->mtask); | 614 | BUG_ON(conn->ctask && conn->mtask); |
538 | 615 | ||
539 | if (conn->ctask) { | 616 | if (conn->ctask) { |
617 | iscsi_get_ctask(conn->ctask); | ||
540 | rc = tt->xmit_cmd_task(conn, conn->ctask); | 618 | rc = tt->xmit_cmd_task(conn, conn->ctask); |
619 | iscsi_put_ctask(conn->ctask); | ||
541 | if (rc) | 620 | if (rc) |
542 | goto again; | 621 | goto again; |
543 | /* done with this in-progress ctask */ | 622 | /* done with this in-progress ctask */ |
@@ -568,20 +647,31 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
568 | } | 647 | } |
569 | 648 | ||
570 | /* process command queue */ | 649 | /* process command queue */ |
571 | while (__kfifo_get(conn->xmitqueue, (void*)&conn->ctask, | 650 | spin_lock_bh(&conn->session->lock); |
572 | sizeof(void*))) { | 651 | while (!list_empty(&conn->xmitqueue)) { |
573 | /* | 652 | /* |
574 | * iscsi tcp may readd the task to the xmitqueue to send | 653 | * iscsi tcp may readd the task to the xmitqueue to send |
575 | * write data | 654 | * write data |
576 | */ | 655 | */ |
577 | spin_lock_bh(&conn->session->lock); | 656 | conn->ctask = list_entry(conn->xmitqueue.next, |
578 | if (list_empty(&conn->ctask->running)) | 657 | struct iscsi_cmd_task, running); |
579 | list_add_tail(&conn->ctask->running, &conn->run_list); | 658 | conn->ctask->state = ISCSI_TASK_RUNNING; |
659 | list_move_tail(conn->xmitqueue.next, &conn->run_list); | ||
660 | __iscsi_get_ctask(conn->ctask); | ||
580 | spin_unlock_bh(&conn->session->lock); | 661 | spin_unlock_bh(&conn->session->lock); |
662 | |||
581 | rc = tt->xmit_cmd_task(conn, conn->ctask); | 663 | rc = tt->xmit_cmd_task(conn, conn->ctask); |
582 | if (rc) | 664 | if (rc) |
583 | goto again; | 665 | goto again; |
666 | |||
667 | spin_lock_bh(&conn->session->lock); | ||
668 | __iscsi_put_ctask(conn->ctask); | ||
669 | if (rc) { | ||
670 | spin_unlock_bh(&conn->session->lock); | ||
671 | goto again; | ||
672 | } | ||
584 | } | 673 | } |
674 | spin_unlock_bh(&conn->session->lock); | ||
585 | /* done with this ctask */ | 675 | /* done with this ctask */ |
586 | conn->ctask = NULL; | 676 | conn->ctask = NULL; |
587 | 677 | ||
@@ -629,6 +719,7 @@ enum { | |||
629 | FAILURE_SESSION_FAILED, | 719 | FAILURE_SESSION_FAILED, |
630 | FAILURE_SESSION_FREED, | 720 | FAILURE_SESSION_FREED, |
631 | FAILURE_WINDOW_CLOSED, | 721 | FAILURE_WINDOW_CLOSED, |
722 | FAILURE_OOM, | ||
632 | FAILURE_SESSION_TERMINATE, | 723 | FAILURE_SESSION_TERMINATE, |
633 | FAILURE_SESSION_IN_RECOVERY, | 724 | FAILURE_SESSION_IN_RECOVERY, |
634 | FAILURE_SESSION_RECOVERY_TIMEOUT, | 725 | FAILURE_SESSION_RECOVERY_TIMEOUT, |
@@ -644,6 +735,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
644 | 735 | ||
645 | sc->scsi_done = done; | 736 | sc->scsi_done = done; |
646 | sc->result = 0; | 737 | sc->result = 0; |
738 | sc->SCp.ptr = NULL; | ||
647 | 739 | ||
648 | host = sc->device->host; | 740 | host = sc->device->host; |
649 | session = iscsi_hostdata(host->hostdata); | 741 | session = iscsi_hostdata(host->hostdata); |
@@ -687,10 +779,16 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
687 | 779 | ||
688 | conn = session->leadconn; | 780 | conn = session->leadconn; |
689 | 781 | ||
690 | __kfifo_get(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); | 782 | if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask, |
783 | sizeof(void*))) { | ||
784 | reason = FAILURE_OOM; | ||
785 | goto reject; | ||
786 | } | ||
691 | sc->SCp.phase = session->age; | 787 | sc->SCp.phase = session->age; |
692 | sc->SCp.ptr = (char *)ctask; | 788 | sc->SCp.ptr = (char *)ctask; |
693 | 789 | ||
790 | atomic_set(&ctask->refcount, 1); | ||
791 | ctask->state = ISCSI_TASK_PENDING; | ||
694 | ctask->mtask = NULL; | 792 | ctask->mtask = NULL; |
695 | ctask->conn = conn; | 793 | ctask->conn = conn; |
696 | ctask->sc = sc; | 794 | ctask->sc = sc; |
@@ -700,11 +798,12 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
700 | 798 | ||
701 | session->tt->init_cmd_task(ctask); | 799 | session->tt->init_cmd_task(ctask); |
702 | 800 | ||
703 | __kfifo_put(conn->xmitqueue, (void*)&ctask, sizeof(void*)); | 801 | list_add_tail(&ctask->running, &conn->xmitqueue); |
704 | debug_scsi( | 802 | debug_scsi( |
705 | "ctask enq [%s cid %d sc %lx itt 0x%x len %d cmdsn %d win %d]\n", | 803 | "ctask enq [%s cid %d sc %p cdb 0x%x itt 0x%x len %d cmdsn %d " |
804 | "win %d]\n", | ||
706 | sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", | 805 | sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", |
707 | conn->id, (long)sc, ctask->itt, sc->request_bufflen, | 806 | conn->id, sc, sc->cmnd[0], ctask->itt, sc->request_bufflen, |
708 | session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); | 807 | session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); |
709 | spin_unlock(&session->lock); | 808 | spin_unlock(&session->lock); |
710 | 809 | ||
@@ -977,31 +1076,27 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, | |||
977 | /* | 1076 | /* |
978 | * xmit mutex and session lock must be held | 1077 | * xmit mutex and session lock must be held |
979 | */ | 1078 | */ |
980 | #define iscsi_remove_task(tasktype) \ | 1079 | static struct iscsi_mgmt_task * |
981 | static struct iscsi_##tasktype * \ | 1080 | iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt) |
982 | iscsi_remove_##tasktype(struct kfifo *fifo, uint32_t itt) \ | 1081 | { |
983 | { \ | 1082 | int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*); |
984 | int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*); \ | 1083 | struct iscsi_mgmt_task *task; |
985 | struct iscsi_##tasktype *task; \ | 1084 | |
986 | \ | 1085 | debug_scsi("searching %d tasks\n", nr_tasks); |
987 | debug_scsi("searching %d tasks\n", nr_tasks); \ | 1086 | |
988 | \ | 1087 | for (i = 0; i < nr_tasks; i++) { |
989 | for (i = 0; i < nr_tasks; i++) { \ | 1088 | __kfifo_get(fifo, (void*)&task, sizeof(void*)); |
990 | __kfifo_get(fifo, (void*)&task, sizeof(void*)); \ | 1089 | debug_scsi("check task %u\n", task->itt); |
991 | debug_scsi("check task %u\n", task->itt); \ | 1090 | |
992 | \ | 1091 | if (task->itt == itt) { |
993 | if (task->itt == itt) { \ | 1092 | debug_scsi("matched task\n"); |
994 | debug_scsi("matched task\n"); \ | 1093 | return task; |
995 | return task; \ | 1094 | } |
996 | } \ | ||
997 | \ | ||
998 | __kfifo_put(fifo, (void*)&task, sizeof(void*)); \ | ||
999 | } \ | ||
1000 | return NULL; \ | ||
1001 | } | ||
1002 | 1095 | ||
1003 | iscsi_remove_task(mgmt_task); | 1096 | __kfifo_put(fifo, (void*)&task, sizeof(void*)); |
1004 | iscsi_remove_task(cmd_task); | 1097 | } |
1098 | return NULL; | ||
1099 | } | ||
1005 | 1100 | ||
1006 | static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask) | 1101 | static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask) |
1007 | { | 1102 | { |
@@ -1027,25 +1122,39 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
1027 | { | 1122 | { |
1028 | struct scsi_cmnd *sc; | 1123 | struct scsi_cmnd *sc; |
1029 | 1124 | ||
1030 | conn->session->tt->cleanup_cmd_task(conn, ctask); | ||
1031 | iscsi_ctask_mtask_cleanup(ctask); | ||
1032 | |||
1033 | sc = ctask->sc; | 1125 | sc = ctask->sc; |
1034 | if (!sc) | 1126 | if (!sc) |
1035 | return; | 1127 | return; |
1128 | |||
1129 | conn->session->tt->cleanup_cmd_task(conn, ctask); | ||
1130 | iscsi_ctask_mtask_cleanup(ctask); | ||
1131 | |||
1036 | sc->result = err; | 1132 | sc->result = err; |
1037 | sc->resid = sc->request_bufflen; | 1133 | sc->resid = sc->request_bufflen; |
1038 | iscsi_complete_command(conn->session, ctask); | 1134 | /* release ref from queuecommand */ |
1135 | __iscsi_put_ctask(ctask); | ||
1039 | } | 1136 | } |
1040 | 1137 | ||
1041 | int iscsi_eh_abort(struct scsi_cmnd *sc) | 1138 | int iscsi_eh_abort(struct scsi_cmnd *sc) |
1042 | { | 1139 | { |
1043 | struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; | 1140 | struct iscsi_cmd_task *ctask; |
1044 | struct iscsi_conn *conn = ctask->conn; | 1141 | struct iscsi_conn *conn; |
1045 | struct iscsi_session *session = conn->session; | 1142 | struct iscsi_session *session; |
1046 | struct iscsi_cmd_task *pending_ctask; | ||
1047 | int rc; | 1143 | int rc; |
1048 | 1144 | ||
1145 | /* | ||
1146 | * if session was ISCSI_STATE_IN_RECOVERY then we may not have | ||
1147 | * got the command. | ||
1148 | */ | ||
1149 | if (!sc->SCp.ptr) { | ||
1150 | debug_scsi("sc never reached iscsi layer or it completed.\n"); | ||
1151 | return SUCCESS; | ||
1152 | } | ||
1153 | |||
1154 | ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; | ||
1155 | conn = ctask->conn; | ||
1156 | session = conn->session; | ||
1157 | |||
1049 | conn->eh_abort_cnt++; | 1158 | conn->eh_abort_cnt++; |
1050 | debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); | 1159 | debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); |
1051 | 1160 | ||
@@ -1061,8 +1170,11 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1061 | goto failed; | 1170 | goto failed; |
1062 | 1171 | ||
1063 | /* ctask completed before time out */ | 1172 | /* ctask completed before time out */ |
1064 | if (!ctask->sc) | 1173 | if (!ctask->sc) { |
1065 | goto success; | 1174 | spin_unlock_bh(&session->lock); |
1175 | debug_scsi("sc completed while abort in progress\n"); | ||
1176 | goto success_rel_mutex; | ||
1177 | } | ||
1066 | 1178 | ||
1067 | /* what should we do here ? */ | 1179 | /* what should we do here ? */ |
1068 | if (conn->ctask == ctask) { | 1180 | if (conn->ctask == ctask) { |
@@ -1071,17 +1183,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1071 | goto failed; | 1183 | goto failed; |
1072 | } | 1184 | } |
1073 | 1185 | ||
1074 | /* check for the easy pending cmd abort */ | 1186 | if (ctask->state == ISCSI_TASK_PENDING) |
1075 | pending_ctask = iscsi_remove_cmd_task(conn->xmitqueue, ctask->itt); | 1187 | goto success_cleanup; |
1076 | if (pending_ctask) { | ||
1077 | /* iscsi_tcp queues write transfers on the xmitqueue */ | ||
1078 | if (list_empty(&pending_ctask->running)) { | ||
1079 | debug_scsi("found pending task\n"); | ||
1080 | goto success; | ||
1081 | } else | ||
1082 | __kfifo_put(conn->xmitqueue, (void*)&pending_ctask, | ||
1083 | sizeof(void*)); | ||
1084 | } | ||
1085 | 1188 | ||
1086 | conn->tmabort_state = TMABORT_INITIAL; | 1189 | conn->tmabort_state = TMABORT_INITIAL; |
1087 | 1190 | ||
@@ -1089,25 +1192,31 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1089 | rc = iscsi_exec_abort_task(sc, ctask); | 1192 | rc = iscsi_exec_abort_task(sc, ctask); |
1090 | spin_lock_bh(&session->lock); | 1193 | spin_lock_bh(&session->lock); |
1091 | 1194 | ||
1092 | iscsi_ctask_mtask_cleanup(ctask); | ||
1093 | if (rc || sc->SCp.phase != session->age || | 1195 | if (rc || sc->SCp.phase != session->age || |
1094 | session->state != ISCSI_STATE_LOGGED_IN) | 1196 | session->state != ISCSI_STATE_LOGGED_IN) |
1095 | goto failed; | 1197 | goto failed; |
1198 | iscsi_ctask_mtask_cleanup(ctask); | ||
1096 | 1199 | ||
1097 | /* ctask completed before tmf abort response */ | 1200 | switch (conn->tmabort_state) { |
1098 | if (!ctask->sc) { | 1201 | case TMABORT_SUCCESS: |
1099 | debug_scsi("sc completed while abort in progress\n"); | 1202 | goto success_cleanup; |
1100 | goto success; | 1203 | case TMABORT_NOT_FOUND: |
1101 | } | 1204 | if (!ctask->sc) { |
1102 | 1205 | /* ctask completed before tmf abort response */ | |
1103 | if (conn->tmabort_state != TMABORT_SUCCESS) { | 1206 | spin_unlock_bh(&session->lock); |
1207 | debug_scsi("sc completed while abort in progress\n"); | ||
1208 | goto success_rel_mutex; | ||
1209 | } | ||
1210 | /* fall through */ | ||
1211 | default: | ||
1212 | /* timedout or failed */ | ||
1104 | spin_unlock_bh(&session->lock); | 1213 | spin_unlock_bh(&session->lock); |
1105 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | 1214 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); |
1106 | spin_lock_bh(&session->lock); | 1215 | spin_lock_bh(&session->lock); |
1107 | goto failed; | 1216 | goto failed; |
1108 | } | 1217 | } |
1109 | 1218 | ||
1110 | success: | 1219 | success_cleanup: |
1111 | debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); | 1220 | debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); |
1112 | spin_unlock_bh(&session->lock); | 1221 | spin_unlock_bh(&session->lock); |
1113 | 1222 | ||
@@ -1121,6 +1230,7 @@ success: | |||
1121 | spin_unlock(&session->lock); | 1230 | spin_unlock(&session->lock); |
1122 | write_unlock_bh(conn->recv_lock); | 1231 | write_unlock_bh(conn->recv_lock); |
1123 | 1232 | ||
1233 | success_rel_mutex: | ||
1124 | mutex_unlock(&conn->xmitmutex); | 1234 | mutex_unlock(&conn->xmitmutex); |
1125 | return SUCCESS; | 1235 | return SUCCESS; |
1126 | 1236 | ||
@@ -1263,6 +1373,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, | |||
1263 | if (cmd_task_size) | 1373 | if (cmd_task_size) |
1264 | ctask->dd_data = &ctask[1]; | 1374 | ctask->dd_data = &ctask[1]; |
1265 | ctask->itt = cmd_i; | 1375 | ctask->itt = cmd_i; |
1376 | INIT_LIST_HEAD(&ctask->running); | ||
1266 | } | 1377 | } |
1267 | 1378 | ||
1268 | spin_lock_init(&session->lock); | 1379 | spin_lock_init(&session->lock); |
@@ -1282,18 +1393,24 @@ iscsi_session_setup(struct iscsi_transport *iscsit, | |||
1282 | if (mgmt_task_size) | 1393 | if (mgmt_task_size) |
1283 | mtask->dd_data = &mtask[1]; | 1394 | mtask->dd_data = &mtask[1]; |
1284 | mtask->itt = ISCSI_MGMT_ITT_OFFSET + cmd_i; | 1395 | mtask->itt = ISCSI_MGMT_ITT_OFFSET + cmd_i; |
1396 | INIT_LIST_HEAD(&mtask->running); | ||
1285 | } | 1397 | } |
1286 | 1398 | ||
1287 | if (scsi_add_host(shost, NULL)) | 1399 | if (scsi_add_host(shost, NULL)) |
1288 | goto add_host_fail; | 1400 | goto add_host_fail; |
1289 | 1401 | ||
1402 | if (!try_module_get(iscsit->owner)) | ||
1403 | goto cls_session_fail; | ||
1404 | |||
1290 | cls_session = iscsi_create_session(shost, iscsit, 0); | 1405 | cls_session = iscsi_create_session(shost, iscsit, 0); |
1291 | if (!cls_session) | 1406 | if (!cls_session) |
1292 | goto cls_session_fail; | 1407 | goto module_put; |
1293 | *(unsigned long*)shost->hostdata = (unsigned long)cls_session; | 1408 | *(unsigned long*)shost->hostdata = (unsigned long)cls_session; |
1294 | 1409 | ||
1295 | return cls_session; | 1410 | return cls_session; |
1296 | 1411 | ||
1412 | module_put: | ||
1413 | module_put(iscsit->owner); | ||
1297 | cls_session_fail: | 1414 | cls_session_fail: |
1298 | scsi_remove_host(shost); | 1415 | scsi_remove_host(shost); |
1299 | add_host_fail: | 1416 | add_host_fail: |
@@ -1317,14 +1434,18 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) | |||
1317 | { | 1434 | { |
1318 | struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); | 1435 | struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); |
1319 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); | 1436 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); |
1437 | struct module *owner = cls_session->transport->owner; | ||
1320 | 1438 | ||
1321 | scsi_remove_host(shost); | 1439 | scsi_remove_host(shost); |
1322 | 1440 | ||
1323 | iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds); | 1441 | iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds); |
1324 | iscsi_pool_free(&session->cmdpool, (void**)session->cmds); | 1442 | iscsi_pool_free(&session->cmdpool, (void**)session->cmds); |
1325 | 1443 | ||
1444 | kfree(session->targetname); | ||
1445 | |||
1326 | iscsi_destroy_session(cls_session); | 1446 | iscsi_destroy_session(cls_session); |
1327 | scsi_host_put(shost); | 1447 | scsi_host_put(shost); |
1448 | module_put(owner); | ||
1328 | } | 1449 | } |
1329 | EXPORT_SYMBOL_GPL(iscsi_session_teardown); | 1450 | EXPORT_SYMBOL_GPL(iscsi_session_teardown); |
1330 | 1451 | ||
@@ -1355,12 +1476,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
1355 | conn->tmabort_state = TMABORT_INITIAL; | 1476 | conn->tmabort_state = TMABORT_INITIAL; |
1356 | INIT_LIST_HEAD(&conn->run_list); | 1477 | INIT_LIST_HEAD(&conn->run_list); |
1357 | INIT_LIST_HEAD(&conn->mgmt_run_list); | 1478 | INIT_LIST_HEAD(&conn->mgmt_run_list); |
1358 | 1479 | INIT_LIST_HEAD(&conn->xmitqueue); | |
1359 | /* initialize general xmit PDU commands queue */ | ||
1360 | conn->xmitqueue = kfifo_alloc(session->cmds_max * sizeof(void*), | ||
1361 | GFP_KERNEL, NULL); | ||
1362 | if (conn->xmitqueue == ERR_PTR(-ENOMEM)) | ||
1363 | goto xmitqueue_alloc_fail; | ||
1364 | 1480 | ||
1365 | /* initialize general immediate & non-immediate PDU commands queue */ | 1481 | /* initialize general immediate & non-immediate PDU commands queue */ |
1366 | conn->immqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*), | 1482 | conn->immqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*), |
@@ -1388,7 +1504,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
1388 | data = kmalloc(DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, GFP_KERNEL); | 1504 | data = kmalloc(DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, GFP_KERNEL); |
1389 | if (!data) | 1505 | if (!data) |
1390 | goto login_mtask_data_alloc_fail; | 1506 | goto login_mtask_data_alloc_fail; |
1391 | conn->login_mtask->data = data; | 1507 | conn->login_mtask->data = conn->data = data; |
1392 | 1508 | ||
1393 | init_timer(&conn->tmabort_timer); | 1509 | init_timer(&conn->tmabort_timer); |
1394 | mutex_init(&conn->xmitmutex); | 1510 | mutex_init(&conn->xmitmutex); |
@@ -1404,8 +1520,6 @@ login_mtask_alloc_fail: | |||
1404 | mgmtqueue_alloc_fail: | 1520 | mgmtqueue_alloc_fail: |
1405 | kfifo_free(conn->immqueue); | 1521 | kfifo_free(conn->immqueue); |
1406 | immqueue_alloc_fail: | 1522 | immqueue_alloc_fail: |
1407 | kfifo_free(conn->xmitqueue); | ||
1408 | xmitqueue_alloc_fail: | ||
1409 | iscsi_destroy_conn(cls_conn); | 1523 | iscsi_destroy_conn(cls_conn); |
1410 | return NULL; | 1524 | return NULL; |
1411 | } | 1525 | } |
@@ -1426,12 +1540,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) | |||
1426 | 1540 | ||
1427 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | 1541 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); |
1428 | mutex_lock(&conn->xmitmutex); | 1542 | mutex_lock(&conn->xmitmutex); |
1429 | if (conn->c_stage == ISCSI_CONN_INITIAL_STAGE) { | ||
1430 | if (session->tt->suspend_conn_recv) | ||
1431 | session->tt->suspend_conn_recv(conn); | ||
1432 | |||
1433 | session->tt->terminate_conn(conn); | ||
1434 | } | ||
1435 | 1543 | ||
1436 | spin_lock_bh(&session->lock); | 1544 | spin_lock_bh(&session->lock); |
1437 | conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; | 1545 | conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; |
@@ -1468,7 +1576,8 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) | |||
1468 | } | 1576 | } |
1469 | 1577 | ||
1470 | spin_lock_bh(&session->lock); | 1578 | spin_lock_bh(&session->lock); |
1471 | kfree(conn->login_mtask->data); | 1579 | kfree(conn->data); |
1580 | kfree(conn->persistent_address); | ||
1472 | __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, | 1581 | __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, |
1473 | sizeof(void*)); | 1582 | sizeof(void*)); |
1474 | list_del(&conn->item); | 1583 | list_del(&conn->item); |
@@ -1483,7 +1592,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) | |||
1483 | session->cmdsn = session->max_cmdsn = session->exp_cmdsn = 1; | 1592 | session->cmdsn = session->max_cmdsn = session->exp_cmdsn = 1; |
1484 | spin_unlock_bh(&session->lock); | 1593 | spin_unlock_bh(&session->lock); |
1485 | 1594 | ||
1486 | kfifo_free(conn->xmitqueue); | ||
1487 | kfifo_free(conn->immqueue); | 1595 | kfifo_free(conn->immqueue); |
1488 | kfifo_free(conn->mgmtqueue); | 1596 | kfifo_free(conn->mgmtqueue); |
1489 | 1597 | ||
@@ -1496,11 +1604,19 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) | |||
1496 | struct iscsi_conn *conn = cls_conn->dd_data; | 1604 | struct iscsi_conn *conn = cls_conn->dd_data; |
1497 | struct iscsi_session *session = conn->session; | 1605 | struct iscsi_session *session = conn->session; |
1498 | 1606 | ||
1499 | if (session == NULL) { | 1607 | if (!session) { |
1500 | printk(KERN_ERR "iscsi: can't start unbound connection\n"); | 1608 | printk(KERN_ERR "iscsi: can't start unbound connection\n"); |
1501 | return -EPERM; | 1609 | return -EPERM; |
1502 | } | 1610 | } |
1503 | 1611 | ||
1612 | if ((session->imm_data_en || !session->initial_r2t_en) && | ||
1613 | session->first_burst > session->max_burst) { | ||
1614 | printk("iscsi: invalid burst lengths: " | ||
1615 | "first_burst %d max_burst %d\n", | ||
1616 | session->first_burst, session->max_burst); | ||
1617 | return -EINVAL; | ||
1618 | } | ||
1619 | |||
1504 | spin_lock_bh(&session->lock); | 1620 | spin_lock_bh(&session->lock); |
1505 | conn->c_stage = ISCSI_CONN_STARTED; | 1621 | conn->c_stage = ISCSI_CONN_STARTED; |
1506 | session->state = ISCSI_STATE_LOGGED_IN; | 1622 | session->state = ISCSI_STATE_LOGGED_IN; |
@@ -1566,7 +1682,7 @@ static void fail_all_commands(struct iscsi_conn *conn) | |||
1566 | struct iscsi_cmd_task *ctask, *tmp; | 1682 | struct iscsi_cmd_task *ctask, *tmp; |
1567 | 1683 | ||
1568 | /* flush pending */ | 1684 | /* flush pending */ |
1569 | while (__kfifo_get(conn->xmitqueue, (void*)&ctask, sizeof(void*))) { | 1685 | list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) { |
1570 | debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc, | 1686 | debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc, |
1571 | ctask->itt); | 1687 | ctask->itt); |
1572 | fail_command(conn, ctask, DID_BUS_BUSY << 16); | 1688 | fail_command(conn, ctask, DID_BUS_BUSY << 16); |
@@ -1609,8 +1725,9 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, | |||
1609 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | 1725 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); |
1610 | spin_unlock_bh(&session->lock); | 1726 | spin_unlock_bh(&session->lock); |
1611 | 1727 | ||
1612 | if (session->tt->suspend_conn_recv) | 1728 | write_lock_bh(conn->recv_lock); |
1613 | session->tt->suspend_conn_recv(conn); | 1729 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); |
1730 | write_unlock_bh(conn->recv_lock); | ||
1614 | 1731 | ||
1615 | mutex_lock(&conn->xmitmutex); | 1732 | mutex_lock(&conn->xmitmutex); |
1616 | /* | 1733 | /* |
@@ -1629,7 +1746,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, | |||
1629 | } | 1746 | } |
1630 | } | 1747 | } |
1631 | 1748 | ||
1632 | session->tt->terminate_conn(conn); | ||
1633 | /* | 1749 | /* |
1634 | * flush queues. | 1750 | * flush queues. |
1635 | */ | 1751 | */ |
@@ -1697,6 +1813,185 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session, | |||
1697 | } | 1813 | } |
1698 | EXPORT_SYMBOL_GPL(iscsi_conn_bind); | 1814 | EXPORT_SYMBOL_GPL(iscsi_conn_bind); |
1699 | 1815 | ||
1816 | |||
1817 | int iscsi_set_param(struct iscsi_cls_conn *cls_conn, | ||
1818 | enum iscsi_param param, char *buf, int buflen) | ||
1819 | { | ||
1820 | struct iscsi_conn *conn = cls_conn->dd_data; | ||
1821 | struct iscsi_session *session = conn->session; | ||
1822 | uint32_t value; | ||
1823 | |||
1824 | switch(param) { | ||
1825 | case ISCSI_PARAM_MAX_RECV_DLENGTH: | ||
1826 | sscanf(buf, "%d", &conn->max_recv_dlength); | ||
1827 | break; | ||
1828 | case ISCSI_PARAM_MAX_XMIT_DLENGTH: | ||
1829 | sscanf(buf, "%d", &conn->max_xmit_dlength); | ||
1830 | break; | ||
1831 | case ISCSI_PARAM_HDRDGST_EN: | ||
1832 | sscanf(buf, "%d", &conn->hdrdgst_en); | ||
1833 | break; | ||
1834 | case ISCSI_PARAM_DATADGST_EN: | ||
1835 | sscanf(buf, "%d", &conn->datadgst_en); | ||
1836 | break; | ||
1837 | case ISCSI_PARAM_INITIAL_R2T_EN: | ||
1838 | sscanf(buf, "%d", &session->initial_r2t_en); | ||
1839 | break; | ||
1840 | case ISCSI_PARAM_MAX_R2T: | ||
1841 | sscanf(buf, "%d", &session->max_r2t); | ||
1842 | break; | ||
1843 | case ISCSI_PARAM_IMM_DATA_EN: | ||
1844 | sscanf(buf, "%d", &session->imm_data_en); | ||
1845 | break; | ||
1846 | case ISCSI_PARAM_FIRST_BURST: | ||
1847 | sscanf(buf, "%d", &session->first_burst); | ||
1848 | break; | ||
1849 | case ISCSI_PARAM_MAX_BURST: | ||
1850 | sscanf(buf, "%d", &session->max_burst); | ||
1851 | break; | ||
1852 | case ISCSI_PARAM_PDU_INORDER_EN: | ||
1853 | sscanf(buf, "%d", &session->pdu_inorder_en); | ||
1854 | break; | ||
1855 | case ISCSI_PARAM_DATASEQ_INORDER_EN: | ||
1856 | sscanf(buf, "%d", &session->dataseq_inorder_en); | ||
1857 | break; | ||
1858 | case ISCSI_PARAM_ERL: | ||
1859 | sscanf(buf, "%d", &session->erl); | ||
1860 | break; | ||
1861 | case ISCSI_PARAM_IFMARKER_EN: | ||
1862 | sscanf(buf, "%d", &value); | ||
1863 | BUG_ON(value); | ||
1864 | break; | ||
1865 | case ISCSI_PARAM_OFMARKER_EN: | ||
1866 | sscanf(buf, "%d", &value); | ||
1867 | BUG_ON(value); | ||
1868 | break; | ||
1869 | case ISCSI_PARAM_EXP_STATSN: | ||
1870 | sscanf(buf, "%u", &conn->exp_statsn); | ||
1871 | break; | ||
1872 | case ISCSI_PARAM_TARGET_NAME: | ||
1873 | /* this should not change between logins */ | ||
1874 | if (session->targetname) | ||
1875 | break; | ||
1876 | |||
1877 | session->targetname = kstrdup(buf, GFP_KERNEL); | ||
1878 | if (!session->targetname) | ||
1879 | return -ENOMEM; | ||
1880 | break; | ||
1881 | case ISCSI_PARAM_TPGT: | ||
1882 | sscanf(buf, "%d", &session->tpgt); | ||
1883 | break; | ||
1884 | case ISCSI_PARAM_PERSISTENT_PORT: | ||
1885 | sscanf(buf, "%d", &conn->persistent_port); | ||
1886 | break; | ||
1887 | case ISCSI_PARAM_PERSISTENT_ADDRESS: | ||
1888 | /* | ||
1889 | * this is the address returned in discovery so it should | ||
1890 | * not change between logins. | ||
1891 | */ | ||
1892 | if (conn->persistent_address) | ||
1893 | break; | ||
1894 | |||
1895 | conn->persistent_address = kstrdup(buf, GFP_KERNEL); | ||
1896 | if (!conn->persistent_address) | ||
1897 | return -ENOMEM; | ||
1898 | break; | ||
1899 | default: | ||
1900 | return -ENOSYS; | ||
1901 | } | ||
1902 | |||
1903 | return 0; | ||
1904 | } | ||
1905 | EXPORT_SYMBOL_GPL(iscsi_set_param); | ||
1906 | |||
1907 | int iscsi_session_get_param(struct iscsi_cls_session *cls_session, | ||
1908 | enum iscsi_param param, char *buf) | ||
1909 | { | ||
1910 | struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); | ||
1911 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); | ||
1912 | int len; | ||
1913 | |||
1914 | switch(param) { | ||
1915 | case ISCSI_PARAM_INITIAL_R2T_EN: | ||
1916 | len = sprintf(buf, "%d\n", session->initial_r2t_en); | ||
1917 | break; | ||
1918 | case ISCSI_PARAM_MAX_R2T: | ||
1919 | len = sprintf(buf, "%hu\n", session->max_r2t); | ||
1920 | break; | ||
1921 | case ISCSI_PARAM_IMM_DATA_EN: | ||
1922 | len = sprintf(buf, "%d\n", session->imm_data_en); | ||
1923 | break; | ||
1924 | case ISCSI_PARAM_FIRST_BURST: | ||
1925 | len = sprintf(buf, "%u\n", session->first_burst); | ||
1926 | break; | ||
1927 | case ISCSI_PARAM_MAX_BURST: | ||
1928 | len = sprintf(buf, "%u\n", session->max_burst); | ||
1929 | break; | ||
1930 | case ISCSI_PARAM_PDU_INORDER_EN: | ||
1931 | len = sprintf(buf, "%d\n", session->pdu_inorder_en); | ||
1932 | break; | ||
1933 | case ISCSI_PARAM_DATASEQ_INORDER_EN: | ||
1934 | len = sprintf(buf, "%d\n", session->dataseq_inorder_en); | ||
1935 | break; | ||
1936 | case ISCSI_PARAM_ERL: | ||
1937 | len = sprintf(buf, "%d\n", session->erl); | ||
1938 | break; | ||
1939 | case ISCSI_PARAM_TARGET_NAME: | ||
1940 | len = sprintf(buf, "%s\n", session->targetname); | ||
1941 | break; | ||
1942 | case ISCSI_PARAM_TPGT: | ||
1943 | len = sprintf(buf, "%d\n", session->tpgt); | ||
1944 | break; | ||
1945 | default: | ||
1946 | return -ENOSYS; | ||
1947 | } | ||
1948 | |||
1949 | return len; | ||
1950 | } | ||
1951 | EXPORT_SYMBOL_GPL(iscsi_session_get_param); | ||
1952 | |||
1953 | int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, | ||
1954 | enum iscsi_param param, char *buf) | ||
1955 | { | ||
1956 | struct iscsi_conn *conn = cls_conn->dd_data; | ||
1957 | int len; | ||
1958 | |||
1959 | switch(param) { | ||
1960 | case ISCSI_PARAM_MAX_RECV_DLENGTH: | ||
1961 | len = sprintf(buf, "%u\n", conn->max_recv_dlength); | ||
1962 | break; | ||
1963 | case ISCSI_PARAM_MAX_XMIT_DLENGTH: | ||
1964 | len = sprintf(buf, "%u\n", conn->max_xmit_dlength); | ||
1965 | break; | ||
1966 | case ISCSI_PARAM_HDRDGST_EN: | ||
1967 | len = sprintf(buf, "%d\n", conn->hdrdgst_en); | ||
1968 | break; | ||
1969 | case ISCSI_PARAM_DATADGST_EN: | ||
1970 | len = sprintf(buf, "%d\n", conn->datadgst_en); | ||
1971 | break; | ||
1972 | case ISCSI_PARAM_IFMARKER_EN: | ||
1973 | len = sprintf(buf, "%d\n", conn->ifmarker_en); | ||
1974 | break; | ||
1975 | case ISCSI_PARAM_OFMARKER_EN: | ||
1976 | len = sprintf(buf, "%d\n", conn->ofmarker_en); | ||
1977 | break; | ||
1978 | case ISCSI_PARAM_EXP_STATSN: | ||
1979 | len = sprintf(buf, "%u\n", conn->exp_statsn); | ||
1980 | break; | ||
1981 | case ISCSI_PARAM_PERSISTENT_PORT: | ||
1982 | len = sprintf(buf, "%d\n", conn->persistent_port); | ||
1983 | break; | ||
1984 | case ISCSI_PARAM_PERSISTENT_ADDRESS: | ||
1985 | len = sprintf(buf, "%s\n", conn->persistent_address); | ||
1986 | break; | ||
1987 | default: | ||
1988 | return -ENOSYS; | ||
1989 | } | ||
1990 | |||
1991 | return len; | ||
1992 | } | ||
1993 | EXPORT_SYMBOL_GPL(iscsi_conn_get_param); | ||
1994 | |||
1700 | MODULE_AUTHOR("Mike Christie"); | 1995 | MODULE_AUTHOR("Mike Christie"); |
1701 | MODULE_DESCRIPTION("iSCSI library functions"); | 1996 | MODULE_DESCRIPTION("iSCSI library functions"); |
1702 | MODULE_LICENSE("GPL"); | 1997 | MODULE_LICENSE("GPL"); |