diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/libiscsi.c | 59 |
1 files changed, 50 insertions, 9 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index a7c6e70f4ef8..9584cbc082fe 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -179,16 +179,15 @@ EXPORT_SYMBOL_GPL(iscsi_prep_scsi_cmd_pdu); | |||
179 | 179 | ||
180 | /** | 180 | /** |
181 | * iscsi_complete_command - return command back to scsi-ml | 181 | * iscsi_complete_command - return command back to scsi-ml |
182 | * @session: iscsi session | ||
183 | * @ctask: iscsi cmd task | 182 | * @ctask: iscsi cmd task |
184 | * | 183 | * |
185 | * Must be called with session lock. | 184 | * Must be called with session lock. |
186 | * This function returns the scsi command to scsi-ml and returns | 185 | * This function returns the scsi command to scsi-ml and returns |
187 | * the cmd task to the pool of available cmd tasks. | 186 | * the cmd task to the pool of available cmd tasks. |
188 | */ | 187 | */ |
189 | static void iscsi_complete_command(struct iscsi_session *session, | 188 | static void iscsi_complete_command(struct iscsi_cmd_task *ctask) |
190 | struct iscsi_cmd_task *ctask) | ||
191 | { | 189 | { |
190 | struct iscsi_session *session = ctask->conn->session; | ||
192 | struct scsi_cmnd *sc = ctask->sc; | 191 | struct scsi_cmnd *sc = ctask->sc; |
193 | 192 | ||
194 | ctask->state = ISCSI_TASK_COMPLETED; | 193 | ctask->state = ISCSI_TASK_COMPLETED; |
@@ -198,6 +197,35 @@ static void iscsi_complete_command(struct iscsi_session *session, | |||
198 | sc->scsi_done(sc); | 197 | sc->scsi_done(sc); |
199 | } | 198 | } |
200 | 199 | ||
200 | static void __iscsi_get_ctask(struct iscsi_cmd_task *ctask) | ||
201 | { | ||
202 | atomic_inc(&ctask->refcount); | ||
203 | } | ||
204 | |||
205 | static void iscsi_get_ctask(struct iscsi_cmd_task *ctask) | ||
206 | { | ||
207 | spin_lock_bh(&ctask->conn->session->lock); | ||
208 | __iscsi_get_ctask(ctask); | ||
209 | spin_unlock_bh(&ctask->conn->session->lock); | ||
210 | } | ||
211 | |||
212 | static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask) | ||
213 | { | ||
214 | struct iscsi_conn *conn = ctask->conn; | ||
215 | |||
216 | if (atomic_dec_and_test(&ctask->refcount)) { | ||
217 | conn->session->tt->cleanup_cmd_task(conn, ctask); | ||
218 | iscsi_complete_command(ctask); | ||
219 | } | ||
220 | } | ||
221 | |||
222 | static void iscsi_put_ctask(struct iscsi_cmd_task *ctask) | ||
223 | { | ||
224 | spin_lock_bh(&ctask->conn->session->lock); | ||
225 | __iscsi_put_ctask(ctask); | ||
226 | spin_unlock_bh(&ctask->conn->session->lock); | ||
227 | } | ||
228 | |||
201 | /** | 229 | /** |
202 | * iscsi_cmd_rsp - SCSI Command Response processing | 230 | * iscsi_cmd_rsp - SCSI Command Response processing |
203 | * @conn: iscsi connection | 231 | * @conn: iscsi connection |
@@ -274,7 +302,7 @@ out: | |||
274 | (long)sc, sc->result, ctask->itt); | 302 | (long)sc, sc->result, ctask->itt); |
275 | conn->scsirsp_pdus_cnt++; | 303 | conn->scsirsp_pdus_cnt++; |
276 | 304 | ||
277 | iscsi_complete_command(conn->session, ctask); | 305 | __iscsi_put_ctask(ctask); |
278 | return rc; | 306 | return rc; |
279 | } | 307 | } |
280 | 308 | ||
@@ -338,7 +366,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
338 | BUG_ON((void*)ctask != ctask->sc->SCp.ptr); | 366 | BUG_ON((void*)ctask != ctask->sc->SCp.ptr); |
339 | if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { | 367 | if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { |
340 | conn->scsirsp_pdus_cnt++; | 368 | conn->scsirsp_pdus_cnt++; |
341 | iscsi_complete_command(session, ctask); | 369 | __iscsi_put_ctask(ctask); |
342 | } | 370 | } |
343 | break; | 371 | break; |
344 | case ISCSI_OP_R2T: | 372 | case ISCSI_OP_R2T: |
@@ -563,7 +591,9 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
563 | BUG_ON(conn->ctask && conn->mtask); | 591 | BUG_ON(conn->ctask && conn->mtask); |
564 | 592 | ||
565 | if (conn->ctask) { | 593 | if (conn->ctask) { |
594 | iscsi_get_ctask(conn->ctask); | ||
566 | rc = tt->xmit_cmd_task(conn, conn->ctask); | 595 | rc = tt->xmit_cmd_task(conn, conn->ctask); |
596 | iscsi_put_ctask(conn->ctask); | ||
567 | if (rc) | 597 | if (rc) |
568 | goto again; | 598 | goto again; |
569 | /* done with this in-progress ctask */ | 599 | /* done with this in-progress ctask */ |
@@ -604,12 +634,19 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
604 | struct iscsi_cmd_task, running); | 634 | struct iscsi_cmd_task, running); |
605 | conn->ctask->state = ISCSI_TASK_RUNNING; | 635 | conn->ctask->state = ISCSI_TASK_RUNNING; |
606 | list_move_tail(conn->xmitqueue.next, &conn->run_list); | 636 | list_move_tail(conn->xmitqueue.next, &conn->run_list); |
637 | __iscsi_get_ctask(conn->ctask); | ||
607 | spin_unlock_bh(&conn->session->lock); | 638 | spin_unlock_bh(&conn->session->lock); |
608 | 639 | ||
609 | rc = tt->xmit_cmd_task(conn, conn->ctask); | 640 | rc = tt->xmit_cmd_task(conn, conn->ctask); |
610 | if (rc) | 641 | if (rc) |
611 | goto again; | 642 | goto again; |
643 | |||
612 | spin_lock_bh(&conn->session->lock); | 644 | spin_lock_bh(&conn->session->lock); |
645 | __iscsi_put_ctask(conn->ctask); | ||
646 | if (rc) { | ||
647 | spin_unlock_bh(&conn->session->lock); | ||
648 | goto again; | ||
649 | } | ||
613 | } | 650 | } |
614 | spin_unlock_bh(&conn->session->lock); | 651 | spin_unlock_bh(&conn->session->lock); |
615 | /* done with this ctask */ | 652 | /* done with this ctask */ |
@@ -659,6 +696,7 @@ enum { | |||
659 | FAILURE_SESSION_FAILED, | 696 | FAILURE_SESSION_FAILED, |
660 | FAILURE_SESSION_FREED, | 697 | FAILURE_SESSION_FREED, |
661 | FAILURE_WINDOW_CLOSED, | 698 | FAILURE_WINDOW_CLOSED, |
699 | FAILURE_OOM, | ||
662 | FAILURE_SESSION_TERMINATE, | 700 | FAILURE_SESSION_TERMINATE, |
663 | FAILURE_SESSION_IN_RECOVERY, | 701 | FAILURE_SESSION_IN_RECOVERY, |
664 | FAILURE_SESSION_RECOVERY_TIMEOUT, | 702 | FAILURE_SESSION_RECOVERY_TIMEOUT, |
@@ -717,10 +755,15 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
717 | 755 | ||
718 | conn = session->leadconn; | 756 | conn = session->leadconn; |
719 | 757 | ||
720 | __kfifo_get(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); | 758 | if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask, |
759 | sizeof(void*))) { | ||
760 | reason = FAILURE_OOM; | ||
761 | goto reject; | ||
762 | } | ||
721 | sc->SCp.phase = session->age; | 763 | sc->SCp.phase = session->age; |
722 | sc->SCp.ptr = (char *)ctask; | 764 | sc->SCp.ptr = (char *)ctask; |
723 | 765 | ||
766 | atomic_set(&ctask->refcount, 1); | ||
724 | ctask->state = ISCSI_TASK_PENDING; | 767 | ctask->state = ISCSI_TASK_PENDING; |
725 | ctask->mtask = NULL; | 768 | ctask->mtask = NULL; |
726 | ctask->conn = conn; | 769 | ctask->conn = conn; |
@@ -1057,13 +1100,11 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
1057 | sc = ctask->sc; | 1100 | sc = ctask->sc; |
1058 | if (!sc) | 1101 | if (!sc) |
1059 | return; | 1102 | return; |
1060 | |||
1061 | conn->session->tt->cleanup_cmd_task(conn, ctask); | ||
1062 | iscsi_ctask_mtask_cleanup(ctask); | 1103 | iscsi_ctask_mtask_cleanup(ctask); |
1063 | 1104 | ||
1064 | sc->result = err; | 1105 | sc->result = err; |
1065 | sc->resid = sc->request_bufflen; | 1106 | sc->resid = sc->request_bufflen; |
1066 | iscsi_complete_command(conn->session, ctask); | 1107 | __iscsi_put_ctask(ctask); |
1067 | } | 1108 | } |
1068 | 1109 | ||
1069 | int iscsi_eh_abort(struct scsi_cmnd *sc) | 1110 | int iscsi_eh_abort(struct scsi_cmnd *sc) |