.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * QLogic iSCSI Offload Driver |
---|
3 | 4 | * Copyright (c) 2016 Cavium Inc. |
---|
4 | | - * |
---|
5 | | - * This software is available under the terms of the GNU General Public License |
---|
6 | | - * (GPL) Version 2, available from the file COPYING in the main directory of |
---|
7 | | - * this source tree. |
---|
8 | 5 | */ |
---|
9 | 6 | |
---|
10 | 7 | #include <linux/blkdev.h> |
---|
.. | .. |
---|
61 | 58 | .max_sectors = 0xffff, |
---|
62 | 59 | .dma_boundary = QEDI_HW_DMA_BOUNDARY, |
---|
63 | 60 | .cmd_per_lun = 128, |
---|
64 | | - .use_clustering = ENABLE_CLUSTERING, |
---|
65 | 61 | .shost_attrs = qedi_shost_attrs, |
---|
66 | 62 | }; |
---|
67 | 63 | |
---|
.. | .. |
---|
334 | 330 | |
---|
335 | 331 | void qedi_mark_device_missing(struct iscsi_cls_session *cls_session) |
---|
336 | 332 | { |
---|
337 | | - iscsi_block_session(cls_session); |
---|
| 333 | + struct iscsi_session *session = cls_session->dd_data; |
---|
| 334 | + struct qedi_conn *qedi_conn = session->leadconn->dd_data; |
---|
| 335 | + |
---|
| 336 | + spin_lock_bh(&session->frwd_lock); |
---|
| 337 | + set_bit(QEDI_BLOCK_IO, &qedi_conn->qedi->flags); |
---|
| 338 | + spin_unlock_bh(&session->frwd_lock); |
---|
338 | 339 | } |
---|
339 | 340 | |
---|
340 | 341 | void qedi_mark_device_available(struct iscsi_cls_session *cls_session) |
---|
341 | 342 | { |
---|
342 | | - iscsi_unblock_session(cls_session); |
---|
| 343 | + struct iscsi_session *session = cls_session->dd_data; |
---|
| 344 | + struct qedi_conn *qedi_conn = session->leadconn->dd_data; |
---|
| 345 | + |
---|
| 346 | + spin_lock_bh(&session->frwd_lock); |
---|
| 347 | + clear_bit(QEDI_BLOCK_IO, &qedi_conn->qedi->flags); |
---|
| 348 | + spin_unlock_bh(&session->frwd_lock); |
---|
343 | 349 | } |
---|
344 | 350 | |
---|
345 | 351 | static int qedi_bind_conn_to_iscsi_cid(struct qedi_ctx *qedi, |
---|
.. | .. |
---|
381 | 387 | struct qedi_ctx *qedi = iscsi_host_priv(shost); |
---|
382 | 388 | struct qedi_endpoint *qedi_ep; |
---|
383 | 389 | struct iscsi_endpoint *ep; |
---|
| 390 | + int rc = 0; |
---|
384 | 391 | |
---|
385 | 392 | ep = iscsi_lookup_endpoint(transport_fd); |
---|
386 | 393 | if (!ep) |
---|
.. | .. |
---|
388 | 395 | |
---|
389 | 396 | qedi_ep = ep->dd_data; |
---|
390 | 397 | if ((qedi_ep->state == EP_STATE_TCP_FIN_RCVD) || |
---|
391 | | - (qedi_ep->state == EP_STATE_TCP_RST_RCVD)) |
---|
392 | | - return -EINVAL; |
---|
| 398 | + (qedi_ep->state == EP_STATE_TCP_RST_RCVD)) { |
---|
| 399 | + rc = -EINVAL; |
---|
| 400 | + goto put_ep; |
---|
| 401 | + } |
---|
393 | 402 | |
---|
394 | | - if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) |
---|
395 | | - return -EINVAL; |
---|
| 403 | + if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) { |
---|
| 404 | + rc = -EINVAL; |
---|
| 405 | + goto put_ep; |
---|
| 406 | + } |
---|
| 407 | + |
---|
396 | 408 | |
---|
397 | 409 | qedi_ep->conn = qedi_conn; |
---|
398 | 410 | qedi_conn->ep = qedi_ep; |
---|
| 411 | + qedi_conn->iscsi_ep = ep; |
---|
399 | 412 | qedi_conn->iscsi_conn_id = qedi_ep->iscsi_cid; |
---|
400 | 413 | qedi_conn->fw_cid = qedi_ep->fw_cid; |
---|
401 | 414 | qedi_conn->cmd_cleanup_req = 0; |
---|
402 | 415 | qedi_conn->cmd_cleanup_cmpl = 0; |
---|
403 | 416 | |
---|
404 | | - if (qedi_bind_conn_to_iscsi_cid(qedi, qedi_conn)) |
---|
405 | | - return -EINVAL; |
---|
| 417 | + if (qedi_bind_conn_to_iscsi_cid(qedi, qedi_conn)) { |
---|
| 418 | + rc = -EINVAL; |
---|
| 419 | + goto put_ep; |
---|
| 420 | + } |
---|
| 421 | + |
---|
406 | 422 | |
---|
407 | 423 | spin_lock_init(&qedi_conn->tmf_work_lock); |
---|
408 | 424 | INIT_LIST_HEAD(&qedi_conn->tmf_work_list); |
---|
409 | 425 | init_waitqueue_head(&qedi_conn->wait_queue); |
---|
410 | | - return 0; |
---|
| 426 | +put_ep: |
---|
| 427 | + iscsi_put_endpoint(ep); |
---|
| 428 | + return rc; |
---|
411 | 429 | } |
---|
412 | 430 | |
---|
413 | 431 | static int qedi_iscsi_update_conn(struct qedi_ctx *qedi, |
---|
.. | .. |
---|
580 | 598 | rval = qedi_iscsi_update_conn(qedi, qedi_conn); |
---|
581 | 599 | if (rval) { |
---|
582 | 600 | iscsi_conn_printk(KERN_ALERT, conn, |
---|
583 | | - "conn_start: FW oflload conn failed.\n"); |
---|
| 601 | + "conn_start: FW offload conn failed.\n"); |
---|
584 | 602 | rval = -EINVAL; |
---|
585 | 603 | goto start_err; |
---|
586 | 604 | } |
---|
.. | .. |
---|
591 | 609 | rval = iscsi_conn_start(cls_conn); |
---|
592 | 610 | if (rval) { |
---|
593 | 611 | iscsi_conn_printk(KERN_ALERT, conn, |
---|
594 | | - "iscsi_conn_start: FW oflload conn failed!!\n"); |
---|
| 612 | + "iscsi_conn_start: FW offload conn failed!!\n"); |
---|
595 | 613 | } |
---|
596 | 614 | |
---|
597 | 615 | start_err: |
---|
.. | .. |
---|
775 | 793 | } |
---|
776 | 794 | |
---|
777 | 795 | cmd->conn = conn->dd_data; |
---|
778 | | - cmd->scsi_cmd = NULL; |
---|
779 | 796 | return qedi_iscsi_send_generic_request(task); |
---|
780 | 797 | } |
---|
781 | 798 | |
---|
.. | .. |
---|
785 | 802 | struct qedi_conn *qedi_conn = conn->dd_data; |
---|
786 | 803 | struct qedi_cmd *cmd = task->dd_data; |
---|
787 | 804 | struct scsi_cmnd *sc = task->sc; |
---|
| 805 | + |
---|
| 806 | + /* Clear now so in cleanup_task we know it didn't make it */ |
---|
| 807 | + cmd->scsi_cmd = NULL; |
---|
| 808 | + cmd->task_id = U16_MAX; |
---|
| 809 | + |
---|
| 810 | + if (test_bit(QEDI_IN_SHUTDOWN, &qedi_conn->qedi->flags)) |
---|
| 811 | + return -ENODEV; |
---|
| 812 | + |
---|
| 813 | + if (test_bit(QEDI_BLOCK_IO, &qedi_conn->qedi->flags)) |
---|
| 814 | + return -EACCES; |
---|
788 | 815 | |
---|
789 | 816 | cmd->state = 0; |
---|
790 | 817 | cmd->task = NULL; |
---|
.. | .. |
---|
799 | 826 | |
---|
800 | 827 | cmd->scsi_cmd = sc; |
---|
801 | 828 | return qedi_iscsi_send_ioreq(task); |
---|
| 829 | +} |
---|
| 830 | + |
---|
| 831 | +static void qedi_offload_work(struct work_struct *work) |
---|
| 832 | +{ |
---|
| 833 | + struct qedi_endpoint *qedi_ep = |
---|
| 834 | + container_of(work, struct qedi_endpoint, offload_work); |
---|
| 835 | + struct qedi_ctx *qedi; |
---|
| 836 | + int wait_delay = 5 * HZ; |
---|
| 837 | + int ret; |
---|
| 838 | + |
---|
| 839 | + qedi = qedi_ep->qedi; |
---|
| 840 | + |
---|
| 841 | + ret = qedi_iscsi_offload_conn(qedi_ep); |
---|
| 842 | + if (ret) { |
---|
| 843 | + QEDI_ERR(&qedi->dbg_ctx, |
---|
| 844 | + "offload error: iscsi_cid=%u, qedi_ep=%p, ret=%d\n", |
---|
| 845 | + qedi_ep->iscsi_cid, qedi_ep, ret); |
---|
| 846 | + qedi_ep->state = EP_STATE_OFLDCONN_FAILED; |
---|
| 847 | + return; |
---|
| 848 | + } |
---|
| 849 | + |
---|
| 850 | + ret = wait_event_interruptible_timeout(qedi_ep->tcp_ofld_wait, |
---|
| 851 | + (qedi_ep->state == |
---|
| 852 | + EP_STATE_OFLDCONN_COMPL), |
---|
| 853 | + wait_delay); |
---|
| 854 | + if (ret <= 0 || qedi_ep->state != EP_STATE_OFLDCONN_COMPL) { |
---|
| 855 | + qedi_ep->state = EP_STATE_OFLDCONN_FAILED; |
---|
| 856 | + QEDI_ERR(&qedi->dbg_ctx, |
---|
| 857 | + "Offload conn TIMEOUT iscsi_cid=%u, qedi_ep=%p\n", |
---|
| 858 | + qedi_ep->iscsi_cid, qedi_ep); |
---|
| 859 | + } |
---|
802 | 860 | } |
---|
803 | 861 | |
---|
804 | 862 | static struct iscsi_endpoint * |
---|
.. | .. |
---|
836 | 894 | return ERR_PTR(ret); |
---|
837 | 895 | } |
---|
838 | 896 | |
---|
| 897 | + if (atomic_read(&qedi->link_state) != QEDI_LINK_UP) { |
---|
| 898 | + QEDI_WARN(&qedi->dbg_ctx, "qedi link down\n"); |
---|
| 899 | + return ERR_PTR(-ENXIO); |
---|
| 900 | + } |
---|
| 901 | + |
---|
839 | 902 | ep = iscsi_create_endpoint(sizeof(struct qedi_endpoint)); |
---|
840 | 903 | if (!ep) { |
---|
841 | 904 | QEDI_ERR(&qedi->dbg_ctx, "endpoint create fail\n"); |
---|
.. | .. |
---|
844 | 907 | } |
---|
845 | 908 | qedi_ep = ep->dd_data; |
---|
846 | 909 | memset(qedi_ep, 0, sizeof(struct qedi_endpoint)); |
---|
| 910 | + INIT_WORK(&qedi_ep->offload_work, qedi_offload_work); |
---|
847 | 911 | qedi_ep->state = EP_STATE_IDLE; |
---|
848 | 912 | qedi_ep->iscsi_cid = (u32)-1; |
---|
849 | 913 | qedi_ep->qedi = qedi; |
---|
.. | .. |
---|
868 | 932 | qedi_ep->dst_addr, qedi_ep->dst_port); |
---|
869 | 933 | } else { |
---|
870 | 934 | QEDI_ERR(&qedi->dbg_ctx, "Invalid endpoint\n"); |
---|
871 | | - } |
---|
872 | | - |
---|
873 | | - if (atomic_read(&qedi->link_state) != QEDI_LINK_UP) { |
---|
874 | | - QEDI_WARN(&qedi->dbg_ctx, "qedi link down\n"); |
---|
875 | | - ret = -ENXIO; |
---|
876 | | - goto ep_conn_exit; |
---|
877 | 935 | } |
---|
878 | 936 | |
---|
879 | 937 | ret = qedi_alloc_sq(qedi, qedi_ep); |
---|
.. | .. |
---|
992 | 1050 | struct iscsi_conn *conn = NULL; |
---|
993 | 1051 | struct qedi_ctx *qedi; |
---|
994 | 1052 | int ret = 0; |
---|
995 | | - int wait_delay = 20 * HZ; |
---|
| 1053 | + int wait_delay; |
---|
996 | 1054 | int abrt_conn = 0; |
---|
997 | 1055 | int count = 10; |
---|
998 | 1056 | |
---|
| 1057 | + wait_delay = 60 * HZ + DEF_MAX_RT_TIME; |
---|
999 | 1058 | qedi_ep = ep->dd_data; |
---|
1000 | 1059 | qedi = qedi_ep->qedi; |
---|
1001 | 1060 | |
---|
| 1061 | + flush_work(&qedi_ep->offload_work); |
---|
| 1062 | + |
---|
1002 | 1063 | if (qedi_ep->state == EP_STATE_OFLDCONN_START) |
---|
1003 | 1064 | goto ep_exit_recover; |
---|
1004 | | - |
---|
1005 | | - if (qedi_ep->state != EP_STATE_OFLDCONN_NONE) |
---|
1006 | | - flush_work(&qedi_ep->offload_work); |
---|
1007 | 1065 | |
---|
1008 | 1066 | if (qedi_ep->conn) { |
---|
1009 | 1067 | qedi_conn = qedi_ep->conn; |
---|
.. | .. |
---|
1071 | 1129 | wait_delay += qedi->pf_params.iscsi_pf_params.two_msl_timer; |
---|
1072 | 1130 | |
---|
1073 | 1131 | qedi_ep->state = EP_STATE_DISCONN_START; |
---|
| 1132 | + |
---|
| 1133 | + if (test_bit(QEDI_IN_SHUTDOWN, &qedi->flags) || |
---|
| 1134 | + test_bit(QEDI_IN_RECOVERY, &qedi->flags)) |
---|
| 1135 | + goto ep_release_conn; |
---|
| 1136 | + |
---|
1074 | 1137 | ret = qedi_ops->destroy_conn(qedi->cdev, qedi_ep->handle, abrt_conn); |
---|
1075 | 1138 | if (ret) { |
---|
1076 | 1139 | QEDI_WARN(&qedi->dbg_ctx, |
---|
.. | .. |
---|
1162 | 1225 | uctrl->hw_tx_cons++; |
---|
1163 | 1226 | |
---|
1164 | 1227 | return rc; |
---|
1165 | | -} |
---|
1166 | | - |
---|
1167 | | -static void qedi_offload_work(struct work_struct *work) |
---|
1168 | | -{ |
---|
1169 | | - struct qedi_endpoint *qedi_ep = |
---|
1170 | | - container_of(work, struct qedi_endpoint, offload_work); |
---|
1171 | | - struct qedi_ctx *qedi; |
---|
1172 | | - int wait_delay = 20 * HZ; |
---|
1173 | | - int ret; |
---|
1174 | | - |
---|
1175 | | - qedi = qedi_ep->qedi; |
---|
1176 | | - |
---|
1177 | | - ret = qedi_iscsi_offload_conn(qedi_ep); |
---|
1178 | | - if (ret) { |
---|
1179 | | - QEDI_ERR(&qedi->dbg_ctx, |
---|
1180 | | - "offload error: iscsi_cid=%u, qedi_ep=%p, ret=%d\n", |
---|
1181 | | - qedi_ep->iscsi_cid, qedi_ep, ret); |
---|
1182 | | - qedi_ep->state = EP_STATE_OFLDCONN_FAILED; |
---|
1183 | | - return; |
---|
1184 | | - } |
---|
1185 | | - |
---|
1186 | | - ret = wait_event_interruptible_timeout(qedi_ep->tcp_ofld_wait, |
---|
1187 | | - (qedi_ep->state == |
---|
1188 | | - EP_STATE_OFLDCONN_COMPL), |
---|
1189 | | - wait_delay); |
---|
1190 | | - if ((ret <= 0) || (qedi_ep->state != EP_STATE_OFLDCONN_COMPL)) { |
---|
1191 | | - qedi_ep->state = EP_STATE_OFLDCONN_FAILED; |
---|
1192 | | - QEDI_ERR(&qedi->dbg_ctx, |
---|
1193 | | - "Offload conn TIMEOUT iscsi_cid=%u, qedi_ep=%p\n", |
---|
1194 | | - qedi_ep->iscsi_cid, qedi_ep); |
---|
1195 | | - } |
---|
1196 | 1228 | } |
---|
1197 | 1229 | |
---|
1198 | 1230 | static int qedi_set_path(struct Scsi_Host *shost, struct iscsi_path *path_data) |
---|
.. | .. |
---|
1310 | 1342 | qedi_ep->dst_addr, qedi_ep->dst_port); |
---|
1311 | 1343 | } |
---|
1312 | 1344 | |
---|
1313 | | - INIT_WORK(&qedi_ep->offload_work, qedi_offload_work); |
---|
1314 | 1345 | queue_work(qedi->offload_thread, &qedi_ep->offload_work); |
---|
1315 | 1346 | |
---|
1316 | 1347 | ret = 0; |
---|
.. | .. |
---|
1378 | 1409 | |
---|
1379 | 1410 | static void qedi_cleanup_task(struct iscsi_task *task) |
---|
1380 | 1411 | { |
---|
1381 | | - if (!task->sc || task->state == ISCSI_TASK_PENDING) { |
---|
| 1412 | + struct qedi_cmd *cmd; |
---|
| 1413 | + |
---|
| 1414 | + if (task->state == ISCSI_TASK_PENDING) { |
---|
1382 | 1415 | QEDI_INFO(NULL, QEDI_LOG_IO, "Returning ref_cnt=%d\n", |
---|
1383 | 1416 | refcount_read(&task->refcount)); |
---|
1384 | 1417 | return; |
---|
1385 | 1418 | } |
---|
1386 | 1419 | |
---|
1387 | | - qedi_iscsi_unmap_sg_list(task->dd_data); |
---|
| 1420 | + if (task->sc) |
---|
| 1421 | + qedi_iscsi_unmap_sg_list(task->dd_data); |
---|
| 1422 | + |
---|
| 1423 | + cmd = task->dd_data; |
---|
| 1424 | + if (cmd->task_id != U16_MAX) |
---|
| 1425 | + qedi_clear_task_idx(iscsi_host_priv(task->conn->session->host), |
---|
| 1426 | + cmd->task_id); |
---|
| 1427 | + |
---|
| 1428 | + cmd->task_id = U16_MAX; |
---|
| 1429 | + cmd->scsi_cmd = NULL; |
---|
1388 | 1430 | } |
---|
1389 | 1431 | |
---|
1390 | 1432 | struct iscsi_transport qedi_iscsi_transport = { |
---|
.. | .. |
---|
1396 | 1438 | .destroy_session = qedi_session_destroy, |
---|
1397 | 1439 | .create_conn = qedi_conn_create, |
---|
1398 | 1440 | .bind_conn = qedi_conn_bind, |
---|
| 1441 | + .unbind_conn = iscsi_conn_unbind, |
---|
1399 | 1442 | .start_conn = qedi_conn_start, |
---|
1400 | 1443 | .stop_conn = iscsi_conn_stop, |
---|
1401 | 1444 | .destroy_conn = qedi_conn_destroy, |
---|
.. | .. |
---|
1548 | 1591 | }, |
---|
1549 | 1592 | }; |
---|
1550 | 1593 | |
---|
1551 | | -char *qedi_get_iscsi_error(enum iscsi_error_types err_code) |
---|
| 1594 | +static char *qedi_get_iscsi_error(enum iscsi_error_types err_code) |
---|
1552 | 1595 | { |
---|
1553 | 1596 | int i; |
---|
1554 | 1597 | char *msg = NULL; |
---|
.. | .. |
---|
1609 | 1652 | qedi_start_conn_recovery(qedi_conn->qedi, qedi_conn); |
---|
1610 | 1653 | } |
---|
1611 | 1654 | |
---|
| 1655 | +void qedi_clear_session_ctx(struct iscsi_cls_session *cls_sess) |
---|
| 1656 | +{ |
---|
| 1657 | + struct iscsi_session *session = cls_sess->dd_data; |
---|
| 1658 | + struct iscsi_conn *conn = session->leadconn; |
---|
| 1659 | + struct qedi_conn *qedi_conn = conn->dd_data; |
---|
| 1660 | + |
---|
| 1661 | + if (iscsi_is_session_online(cls_sess)) |
---|
| 1662 | + qedi_ep_disconnect(qedi_conn->iscsi_ep); |
---|
| 1663 | + |
---|
| 1664 | + qedi_conn_destroy(qedi_conn->cls_conn); |
---|
| 1665 | + |
---|
| 1666 | + qedi_session_destroy(cls_sess); |
---|
| 1667 | +} |
---|
| 1668 | + |
---|
1612 | 1669 | void qedi_process_tcp_error(struct qedi_endpoint *ep, |
---|
1613 | 1670 | struct iscsi_eqe_data *data) |
---|
1614 | 1671 | { |
---|