diff options
author | Mike Christie <michaelc@cs.wisc.edu> | 2009-05-13 18:57:49 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-05-23 16:44:13 -0400 |
commit | b3cd5050bf8eb32ceecee129cac7c59e6f1668c4 (patch) | |
tree | 5aa4999dd1c5c7fe83354f3965764f0849afaff3 /drivers/scsi/libiscsi.c | |
parent | 1336aed10b8af791378b017f0fa8da4e5b827b8d (diff) |
[SCSI] libiscsi: add task aborted state
If a task did not complete normally due to a TMF, libiscsi will
now complete the task with the state ISCSI_TASK_ABRT_TMF. Drivers
like bnx2i that need to free resources if a command did not complete normally
can then check the task state. If a driver does not need to send
a special command if we have dropped the session then they can check
for ISCSI_TASK_ABRT_SESS_RECOV.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/libiscsi.c')
-rw-r--r-- | drivers/scsi/libiscsi.c | 60 |
1 files changed, 35 insertions, 25 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index dafa054537f6..b00be6c3efc1 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -443,18 +443,20 @@ EXPORT_SYMBOL_GPL(iscsi_put_task); | |||
443 | /** | 443 | /** |
444 | * iscsi_complete_task - finish a task | 444 | * iscsi_complete_task - finish a task |
445 | * @task: iscsi cmd task | 445 | * @task: iscsi cmd task |
446 | * @state: state to complete task with | ||
446 | * | 447 | * |
447 | * Must be called with session lock. | 448 | * Must be called with session lock. |
448 | */ | 449 | */ |
449 | static void iscsi_complete_task(struct iscsi_task *task) | 450 | static void iscsi_complete_task(struct iscsi_task *task, int state) |
450 | { | 451 | { |
451 | struct iscsi_conn *conn = task->conn; | 452 | struct iscsi_conn *conn = task->conn; |
452 | 453 | ||
453 | if (task->state == ISCSI_TASK_COMPLETED) | 454 | if (task->state == ISCSI_TASK_COMPLETED || |
455 | task->state == ISCSI_TASK_ABRT_TMF || | ||
456 | task->state == ISCSI_TASK_ABRT_SESS_RECOV) | ||
454 | return; | 457 | return; |
455 | WARN_ON_ONCE(task->state == ISCSI_TASK_FREE); | 458 | WARN_ON_ONCE(task->state == ISCSI_TASK_FREE); |
456 | 459 | task->state = state; | |
457 | task->state = ISCSI_TASK_COMPLETED; | ||
458 | 460 | ||
459 | if (!list_empty(&task->running)) | 461 | if (!list_empty(&task->running)) |
460 | list_del_init(&task->running); | 462 | list_del_init(&task->running); |
@@ -478,6 +480,7 @@ static void fail_scsi_task(struct iscsi_task *task, int err) | |||
478 | { | 480 | { |
479 | struct iscsi_conn *conn = task->conn; | 481 | struct iscsi_conn *conn = task->conn; |
480 | struct scsi_cmnd *sc; | 482 | struct scsi_cmnd *sc; |
483 | int state; | ||
481 | 484 | ||
482 | /* | 485 | /* |
483 | * if a command completes and we get a successful tmf response | 486 | * if a command completes and we get a successful tmf response |
@@ -488,14 +491,20 @@ static void fail_scsi_task(struct iscsi_task *task, int err) | |||
488 | if (!sc) | 491 | if (!sc) |
489 | return; | 492 | return; |
490 | 493 | ||
491 | if (task->state == ISCSI_TASK_PENDING) | 494 | if (task->state == ISCSI_TASK_PENDING) { |
492 | /* | 495 | /* |
493 | * cmd never made it to the xmit thread, so we should not count | 496 | * cmd never made it to the xmit thread, so we should not count |
494 | * the cmd in the sequencing | 497 | * the cmd in the sequencing |
495 | */ | 498 | */ |
496 | conn->session->queued_cmdsn--; | 499 | conn->session->queued_cmdsn--; |
500 | /* it was never sent so just complete like normal */ | ||
501 | state = ISCSI_TASK_COMPLETED; | ||
502 | } else if (err == DID_TRANSPORT_DISRUPTED) | ||
503 | state = ISCSI_TASK_ABRT_SESS_RECOV; | ||
504 | else | ||
505 | state = ISCSI_TASK_ABRT_TMF; | ||
497 | 506 | ||
498 | sc->result = err; | 507 | sc->result = err << 16; |
499 | if (!scsi_bidi_cmnd(sc)) | 508 | if (!scsi_bidi_cmnd(sc)) |
500 | scsi_set_resid(sc, scsi_bufflen(sc)); | 509 | scsi_set_resid(sc, scsi_bufflen(sc)); |
501 | else { | 510 | else { |
@@ -503,7 +512,7 @@ static void fail_scsi_task(struct iscsi_task *task, int err) | |||
503 | scsi_in(sc)->resid = scsi_in(sc)->length; | 512 | scsi_in(sc)->resid = scsi_in(sc)->length; |
504 | } | 513 | } |
505 | 514 | ||
506 | iscsi_complete_task(task); | 515 | iscsi_complete_task(task, state); |
507 | } | 516 | } |
508 | 517 | ||
509 | static int iscsi_prep_mgmt_task(struct iscsi_conn *conn, | 518 | static int iscsi_prep_mgmt_task(struct iscsi_conn *conn, |
@@ -731,7 +740,7 @@ out: | |||
731 | ISCSI_DBG_SESSION(session, "cmd rsp done [sc %p res %d itt 0x%x]\n", | 740 | ISCSI_DBG_SESSION(session, "cmd rsp done [sc %p res %d itt 0x%x]\n", |
732 | sc, sc->result, task->itt); | 741 | sc, sc->result, task->itt); |
733 | conn->scsirsp_pdus_cnt++; | 742 | conn->scsirsp_pdus_cnt++; |
734 | iscsi_complete_task(task); | 743 | iscsi_complete_task(task, ISCSI_TASK_COMPLETED); |
735 | } | 744 | } |
736 | 745 | ||
737 | /** | 746 | /** |
@@ -769,7 +778,7 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
769 | "[sc %p res %d itt 0x%x]\n", | 778 | "[sc %p res %d itt 0x%x]\n", |
770 | sc, sc->result, task->itt); | 779 | sc, sc->result, task->itt); |
771 | conn->scsirsp_pdus_cnt++; | 780 | conn->scsirsp_pdus_cnt++; |
772 | iscsi_complete_task(task); | 781 | iscsi_complete_task(task, ISCSI_TASK_COMPLETED); |
773 | } | 782 | } |
774 | 783 | ||
775 | static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | 784 | static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) |
@@ -990,7 +999,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
990 | } | 999 | } |
991 | 1000 | ||
992 | iscsi_tmf_rsp(conn, hdr); | 1001 | iscsi_tmf_rsp(conn, hdr); |
993 | iscsi_complete_task(task); | 1002 | iscsi_complete_task(task, ISCSI_TASK_COMPLETED); |
994 | break; | 1003 | break; |
995 | case ISCSI_OP_NOOP_IN: | 1004 | case ISCSI_OP_NOOP_IN: |
996 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); | 1005 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); |
@@ -1008,7 +1017,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
1008 | goto recv_pdu; | 1017 | goto recv_pdu; |
1009 | 1018 | ||
1010 | mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout); | 1019 | mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout); |
1011 | iscsi_complete_task(task); | 1020 | iscsi_complete_task(task, ISCSI_TASK_COMPLETED); |
1012 | break; | 1021 | break; |
1013 | default: | 1022 | default: |
1014 | rc = ISCSI_ERR_BAD_OPCODE; | 1023 | rc = ISCSI_ERR_BAD_OPCODE; |
@@ -1020,7 +1029,7 @@ out: | |||
1020 | recv_pdu: | 1029 | recv_pdu: |
1021 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) | 1030 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) |
1022 | rc = ISCSI_ERR_CONN_FAILED; | 1031 | rc = ISCSI_ERR_CONN_FAILED; |
1023 | iscsi_complete_task(task); | 1032 | iscsi_complete_task(task, ISCSI_TASK_COMPLETED); |
1024 | return rc; | 1033 | return rc; |
1025 | } | 1034 | } |
1026 | EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); | 1035 | EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); |
@@ -1262,7 +1271,7 @@ check_mgmt: | |||
1262 | struct iscsi_task, running); | 1271 | struct iscsi_task, running); |
1263 | list_del_init(&conn->task->running); | 1272 | list_del_init(&conn->task->running); |
1264 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { | 1273 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { |
1265 | fail_scsi_task(conn->task, DID_IMM_RETRY << 16); | 1274 | fail_scsi_task(conn->task, DID_IMM_RETRY); |
1266 | continue; | 1275 | continue; |
1267 | } | 1276 | } |
1268 | rc = iscsi_prep_scsi_cmd_pdu(conn->task); | 1277 | rc = iscsi_prep_scsi_cmd_pdu(conn->task); |
@@ -1273,7 +1282,7 @@ check_mgmt: | |||
1273 | conn->task = NULL; | 1282 | conn->task = NULL; |
1274 | goto again; | 1283 | goto again; |
1275 | } else | 1284 | } else |
1276 | fail_scsi_task(conn->task, DID_ABORT << 16); | 1285 | fail_scsi_task(conn->task, DID_ABORT); |
1277 | continue; | 1286 | continue; |
1278 | } | 1287 | } |
1279 | rc = iscsi_xmit_task(conn); | 1288 | rc = iscsi_xmit_task(conn); |
@@ -1469,7 +1478,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
1469 | 1478 | ||
1470 | prepd_reject: | 1479 | prepd_reject: |
1471 | sc->scsi_done = NULL; | 1480 | sc->scsi_done = NULL; |
1472 | iscsi_complete_task(task); | 1481 | iscsi_complete_task(task, ISCSI_TASK_COMPLETED); |
1473 | reject: | 1482 | reject: |
1474 | spin_unlock(&session->lock); | 1483 | spin_unlock(&session->lock); |
1475 | ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n", | 1484 | ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n", |
@@ -1479,7 +1488,7 @@ reject: | |||
1479 | 1488 | ||
1480 | prepd_fault: | 1489 | prepd_fault: |
1481 | sc->scsi_done = NULL; | 1490 | sc->scsi_done = NULL; |
1482 | iscsi_complete_task(task); | 1491 | iscsi_complete_task(task, ISCSI_TASK_COMPLETED); |
1483 | fault: | 1492 | fault: |
1484 | spin_unlock(&session->lock); | 1493 | spin_unlock(&session->lock); |
1485 | ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n", | 1494 | ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n", |
@@ -1665,7 +1674,7 @@ static void fail_scsi_tasks(struct iscsi_conn *conn, unsigned lun, | |||
1665 | ISCSI_DBG_SESSION(conn->session, | 1674 | ISCSI_DBG_SESSION(conn->session, |
1666 | "failing sc %p itt 0x%x state %d\n", | 1675 | "failing sc %p itt 0x%x state %d\n", |
1667 | task->sc, task->itt, task->state); | 1676 | task->sc, task->itt, task->state); |
1668 | fail_scsi_task(task, error << 16); | 1677 | fail_scsi_task(task, error); |
1669 | } | 1678 | } |
1670 | } | 1679 | } |
1671 | 1680 | ||
@@ -1868,7 +1877,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1868 | } | 1877 | } |
1869 | 1878 | ||
1870 | if (task->state == ISCSI_TASK_PENDING) { | 1879 | if (task->state == ISCSI_TASK_PENDING) { |
1871 | fail_scsi_task(task, DID_ABORT << 16); | 1880 | fail_scsi_task(task, DID_ABORT); |
1872 | goto success; | 1881 | goto success; |
1873 | } | 1882 | } |
1874 | 1883 | ||
@@ -1899,7 +1908,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1899 | * then sent more data for the cmd. | 1908 | * then sent more data for the cmd. |
1900 | */ | 1909 | */ |
1901 | spin_lock(&session->lock); | 1910 | spin_lock(&session->lock); |
1902 | fail_scsi_task(task, DID_ABORT << 16); | 1911 | fail_scsi_task(task, DID_ABORT); |
1903 | conn->tmf_state = TMF_INITIAL; | 1912 | conn->tmf_state = TMF_INITIAL; |
1904 | spin_unlock(&session->lock); | 1913 | spin_unlock(&session->lock); |
1905 | iscsi_start_tx(conn); | 1914 | iscsi_start_tx(conn); |
@@ -2572,7 +2581,7 @@ static void | |||
2572 | fail_mgmt_tasks(struct iscsi_session *session, struct iscsi_conn *conn) | 2581 | fail_mgmt_tasks(struct iscsi_session *session, struct iscsi_conn *conn) |
2573 | { | 2582 | { |
2574 | struct iscsi_task *task; | 2583 | struct iscsi_task *task; |
2575 | int i; | 2584 | int i, state; |
2576 | 2585 | ||
2577 | for (i = 0; i < conn->session->cmds_max; i++) { | 2586 | for (i = 0; i < conn->session->cmds_max; i++) { |
2578 | task = conn->session->cmds[i]; | 2587 | task = conn->session->cmds[i]; |
@@ -2585,7 +2594,11 @@ fail_mgmt_tasks(struct iscsi_session *session, struct iscsi_conn *conn) | |||
2585 | ISCSI_DBG_SESSION(conn->session, | 2594 | ISCSI_DBG_SESSION(conn->session, |
2586 | "failing mgmt itt 0x%x state %d\n", | 2595 | "failing mgmt itt 0x%x state %d\n", |
2587 | task->itt, task->state); | 2596 | task->itt, task->state); |
2588 | iscsi_complete_task(task); | 2597 | state = ISCSI_TASK_ABRT_SESS_RECOV; |
2598 | if (task->state == ISCSI_TASK_PENDING) | ||
2599 | state = ISCSI_TASK_COMPLETED; | ||
2600 | iscsi_complete_task(task, state); | ||
2601 | |||
2589 | } | 2602 | } |
2590 | } | 2603 | } |
2591 | 2604 | ||
@@ -2642,10 +2655,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, | |||
2642 | * flush queues. | 2655 | * flush queues. |
2643 | */ | 2656 | */ |
2644 | spin_lock_bh(&session->lock); | 2657 | spin_lock_bh(&session->lock); |
2645 | if (flag == STOP_CONN_RECOVER) | 2658 | fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED); |
2646 | fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED); | ||
2647 | else | ||
2648 | fail_scsi_tasks(conn, -1, DID_ERROR); | ||
2649 | fail_mgmt_tasks(session, conn); | 2659 | fail_mgmt_tasks(session, conn); |
2650 | spin_unlock_bh(&session->lock); | 2660 | spin_unlock_bh(&session->lock); |
2651 | mutex_unlock(&session->eh_mutex); | 2661 | mutex_unlock(&session->eh_mutex); |