diff options
Diffstat (limited to 'drivers/scsi/libiscsi.c')
-rw-r--r-- | drivers/scsi/libiscsi.c | 389 |
1 files changed, 303 insertions, 86 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index f1a4246f890c..b7689f3d05f5 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -266,6 +266,88 @@ static int iscsi_prep_bidi_ahs(struct iscsi_task *task) | |||
266 | } | 266 | } |
267 | 267 | ||
268 | /** | 268 | /** |
269 | * iscsi_check_tmf_restrictions - check if a task is affected by TMF | ||
270 | * @task: iscsi task | ||
271 | * @opcode: opcode to check for | ||
272 | * | ||
273 | * During TMF a task has to be checked if it's affected. | ||
274 | * All unrelated I/O can be passed through, but I/O to the | ||
275 | * affected LUN should be restricted. | ||
276 | * If 'fast_abort' is set we won't be sending any I/O to the | ||
277 | * affected LUN. | ||
278 | * Otherwise the target is waiting for all TTTs to be completed, | ||
279 | * so we have to send all outstanding Data-Out PDUs to the target. | ||
280 | */ | ||
281 | static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode) | ||
282 | { | ||
283 | struct iscsi_conn *conn = task->conn; | ||
284 | struct iscsi_tm *tmf = &conn->tmhdr; | ||
285 | unsigned int hdr_lun; | ||
286 | |||
287 | if (conn->tmf_state == TMF_INITIAL) | ||
288 | return 0; | ||
289 | |||
290 | if ((tmf->opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_SCSI_TMFUNC) | ||
291 | return 0; | ||
292 | |||
293 | switch (ISCSI_TM_FUNC_VALUE(tmf)) { | ||
294 | case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET: | ||
295 | /* | ||
296 | * Allow PDUs for unrelated LUNs | ||
297 | */ | ||
298 | hdr_lun = scsilun_to_int((struct scsi_lun *)tmf->lun); | ||
299 | if (hdr_lun != task->sc->device->lun) | ||
300 | return 0; | ||
301 | /* fall through */ | ||
302 | case ISCSI_TM_FUNC_TARGET_WARM_RESET: | ||
303 | /* | ||
304 | * Fail all SCSI cmd PDUs | ||
305 | */ | ||
306 | if (opcode != ISCSI_OP_SCSI_DATA_OUT) { | ||
307 | iscsi_conn_printk(KERN_INFO, conn, | ||
308 | "task [op %x/%x itt " | ||
309 | "0x%x/0x%x] " | ||
310 | "rejected.\n", | ||
311 | task->hdr->opcode, opcode, | ||
312 | task->itt, task->hdr_itt); | ||
313 | return -EACCES; | ||
314 | } | ||
315 | /* | ||
316 | * And also all data-out PDUs in response to R2T | ||
317 | * if fast_abort is set. | ||
318 | */ | ||
319 | if (conn->session->fast_abort) { | ||
320 | iscsi_conn_printk(KERN_INFO, conn, | ||
321 | "task [op %x/%x itt " | ||
322 | "0x%x/0x%x] fast abort.\n", | ||
323 | task->hdr->opcode, opcode, | ||
324 | task->itt, task->hdr_itt); | ||
325 | return -EACCES; | ||
326 | } | ||
327 | break; | ||
328 | case ISCSI_TM_FUNC_ABORT_TASK: | ||
329 | /* | ||
330 | * the caller has already checked if the task | ||
331 | * they want to abort was in the pending queue so if | ||
332 | * we are here the cmd pdu has gone out already, and | ||
333 | * we will only hit this for data-outs | ||
334 | */ | ||
335 | if (opcode == ISCSI_OP_SCSI_DATA_OUT && | ||
336 | task->hdr_itt == tmf->rtt) { | ||
337 | ISCSI_DBG_SESSION(conn->session, | ||
338 | "Preventing task %x/%x from sending " | ||
339 | "data-out due to abort task in " | ||
340 | "progress\n", task->itt, | ||
341 | task->hdr_itt); | ||
342 | return -EACCES; | ||
343 | } | ||
344 | break; | ||
345 | } | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | /** | ||
269 | * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu | 351 | * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu |
270 | * @task: iscsi task | 352 | * @task: iscsi task |
271 | * | 353 | * |
@@ -282,6 +364,10 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) | |||
282 | itt_t itt; | 364 | itt_t itt; |
283 | int rc; | 365 | int rc; |
284 | 366 | ||
367 | rc = iscsi_check_tmf_restrictions(task, ISCSI_OP_SCSI_CMD); | ||
368 | if (rc) | ||
369 | return rc; | ||
370 | |||
285 | if (conn->session->tt->alloc_pdu) { | 371 | if (conn->session->tt->alloc_pdu) { |
286 | rc = conn->session->tt->alloc_pdu(task, ISCSI_OP_SCSI_CMD); | 372 | rc = conn->session->tt->alloc_pdu(task, ISCSI_OP_SCSI_CMD); |
287 | if (rc) | 373 | if (rc) |
@@ -577,12 +663,12 @@ static int iscsi_prep_mgmt_task(struct iscsi_conn *conn, | |||
577 | struct iscsi_session *session = conn->session; | 663 | struct iscsi_session *session = conn->session; |
578 | struct iscsi_hdr *hdr = task->hdr; | 664 | struct iscsi_hdr *hdr = task->hdr; |
579 | struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr; | 665 | struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr; |
666 | uint8_t opcode = hdr->opcode & ISCSI_OPCODE_MASK; | ||
580 | 667 | ||
581 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) | 668 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) |
582 | return -ENOTCONN; | 669 | return -ENOTCONN; |
583 | 670 | ||
584 | if (hdr->opcode != (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) && | 671 | if (opcode != ISCSI_OP_LOGIN && opcode != ISCSI_OP_TEXT) |
585 | hdr->opcode != (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) | ||
586 | nop->exp_statsn = cpu_to_be32(conn->exp_statsn); | 672 | nop->exp_statsn = cpu_to_be32(conn->exp_statsn); |
587 | /* | 673 | /* |
588 | * pre-format CmdSN for outgoing PDU. | 674 | * pre-format CmdSN for outgoing PDU. |
@@ -590,9 +676,12 @@ static int iscsi_prep_mgmt_task(struct iscsi_conn *conn, | |||
590 | nop->cmdsn = cpu_to_be32(session->cmdsn); | 676 | nop->cmdsn = cpu_to_be32(session->cmdsn); |
591 | if (hdr->itt != RESERVED_ITT) { | 677 | if (hdr->itt != RESERVED_ITT) { |
592 | /* | 678 | /* |
593 | * TODO: We always use immediate, so we never hit this. | 679 | * TODO: We always use immediate for normal session pdus. |
594 | * If we start to send tmfs or nops as non-immediate then | 680 | * If we start to send tmfs or nops as non-immediate then |
595 | * we should start checking the cmdsn numbers for mgmt tasks. | 681 | * we should start checking the cmdsn numbers for mgmt tasks. |
682 | * | ||
683 | * During discovery sessions iscsid sends TEXT as non immediate, | ||
684 | * but we always only send one PDU at a time. | ||
596 | */ | 685 | */ |
597 | if (conn->c_stage == ISCSI_CONN_STARTED && | 686 | if (conn->c_stage == ISCSI_CONN_STARTED && |
598 | !(hdr->opcode & ISCSI_OP_IMMEDIATE)) { | 687 | !(hdr->opcode & ISCSI_OP_IMMEDIATE)) { |
@@ -620,22 +709,28 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
620 | { | 709 | { |
621 | struct iscsi_session *session = conn->session; | 710 | struct iscsi_session *session = conn->session; |
622 | struct iscsi_host *ihost = shost_priv(session->host); | 711 | struct iscsi_host *ihost = shost_priv(session->host); |
712 | uint8_t opcode = hdr->opcode & ISCSI_OPCODE_MASK; | ||
623 | struct iscsi_task *task; | 713 | struct iscsi_task *task; |
624 | itt_t itt; | 714 | itt_t itt; |
625 | 715 | ||
626 | if (session->state == ISCSI_STATE_TERMINATE) | 716 | if (session->state == ISCSI_STATE_TERMINATE) |
627 | return NULL; | 717 | return NULL; |
628 | 718 | ||
629 | if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) || | 719 | if (opcode == ISCSI_OP_LOGIN || opcode == ISCSI_OP_TEXT) { |
630 | hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) | ||
631 | /* | 720 | /* |
632 | * Login and Text are sent serially, in | 721 | * Login and Text are sent serially, in |
633 | * request-followed-by-response sequence. | 722 | * request-followed-by-response sequence. |
634 | * Same task can be used. Same ITT must be used. | 723 | * Same task can be used. Same ITT must be used. |
635 | * Note that login_task is preallocated at conn_create(). | 724 | * Note that login_task is preallocated at conn_create(). |
636 | */ | 725 | */ |
726 | if (conn->login_task->state != ISCSI_TASK_FREE) { | ||
727 | iscsi_conn_printk(KERN_ERR, conn, "Login/Text in " | ||
728 | "progress. Cannot start new task.\n"); | ||
729 | return NULL; | ||
730 | } | ||
731 | |||
637 | task = conn->login_task; | 732 | task = conn->login_task; |
638 | else { | 733 | } else { |
639 | if (session->state != ISCSI_STATE_LOGGED_IN) | 734 | if (session->state != ISCSI_STATE_LOGGED_IN) |
640 | return NULL; | 735 | return NULL; |
641 | 736 | ||
@@ -1357,6 +1452,7 @@ EXPORT_SYMBOL_GPL(iscsi_requeue_task); | |||
1357 | **/ | 1452 | **/ |
1358 | static int iscsi_data_xmit(struct iscsi_conn *conn) | 1453 | static int iscsi_data_xmit(struct iscsi_conn *conn) |
1359 | { | 1454 | { |
1455 | struct iscsi_task *task; | ||
1360 | int rc = 0; | 1456 | int rc = 0; |
1361 | 1457 | ||
1362 | spin_lock_bh(&conn->session->lock); | 1458 | spin_lock_bh(&conn->session->lock); |
@@ -1394,11 +1490,8 @@ check_mgmt: | |||
1394 | 1490 | ||
1395 | /* process pending command queue */ | 1491 | /* process pending command queue */ |
1396 | while (!list_empty(&conn->cmdqueue)) { | 1492 | while (!list_empty(&conn->cmdqueue)) { |
1397 | if (conn->tmf_state == TMF_QUEUED) | 1493 | conn->task = list_entry(conn->cmdqueue.next, struct iscsi_task, |
1398 | break; | 1494 | running); |
1399 | |||
1400 | conn->task = list_entry(conn->cmdqueue.next, | ||
1401 | struct iscsi_task, running); | ||
1402 | list_del_init(&conn->task->running); | 1495 | list_del_init(&conn->task->running); |
1403 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { | 1496 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { |
1404 | fail_scsi_task(conn->task, DID_IMM_RETRY); | 1497 | fail_scsi_task(conn->task, DID_IMM_RETRY); |
@@ -1406,7 +1499,7 @@ check_mgmt: | |||
1406 | } | 1499 | } |
1407 | rc = iscsi_prep_scsi_cmd_pdu(conn->task); | 1500 | rc = iscsi_prep_scsi_cmd_pdu(conn->task); |
1408 | if (rc) { | 1501 | if (rc) { |
1409 | if (rc == -ENOMEM) { | 1502 | if (rc == -ENOMEM || rc == -EACCES) { |
1410 | list_add_tail(&conn->task->running, | 1503 | list_add_tail(&conn->task->running, |
1411 | &conn->cmdqueue); | 1504 | &conn->cmdqueue); |
1412 | conn->task = NULL; | 1505 | conn->task = NULL; |
@@ -1428,17 +1521,18 @@ check_mgmt: | |||
1428 | } | 1521 | } |
1429 | 1522 | ||
1430 | while (!list_empty(&conn->requeue)) { | 1523 | while (!list_empty(&conn->requeue)) { |
1431 | if (conn->session->fast_abort && conn->tmf_state != TMF_INITIAL) | ||
1432 | break; | ||
1433 | |||
1434 | /* | 1524 | /* |
1435 | * we always do fastlogout - conn stop code will clean up. | 1525 | * we always do fastlogout - conn stop code will clean up. |
1436 | */ | 1526 | */ |
1437 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) | 1527 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) |
1438 | break; | 1528 | break; |
1439 | 1529 | ||
1440 | conn->task = list_entry(conn->requeue.next, | 1530 | task = list_entry(conn->requeue.next, struct iscsi_task, |
1441 | struct iscsi_task, running); | 1531 | running); |
1532 | if (iscsi_check_tmf_restrictions(task, ISCSI_OP_SCSI_DATA_OUT)) | ||
1533 | break; | ||
1534 | |||
1535 | conn->task = task; | ||
1442 | list_del_init(&conn->task->running); | 1536 | list_del_init(&conn->task->running); |
1443 | conn->task->state = ISCSI_TASK_RUNNING; | 1537 | conn->task->state = ISCSI_TASK_RUNNING; |
1444 | rc = iscsi_xmit_task(conn); | 1538 | rc = iscsi_xmit_task(conn); |
@@ -1591,7 +1685,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
1591 | if (!ihost->workq) { | 1685 | if (!ihost->workq) { |
1592 | reason = iscsi_prep_scsi_cmd_pdu(task); | 1686 | reason = iscsi_prep_scsi_cmd_pdu(task); |
1593 | if (reason) { | 1687 | if (reason) { |
1594 | if (reason == -ENOMEM) { | 1688 | if (reason == -ENOMEM || reason == -EACCES) { |
1595 | reason = FAILURE_OOM; | 1689 | reason = FAILURE_OOM; |
1596 | goto prepd_reject; | 1690 | goto prepd_reject; |
1597 | } else { | 1691 | } else { |
@@ -1643,9 +1737,21 @@ fault: | |||
1643 | } | 1737 | } |
1644 | EXPORT_SYMBOL_GPL(iscsi_queuecommand); | 1738 | EXPORT_SYMBOL_GPL(iscsi_queuecommand); |
1645 | 1739 | ||
1646 | int iscsi_change_queue_depth(struct scsi_device *sdev, int depth) | 1740 | int iscsi_change_queue_depth(struct scsi_device *sdev, int depth, int reason) |
1647 | { | 1741 | { |
1648 | scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); | 1742 | switch (reason) { |
1743 | case SCSI_QDEPTH_DEFAULT: | ||
1744 | scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); | ||
1745 | break; | ||
1746 | case SCSI_QDEPTH_QFULL: | ||
1747 | scsi_track_queue_full(sdev, depth); | ||
1748 | break; | ||
1749 | case SCSI_QDEPTH_RAMP_UP: | ||
1750 | scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); | ||
1751 | break; | ||
1752 | default: | ||
1753 | return -EOPNOTSUPP; | ||
1754 | } | ||
1649 | return sdev->queue_depth; | 1755 | return sdev->queue_depth; |
1650 | } | 1756 | } |
1651 | EXPORT_SYMBOL_GPL(iscsi_change_queue_depth); | 1757 | EXPORT_SYMBOL_GPL(iscsi_change_queue_depth); |
@@ -1660,72 +1766,6 @@ int iscsi_target_alloc(struct scsi_target *starget) | |||
1660 | } | 1766 | } |
1661 | EXPORT_SYMBOL_GPL(iscsi_target_alloc); | 1767 | EXPORT_SYMBOL_GPL(iscsi_target_alloc); |
1662 | 1768 | ||
1663 | void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session) | ||
1664 | { | ||
1665 | struct iscsi_session *session = cls_session->dd_data; | ||
1666 | |||
1667 | spin_lock_bh(&session->lock); | ||
1668 | if (session->state != ISCSI_STATE_LOGGED_IN) { | ||
1669 | session->state = ISCSI_STATE_RECOVERY_FAILED; | ||
1670 | if (session->leadconn) | ||
1671 | wake_up(&session->leadconn->ehwait); | ||
1672 | } | ||
1673 | spin_unlock_bh(&session->lock); | ||
1674 | } | ||
1675 | EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout); | ||
1676 | |||
1677 | int iscsi_eh_target_reset(struct scsi_cmnd *sc) | ||
1678 | { | ||
1679 | struct iscsi_cls_session *cls_session; | ||
1680 | struct iscsi_session *session; | ||
1681 | struct iscsi_conn *conn; | ||
1682 | |||
1683 | cls_session = starget_to_session(scsi_target(sc->device)); | ||
1684 | session = cls_session->dd_data; | ||
1685 | conn = session->leadconn; | ||
1686 | |||
1687 | mutex_lock(&session->eh_mutex); | ||
1688 | spin_lock_bh(&session->lock); | ||
1689 | if (session->state == ISCSI_STATE_TERMINATE) { | ||
1690 | failed: | ||
1691 | ISCSI_DBG_EH(session, | ||
1692 | "failing target reset: Could not log back into " | ||
1693 | "target [age %d]\n", | ||
1694 | session->age); | ||
1695 | spin_unlock_bh(&session->lock); | ||
1696 | mutex_unlock(&session->eh_mutex); | ||
1697 | return FAILED; | ||
1698 | } | ||
1699 | |||
1700 | spin_unlock_bh(&session->lock); | ||
1701 | mutex_unlock(&session->eh_mutex); | ||
1702 | /* | ||
1703 | * we drop the lock here but the leadconn cannot be destoyed while | ||
1704 | * we are in the scsi eh | ||
1705 | */ | ||
1706 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | ||
1707 | |||
1708 | ISCSI_DBG_EH(session, "wait for relogin\n"); | ||
1709 | wait_event_interruptible(conn->ehwait, | ||
1710 | session->state == ISCSI_STATE_TERMINATE || | ||
1711 | session->state == ISCSI_STATE_LOGGED_IN || | ||
1712 | session->state == ISCSI_STATE_RECOVERY_FAILED); | ||
1713 | if (signal_pending(current)) | ||
1714 | flush_signals(current); | ||
1715 | |||
1716 | mutex_lock(&session->eh_mutex); | ||
1717 | spin_lock_bh(&session->lock); | ||
1718 | if (session->state == ISCSI_STATE_LOGGED_IN) { | ||
1719 | ISCSI_DBG_EH(session, | ||
1720 | "target reset succeeded\n"); | ||
1721 | } else | ||
1722 | goto failed; | ||
1723 | spin_unlock_bh(&session->lock); | ||
1724 | mutex_unlock(&session->eh_mutex); | ||
1725 | return SUCCESS; | ||
1726 | } | ||
1727 | EXPORT_SYMBOL_GPL(iscsi_eh_target_reset); | ||
1728 | |||
1729 | static void iscsi_tmf_timedout(unsigned long data) | 1769 | static void iscsi_tmf_timedout(unsigned long data) |
1730 | { | 1770 | { |
1731 | struct iscsi_conn *conn = (struct iscsi_conn *)data; | 1771 | struct iscsi_conn *conn = (struct iscsi_conn *)data; |
@@ -2108,6 +2148,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
2108 | spin_lock_bh(&session->lock); | 2148 | spin_lock_bh(&session->lock); |
2109 | fail_scsi_task(task, DID_ABORT); | 2149 | fail_scsi_task(task, DID_ABORT); |
2110 | conn->tmf_state = TMF_INITIAL; | 2150 | conn->tmf_state = TMF_INITIAL; |
2151 | memset(hdr, 0, sizeof(*hdr)); | ||
2111 | spin_unlock_bh(&session->lock); | 2152 | spin_unlock_bh(&session->lock); |
2112 | iscsi_start_tx(conn); | 2153 | iscsi_start_tx(conn); |
2113 | goto success_unlocked; | 2154 | goto success_unlocked; |
@@ -2118,6 +2159,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
2118 | case TMF_NOT_FOUND: | 2159 | case TMF_NOT_FOUND: |
2119 | if (!sc->SCp.ptr) { | 2160 | if (!sc->SCp.ptr) { |
2120 | conn->tmf_state = TMF_INITIAL; | 2161 | conn->tmf_state = TMF_INITIAL; |
2162 | memset(hdr, 0, sizeof(*hdr)); | ||
2121 | /* task completed before tmf abort response */ | 2163 | /* task completed before tmf abort response */ |
2122 | ISCSI_DBG_EH(session, "sc completed while abort in " | 2164 | ISCSI_DBG_EH(session, "sc completed while abort in " |
2123 | "progress\n"); | 2165 | "progress\n"); |
@@ -2212,6 +2254,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc) | |||
2212 | iscsi_suspend_tx(conn); | 2254 | iscsi_suspend_tx(conn); |
2213 | 2255 | ||
2214 | spin_lock_bh(&session->lock); | 2256 | spin_lock_bh(&session->lock); |
2257 | memset(hdr, 0, sizeof(*hdr)); | ||
2215 | fail_scsi_tasks(conn, sc->device->lun, DID_ERROR); | 2258 | fail_scsi_tasks(conn, sc->device->lun, DID_ERROR); |
2216 | conn->tmf_state = TMF_INITIAL; | 2259 | conn->tmf_state = TMF_INITIAL; |
2217 | spin_unlock_bh(&session->lock); | 2260 | spin_unlock_bh(&session->lock); |
@@ -2229,6 +2272,172 @@ done: | |||
2229 | } | 2272 | } |
2230 | EXPORT_SYMBOL_GPL(iscsi_eh_device_reset); | 2273 | EXPORT_SYMBOL_GPL(iscsi_eh_device_reset); |
2231 | 2274 | ||
2275 | void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session) | ||
2276 | { | ||
2277 | struct iscsi_session *session = cls_session->dd_data; | ||
2278 | |||
2279 | spin_lock_bh(&session->lock); | ||
2280 | if (session->state != ISCSI_STATE_LOGGED_IN) { | ||
2281 | session->state = ISCSI_STATE_RECOVERY_FAILED; | ||
2282 | if (session->leadconn) | ||
2283 | wake_up(&session->leadconn->ehwait); | ||
2284 | } | ||
2285 | spin_unlock_bh(&session->lock); | ||
2286 | } | ||
2287 | EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout); | ||
2288 | |||
2289 | /** | ||
2290 | * iscsi_eh_session_reset - drop session and attempt relogin | ||
2291 | * @sc: scsi command | ||
2292 | * | ||
2293 | * This function will wait for a relogin, session termination from | ||
2294 | * userspace, or a recovery/replacement timeout. | ||
2295 | */ | ||
2296 | static int iscsi_eh_session_reset(struct scsi_cmnd *sc) | ||
2297 | { | ||
2298 | struct iscsi_cls_session *cls_session; | ||
2299 | struct iscsi_session *session; | ||
2300 | struct iscsi_conn *conn; | ||
2301 | |||
2302 | cls_session = starget_to_session(scsi_target(sc->device)); | ||
2303 | session = cls_session->dd_data; | ||
2304 | conn = session->leadconn; | ||
2305 | |||
2306 | mutex_lock(&session->eh_mutex); | ||
2307 | spin_lock_bh(&session->lock); | ||
2308 | if (session->state == ISCSI_STATE_TERMINATE) { | ||
2309 | failed: | ||
2310 | ISCSI_DBG_EH(session, | ||
2311 | "failing session reset: Could not log back into " | ||
2312 | "%s, %s [age %d]\n", session->targetname, | ||
2313 | conn->persistent_address, session->age); | ||
2314 | spin_unlock_bh(&session->lock); | ||
2315 | mutex_unlock(&session->eh_mutex); | ||
2316 | return FAILED; | ||
2317 | } | ||
2318 | |||
2319 | spin_unlock_bh(&session->lock); | ||
2320 | mutex_unlock(&session->eh_mutex); | ||
2321 | /* | ||
2322 | * we drop the lock here but the leadconn cannot be destoyed while | ||
2323 | * we are in the scsi eh | ||
2324 | */ | ||
2325 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | ||
2326 | |||
2327 | ISCSI_DBG_EH(session, "wait for relogin\n"); | ||
2328 | wait_event_interruptible(conn->ehwait, | ||
2329 | session->state == ISCSI_STATE_TERMINATE || | ||
2330 | session->state == ISCSI_STATE_LOGGED_IN || | ||
2331 | session->state == ISCSI_STATE_RECOVERY_FAILED); | ||
2332 | if (signal_pending(current)) | ||
2333 | flush_signals(current); | ||
2334 | |||
2335 | mutex_lock(&session->eh_mutex); | ||
2336 | spin_lock_bh(&session->lock); | ||
2337 | if (session->state == ISCSI_STATE_LOGGED_IN) { | ||
2338 | ISCSI_DBG_EH(session, | ||
2339 | "session reset succeeded for %s,%s\n", | ||
2340 | session->targetname, conn->persistent_address); | ||
2341 | } else | ||
2342 | goto failed; | ||
2343 | spin_unlock_bh(&session->lock); | ||
2344 | mutex_unlock(&session->eh_mutex); | ||
2345 | return SUCCESS; | ||
2346 | } | ||
2347 | |||
2348 | static void iscsi_prep_tgt_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr) | ||
2349 | { | ||
2350 | memset(hdr, 0, sizeof(*hdr)); | ||
2351 | hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; | ||
2352 | hdr->flags = ISCSI_TM_FUNC_TARGET_WARM_RESET & ISCSI_FLAG_TM_FUNC_MASK; | ||
2353 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | ||
2354 | hdr->rtt = RESERVED_ITT; | ||
2355 | } | ||
2356 | |||
2357 | /** | ||
2358 | * iscsi_eh_target_reset - reset target | ||
2359 | * @sc: scsi command | ||
2360 | * | ||
2361 | * This will attempt to send a warm target reset. If that fails | ||
2362 | * then we will drop the session and attempt ERL0 recovery. | ||
2363 | */ | ||
2364 | int iscsi_eh_target_reset(struct scsi_cmnd *sc) | ||
2365 | { | ||
2366 | struct iscsi_cls_session *cls_session; | ||
2367 | struct iscsi_session *session; | ||
2368 | struct iscsi_conn *conn; | ||
2369 | struct iscsi_tm *hdr; | ||
2370 | int rc = FAILED; | ||
2371 | |||
2372 | cls_session = starget_to_session(scsi_target(sc->device)); | ||
2373 | session = cls_session->dd_data; | ||
2374 | |||
2375 | ISCSI_DBG_EH(session, "tgt Reset [sc %p tgt %s]\n", sc, | ||
2376 | session->targetname); | ||
2377 | |||
2378 | mutex_lock(&session->eh_mutex); | ||
2379 | spin_lock_bh(&session->lock); | ||
2380 | /* | ||
2381 | * Just check if we are not logged in. We cannot check for | ||
2382 | * the phase because the reset could come from a ioctl. | ||
2383 | */ | ||
2384 | if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) | ||
2385 | goto unlock; | ||
2386 | conn = session->leadconn; | ||
2387 | |||
2388 | /* only have one tmf outstanding at a time */ | ||
2389 | if (conn->tmf_state != TMF_INITIAL) | ||
2390 | goto unlock; | ||
2391 | conn->tmf_state = TMF_QUEUED; | ||
2392 | |||
2393 | hdr = &conn->tmhdr; | ||
2394 | iscsi_prep_tgt_reset_pdu(sc, hdr); | ||
2395 | |||
2396 | if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age, | ||
2397 | session->tgt_reset_timeout)) { | ||
2398 | rc = FAILED; | ||
2399 | goto unlock; | ||
2400 | } | ||
2401 | |||
2402 | switch (conn->tmf_state) { | ||
2403 | case TMF_SUCCESS: | ||
2404 | break; | ||
2405 | case TMF_TIMEDOUT: | ||
2406 | spin_unlock_bh(&session->lock); | ||
2407 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | ||
2408 | goto done; | ||
2409 | default: | ||
2410 | conn->tmf_state = TMF_INITIAL; | ||
2411 | goto unlock; | ||
2412 | } | ||
2413 | |||
2414 | rc = SUCCESS; | ||
2415 | spin_unlock_bh(&session->lock); | ||
2416 | |||
2417 | iscsi_suspend_tx(conn); | ||
2418 | |||
2419 | spin_lock_bh(&session->lock); | ||
2420 | memset(hdr, 0, sizeof(*hdr)); | ||
2421 | fail_scsi_tasks(conn, -1, DID_ERROR); | ||
2422 | conn->tmf_state = TMF_INITIAL; | ||
2423 | spin_unlock_bh(&session->lock); | ||
2424 | |||
2425 | iscsi_start_tx(conn); | ||
2426 | goto done; | ||
2427 | |||
2428 | unlock: | ||
2429 | spin_unlock_bh(&session->lock); | ||
2430 | done: | ||
2431 | ISCSI_DBG_EH(session, "tgt %s reset result = %s\n", session->targetname, | ||
2432 | rc == SUCCESS ? "SUCCESS" : "FAILED"); | ||
2433 | mutex_unlock(&session->eh_mutex); | ||
2434 | |||
2435 | if (rc == FAILED) | ||
2436 | rc = iscsi_eh_session_reset(sc); | ||
2437 | return rc; | ||
2438 | } | ||
2439 | EXPORT_SYMBOL_GPL(iscsi_eh_target_reset); | ||
2440 | |||
2232 | /* | 2441 | /* |
2233 | * Pre-allocate a pool of @max items of @item_size. By default, the pool | 2442 | * Pre-allocate a pool of @max items of @item_size. By default, the pool |
2234 | * should be accessed via kfifo_{get,put} on q->queue. | 2443 | * should be accessed via kfifo_{get,put} on q->queue. |
@@ -2495,6 +2704,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost, | |||
2495 | session->host = shost; | 2704 | session->host = shost; |
2496 | session->state = ISCSI_STATE_FREE; | 2705 | session->state = ISCSI_STATE_FREE; |
2497 | session->fast_abort = 1; | 2706 | session->fast_abort = 1; |
2707 | session->tgt_reset_timeout = 30; | ||
2498 | session->lu_reset_timeout = 15; | 2708 | session->lu_reset_timeout = 15; |
2499 | session->abort_timeout = 10; | 2709 | session->abort_timeout = 10; |
2500 | session->scsi_cmds_max = scsi_cmds; | 2710 | session->scsi_cmds_max = scsi_cmds; |
@@ -2856,6 +3066,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, | |||
2856 | spin_lock_bh(&session->lock); | 3066 | spin_lock_bh(&session->lock); |
2857 | fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED); | 3067 | fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED); |
2858 | fail_mgmt_tasks(session, conn); | 3068 | fail_mgmt_tasks(session, conn); |
3069 | memset(&conn->tmhdr, 0, sizeof(conn->tmhdr)); | ||
2859 | spin_unlock_bh(&session->lock); | 3070 | spin_unlock_bh(&session->lock); |
2860 | mutex_unlock(&session->eh_mutex); | 3071 | mutex_unlock(&session->eh_mutex); |
2861 | } | 3072 | } |
@@ -2932,6 +3143,9 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn, | |||
2932 | case ISCSI_PARAM_LU_RESET_TMO: | 3143 | case ISCSI_PARAM_LU_RESET_TMO: |
2933 | sscanf(buf, "%d", &session->lu_reset_timeout); | 3144 | sscanf(buf, "%d", &session->lu_reset_timeout); |
2934 | break; | 3145 | break; |
3146 | case ISCSI_PARAM_TGT_RESET_TMO: | ||
3147 | sscanf(buf, "%d", &session->tgt_reset_timeout); | ||
3148 | break; | ||
2935 | case ISCSI_PARAM_PING_TMO: | 3149 | case ISCSI_PARAM_PING_TMO: |
2936 | sscanf(buf, "%d", &conn->ping_timeout); | 3150 | sscanf(buf, "%d", &conn->ping_timeout); |
2937 | break; | 3151 | break; |
@@ -3031,6 +3245,9 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session, | |||
3031 | case ISCSI_PARAM_LU_RESET_TMO: | 3245 | case ISCSI_PARAM_LU_RESET_TMO: |
3032 | len = sprintf(buf, "%d\n", session->lu_reset_timeout); | 3246 | len = sprintf(buf, "%d\n", session->lu_reset_timeout); |
3033 | break; | 3247 | break; |
3248 | case ISCSI_PARAM_TGT_RESET_TMO: | ||
3249 | len = sprintf(buf, "%d\n", session->tgt_reset_timeout); | ||
3250 | break; | ||
3034 | case ISCSI_PARAM_INITIAL_R2T_EN: | 3251 | case ISCSI_PARAM_INITIAL_R2T_EN: |
3035 | len = sprintf(buf, "%d\n", session->initial_r2t_en); | 3252 | len = sprintf(buf, "%d\n", session->initial_r2t_en); |
3036 | break; | 3253 | break; |