| .. | .. |
|---|
| 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/module.h> |
|---|
| .. | .. |
|---|
| 31 | 28 | #include "qedi_gbl.h" |
|---|
| 32 | 29 | #include "qedi_iscsi.h" |
|---|
| 33 | 30 | |
|---|
| 31 | +static uint qedi_qed_debug; |
|---|
| 32 | +module_param(qedi_qed_debug, uint, 0644); |
|---|
| 33 | +MODULE_PARM_DESC(qedi_qed_debug, " QED debug level 0 (default)"); |
|---|
| 34 | + |
|---|
| 34 | 35 | static uint qedi_fw_debug; |
|---|
| 35 | 36 | module_param(qedi_fw_debug, uint, 0644); |
|---|
| 36 | 37 | MODULE_PARM_DESC(qedi_fw_debug, " Firmware debug level 0(default) to 3"); |
|---|
| .. | .. |
|---|
| 44 | 45 | MODULE_PARM_DESC(qedi_io_tracing, |
|---|
| 45 | 46 | " Enable logging of SCSI requests/completions into trace buffer. (default off)."); |
|---|
| 46 | 47 | |
|---|
| 48 | +static uint qedi_ll2_buf_size = 0x400; |
|---|
| 49 | +module_param(qedi_ll2_buf_size, uint, 0644); |
|---|
| 50 | +MODULE_PARM_DESC(qedi_ll2_buf_size, |
|---|
| 51 | + "parameter to set ping packet size, default - 0x400, Jumbo packets - 0x2400."); |
|---|
| 52 | + |
|---|
| 53 | +static uint qedi_flags_override; |
|---|
| 54 | +module_param(qedi_flags_override, uint, 0644); |
|---|
| 55 | +MODULE_PARM_DESC(qedi_flags_override, "Disable/Enable MFW error flags bits action."); |
|---|
| 56 | + |
|---|
| 47 | 57 | const struct qed_iscsi_ops *qedi_ops; |
|---|
| 48 | 58 | static struct scsi_transport_template *qedi_scsi_transport; |
|---|
| 49 | 59 | static struct pci_driver qedi_pci_driver; |
|---|
| .. | .. |
|---|
| 56 | 66 | static void qedi_reset_uio_rings(struct qedi_uio_dev *udev); |
|---|
| 57 | 67 | static void qedi_ll2_free_skbs(struct qedi_ctx *qedi); |
|---|
| 58 | 68 | static struct nvm_iscsi_block *qedi_get_nvram_block(struct qedi_ctx *qedi); |
|---|
| 69 | +static void qedi_recovery_handler(struct work_struct *work); |
|---|
| 70 | +static void qedi_schedule_hw_err_handler(void *dev, |
|---|
| 71 | + enum qed_hw_err_type err_type); |
|---|
| 72 | +static int qedi_suspend(struct pci_dev *pdev, pm_message_t state); |
|---|
| 59 | 73 | |
|---|
| 60 | 74 | static int qedi_iscsi_event_cb(void *context, u8 fw_event_code, void *fw_handle) |
|---|
| 61 | 75 | { |
|---|
| .. | .. |
|---|
| 228 | 242 | } |
|---|
| 229 | 243 | |
|---|
| 230 | 244 | /* Allocating memory for Tx/Rx pkt buffer */ |
|---|
| 231 | | - udev->ll2_buf_size = TX_RX_RING * LL2_SINGLE_BUF_SIZE; |
|---|
| 245 | + udev->ll2_buf_size = TX_RX_RING * qedi_ll2_buf_size; |
|---|
| 232 | 246 | udev->ll2_buf_size = QEDI_PAGE_ALIGN(udev->ll2_buf_size); |
|---|
| 233 | 247 | udev->ll2_buf = (void *)__get_free_pages(GFP_KERNEL | __GFP_COMP | |
|---|
| 234 | 248 | __GFP_ZERO, 2); |
|---|
| .. | .. |
|---|
| 283 | 297 | qedi->udev = udev; |
|---|
| 284 | 298 | |
|---|
| 285 | 299 | udev->tx_pkt = udev->ll2_buf; |
|---|
| 286 | | - udev->rx_pkt = udev->ll2_buf + LL2_SINGLE_BUF_SIZE; |
|---|
| 300 | + udev->rx_pkt = udev->ll2_buf + qedi_ll2_buf_size; |
|---|
| 287 | 301 | return 0; |
|---|
| 288 | 302 | |
|---|
| 289 | 303 | err_uctrl: |
|---|
| .. | .. |
|---|
| 644 | 658 | qedi->max_active_conns = ISCSI_MAX_SESS_PER_HBA; |
|---|
| 645 | 659 | qedi->max_sqes = QEDI_SQ_SIZE; |
|---|
| 646 | 660 | |
|---|
| 647 | | - if (shost_use_blk_mq(shost)) |
|---|
| 648 | | - shost->nr_hw_queues = MIN_NUM_CPUS_MSIX(qedi); |
|---|
| 661 | + shost->nr_hw_queues = MIN_NUM_CPUS_MSIX(qedi); |
|---|
| 649 | 662 | |
|---|
| 650 | 663 | pci_set_drvdata(pdev, qedi); |
|---|
| 651 | 664 | |
|---|
| .. | .. |
|---|
| 656 | 669 | static int qedi_ll2_rx(void *cookie, struct sk_buff *skb, u32 arg1, u32 arg2) |
|---|
| 657 | 670 | { |
|---|
| 658 | 671 | struct qedi_ctx *qedi = (struct qedi_ctx *)cookie; |
|---|
| 659 | | - struct qedi_uio_dev *udev; |
|---|
| 660 | | - struct qedi_uio_ctrl *uctrl; |
|---|
| 661 | 672 | struct skb_work_list *work; |
|---|
| 662 | | - u32 prod; |
|---|
| 673 | + struct ethhdr *eh; |
|---|
| 663 | 674 | |
|---|
| 664 | 675 | if (!qedi) { |
|---|
| 665 | 676 | QEDI_ERR(NULL, "qedi is NULL\n"); |
|---|
| .. | .. |
|---|
| 673 | 684 | return 0; |
|---|
| 674 | 685 | } |
|---|
| 675 | 686 | |
|---|
| 676 | | - udev = qedi->udev; |
|---|
| 677 | | - uctrl = udev->uctrl; |
|---|
| 687 | + eh = (struct ethhdr *)skb->data; |
|---|
| 688 | + /* Undo VLAN encapsulation */ |
|---|
| 689 | + if (eh->h_proto == htons(ETH_P_8021Q)) { |
|---|
| 690 | + memmove((u8 *)eh + VLAN_HLEN, eh, ETH_ALEN * 2); |
|---|
| 691 | + eh = (struct ethhdr *)skb_pull(skb, VLAN_HLEN); |
|---|
| 692 | + skb_reset_mac_header(skb); |
|---|
| 693 | + } |
|---|
| 694 | + |
|---|
| 695 | + /* Filter out non FIP/FCoE frames here to free them faster */ |
|---|
| 696 | + if (eh->h_proto != htons(ETH_P_ARP) && |
|---|
| 697 | + eh->h_proto != htons(ETH_P_IP) && |
|---|
| 698 | + eh->h_proto != htons(ETH_P_IPV6)) { |
|---|
| 699 | + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_LL2, |
|---|
| 700 | + "Dropping frame ethertype [0x%x] len [0x%x].\n", |
|---|
| 701 | + eh->h_proto, skb->len); |
|---|
| 702 | + kfree_skb(skb); |
|---|
| 703 | + return 0; |
|---|
| 704 | + } |
|---|
| 705 | + |
|---|
| 706 | + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_LL2, |
|---|
| 707 | + "Allowed frame ethertype [0x%x] len [0x%x].\n", |
|---|
| 708 | + eh->h_proto, skb->len); |
|---|
| 678 | 709 | |
|---|
| 679 | 710 | work = kzalloc(sizeof(*work), GFP_ATOMIC); |
|---|
| 680 | 711 | if (!work) { |
|---|
| .. | .. |
|---|
| 695 | 726 | |
|---|
| 696 | 727 | spin_lock_bh(&qedi->ll2_lock); |
|---|
| 697 | 728 | list_add_tail(&work->list, &qedi->ll2_skb_list); |
|---|
| 698 | | - |
|---|
| 699 | | - ++uctrl->hw_rx_prod_cnt; |
|---|
| 700 | | - prod = (uctrl->hw_rx_prod + 1) % RX_RING; |
|---|
| 701 | | - if (prod != uctrl->host_rx_cons) { |
|---|
| 702 | | - uctrl->hw_rx_prod = prod; |
|---|
| 703 | | - spin_unlock_bh(&qedi->ll2_lock); |
|---|
| 704 | | - wake_up_process(qedi->ll2_recv_thread); |
|---|
| 705 | | - return 0; |
|---|
| 706 | | - } |
|---|
| 707 | | - |
|---|
| 708 | 729 | spin_unlock_bh(&qedi->ll2_lock); |
|---|
| 730 | + |
|---|
| 731 | + wake_up_process(qedi->ll2_recv_thread); |
|---|
| 732 | + |
|---|
| 709 | 733 | return 0; |
|---|
| 710 | 734 | } |
|---|
| 711 | 735 | |
|---|
| .. | .. |
|---|
| 720 | 744 | u32 rx_bd_prod; |
|---|
| 721 | 745 | void *pkt; |
|---|
| 722 | 746 | int len = 0; |
|---|
| 747 | + u32 prod; |
|---|
| 723 | 748 | |
|---|
| 724 | 749 | if (!qedi) { |
|---|
| 725 | 750 | QEDI_ERR(NULL, "qedi is NULL\n"); |
|---|
| .. | .. |
|---|
| 728 | 753 | |
|---|
| 729 | 754 | udev = qedi->udev; |
|---|
| 730 | 755 | uctrl = udev->uctrl; |
|---|
| 731 | | - pkt = udev->rx_pkt + (uctrl->hw_rx_prod * LL2_SINGLE_BUF_SIZE); |
|---|
| 732 | | - len = min_t(u32, skb->len, (u32)LL2_SINGLE_BUF_SIZE); |
|---|
| 756 | + |
|---|
| 757 | + ++uctrl->hw_rx_prod_cnt; |
|---|
| 758 | + prod = (uctrl->hw_rx_prod + 1) % RX_RING; |
|---|
| 759 | + |
|---|
| 760 | + pkt = udev->rx_pkt + (prod * qedi_ll2_buf_size); |
|---|
| 761 | + len = min_t(u32, skb->len, (u32)qedi_ll2_buf_size); |
|---|
| 733 | 762 | memcpy(pkt, skb->data, len); |
|---|
| 734 | 763 | |
|---|
| 735 | 764 | memset(&rxbd, 0, sizeof(rxbd)); |
|---|
| 736 | | - rxbd.rx_pkt_index = uctrl->hw_rx_prod; |
|---|
| 765 | + rxbd.rx_pkt_index = prod; |
|---|
| 737 | 766 | rxbd.rx_pkt_len = len; |
|---|
| 738 | 767 | rxbd.vlan_id = vlan_id; |
|---|
| 739 | 768 | |
|---|
| .. | .. |
|---|
| 743 | 772 | p_rxbd += rx_bd_prod; |
|---|
| 744 | 773 | |
|---|
| 745 | 774 | memcpy(p_rxbd, &rxbd, sizeof(rxbd)); |
|---|
| 775 | + |
|---|
| 776 | + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_LL2, |
|---|
| 777 | + "hw_rx_prod [%d] prod [%d] hw_rx_bd_prod [%d] rx_pkt_idx [%d] rx_len [%d].\n", |
|---|
| 778 | + uctrl->hw_rx_prod, prod, uctrl->hw_rx_bd_prod, |
|---|
| 779 | + rxbd.rx_pkt_index, rxbd.rx_pkt_len); |
|---|
| 780 | + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_LL2, |
|---|
| 781 | + "host_rx_cons [%d] hw_rx_bd_cons [%d].\n", |
|---|
| 782 | + uctrl->host_rx_cons, uctrl->host_rx_bd_cons); |
|---|
| 783 | + |
|---|
| 784 | + uctrl->hw_rx_prod = prod; |
|---|
| 746 | 785 | |
|---|
| 747 | 786 | /* notify the iscsiuio about new packet */ |
|---|
| 748 | 787 | uio_event_notify(&udev->qedi_uinfo); |
|---|
| .. | .. |
|---|
| 757 | 796 | spin_lock_bh(&qedi->ll2_lock); |
|---|
| 758 | 797 | list_for_each_entry_safe(work, work_tmp, &qedi->ll2_skb_list, list) { |
|---|
| 759 | 798 | list_del(&work->list); |
|---|
| 760 | | - if (work->skb) |
|---|
| 761 | | - kfree_skb(work->skb); |
|---|
| 799 | + kfree_skb(work->skb); |
|---|
| 762 | 800 | kfree(work); |
|---|
| 763 | 801 | } |
|---|
| 764 | 802 | spin_unlock_bh(&qedi->ll2_lock); |
|---|
| .. | .. |
|---|
| 796 | 834 | int rval = 0; |
|---|
| 797 | 835 | |
|---|
| 798 | 836 | |
|---|
| 799 | | - num_sq_pages = (MAX_OUSTANDING_TASKS_PER_CON * 8) / PAGE_SIZE; |
|---|
| 837 | + num_sq_pages = (MAX_OUTSTANDING_TASKS_PER_CON * 8) / QEDI_PAGE_SIZE; |
|---|
| 800 | 838 | |
|---|
| 801 | 839 | qedi->num_queues = MIN_NUM_CPUS_MSIX(qedi); |
|---|
| 802 | 840 | |
|---|
| .. | .. |
|---|
| 806 | 844 | memset(&qedi->pf_params.iscsi_pf_params, 0, |
|---|
| 807 | 845 | sizeof(qedi->pf_params.iscsi_pf_params)); |
|---|
| 808 | 846 | |
|---|
| 809 | | - qedi->p_cpuq = pci_alloc_consistent(qedi->pdev, |
|---|
| 847 | + qedi->p_cpuq = dma_alloc_coherent(&qedi->pdev->dev, |
|---|
| 810 | 848 | qedi->num_queues * sizeof(struct qedi_glbl_q_params), |
|---|
| 811 | | - &qedi->hw_p_cpuq); |
|---|
| 849 | + &qedi->hw_p_cpuq, GFP_KERNEL); |
|---|
| 812 | 850 | if (!qedi->p_cpuq) { |
|---|
| 813 | | - QEDI_ERR(&qedi->dbg_ctx, "pci_alloc_consistent fail\n"); |
|---|
| 851 | + QEDI_ERR(&qedi->dbg_ctx, "dma_alloc_coherent fail\n"); |
|---|
| 814 | 852 | rval = -1; |
|---|
| 815 | 853 | goto err_alloc_mem; |
|---|
| 816 | 854 | } |
|---|
| .. | .. |
|---|
| 834 | 872 | qedi->pf_params.iscsi_pf_params.max_fin_rt = 2; |
|---|
| 835 | 873 | |
|---|
| 836 | 874 | for (log_page_size = 0 ; log_page_size < 32 ; log_page_size++) { |
|---|
| 837 | | - if ((1 << log_page_size) == PAGE_SIZE) |
|---|
| 875 | + if ((1 << log_page_size) == QEDI_PAGE_SIZE) |
|---|
| 838 | 876 | break; |
|---|
| 839 | 877 | } |
|---|
| 840 | 878 | qedi->pf_params.iscsi_pf_params.log_page_size = log_page_size; |
|---|
| .. | .. |
|---|
| 871 | 909 | |
|---|
| 872 | 910 | if (qedi->p_cpuq) { |
|---|
| 873 | 911 | size = qedi->num_queues * sizeof(struct qedi_glbl_q_params); |
|---|
| 874 | | - pci_free_consistent(qedi->pdev, size, qedi->p_cpuq, |
|---|
| 912 | + dma_free_coherent(&qedi->pdev->dev, size, qedi->p_cpuq, |
|---|
| 875 | 913 | qedi->hw_p_cpuq); |
|---|
| 876 | 914 | } |
|---|
| 877 | 915 | |
|---|
| .. | .. |
|---|
| 888 | 926 | ipv6_en = !!(block->generic.ctrl_flags & |
|---|
| 889 | 927 | NVM_ISCSI_CFG_GEN_IPV6_ENABLED); |
|---|
| 890 | 928 | |
|---|
| 891 | | - snprintf(tgt->iscsi_name, sizeof(tgt->iscsi_name), "%s\n", |
|---|
| 929 | + snprintf(tgt->iscsi_name, sizeof(tgt->iscsi_name), "%s", |
|---|
| 892 | 930 | block->target[index].target_name.byte); |
|---|
| 893 | 931 | |
|---|
| 894 | 932 | tgt->ipv6_en = ipv6_en; |
|---|
| .. | .. |
|---|
| 1081 | 1119 | return; |
|---|
| 1082 | 1120 | } |
|---|
| 1083 | 1121 | |
|---|
| 1122 | +void qedi_schedule_hw_err_handler(void *dev, |
|---|
| 1123 | + enum qed_hw_err_type err_type) |
|---|
| 1124 | +{ |
|---|
| 1125 | + struct qedi_ctx *qedi = (struct qedi_ctx *)dev; |
|---|
| 1126 | + unsigned long override_flags = qedi_flags_override; |
|---|
| 1127 | + |
|---|
| 1128 | + if (override_flags && test_bit(QEDI_ERR_OVERRIDE_EN, &override_flags)) |
|---|
| 1129 | + qedi->qedi_err_flags = qedi_flags_override; |
|---|
| 1130 | + |
|---|
| 1131 | + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, |
|---|
| 1132 | + "HW error handler scheduled, err=%d err_flags=0x%x\n", |
|---|
| 1133 | + err_type, qedi->qedi_err_flags); |
|---|
| 1134 | + |
|---|
| 1135 | + switch (err_type) { |
|---|
| 1136 | + case QED_HW_ERR_FAN_FAIL: |
|---|
| 1137 | + schedule_delayed_work(&qedi->board_disable_work, 0); |
|---|
| 1138 | + break; |
|---|
| 1139 | + case QED_HW_ERR_MFW_RESP_FAIL: |
|---|
| 1140 | + case QED_HW_ERR_HW_ATTN: |
|---|
| 1141 | + case QED_HW_ERR_DMAE_FAIL: |
|---|
| 1142 | + case QED_HW_ERR_RAMROD_FAIL: |
|---|
| 1143 | + case QED_HW_ERR_FW_ASSERT: |
|---|
| 1144 | + /* Prevent HW attentions from being reasserted */ |
|---|
| 1145 | + if (test_bit(QEDI_ERR_ATTN_CLR_EN, &qedi->qedi_err_flags)) |
|---|
| 1146 | + qedi_ops->common->attn_clr_enable(qedi->cdev, true); |
|---|
| 1147 | + |
|---|
| 1148 | + if (err_type == QED_HW_ERR_RAMROD_FAIL && |
|---|
| 1149 | + test_bit(QEDI_ERR_IS_RECOVERABLE, &qedi->qedi_err_flags)) |
|---|
| 1150 | + qedi_ops->common->recovery_process(qedi->cdev); |
|---|
| 1151 | + |
|---|
| 1152 | + break; |
|---|
| 1153 | + default: |
|---|
| 1154 | + break; |
|---|
| 1155 | + } |
|---|
| 1156 | +} |
|---|
| 1157 | + |
|---|
| 1158 | +static void qedi_schedule_recovery_handler(void *dev) |
|---|
| 1159 | +{ |
|---|
| 1160 | + struct qedi_ctx *qedi = dev; |
|---|
| 1161 | + |
|---|
| 1162 | + QEDI_ERR(&qedi->dbg_ctx, "Recovery handler scheduled.\n"); |
|---|
| 1163 | + |
|---|
| 1164 | + if (test_and_set_bit(QEDI_IN_RECOVERY, &qedi->flags)) |
|---|
| 1165 | + return; |
|---|
| 1166 | + |
|---|
| 1167 | + atomic_set(&qedi->link_state, QEDI_LINK_DOWN); |
|---|
| 1168 | + |
|---|
| 1169 | + schedule_delayed_work(&qedi->recovery_work, 0); |
|---|
| 1170 | +} |
|---|
| 1171 | + |
|---|
| 1172 | +static void qedi_set_conn_recovery(struct iscsi_cls_session *cls_session) |
|---|
| 1173 | +{ |
|---|
| 1174 | + struct iscsi_session *session = cls_session->dd_data; |
|---|
| 1175 | + struct iscsi_conn *conn = session->leadconn; |
|---|
| 1176 | + struct qedi_conn *qedi_conn = conn->dd_data; |
|---|
| 1177 | + |
|---|
| 1178 | + qedi_start_conn_recovery(qedi_conn->qedi, qedi_conn); |
|---|
| 1179 | +} |
|---|
| 1180 | + |
|---|
| 1084 | 1181 | static void qedi_link_update(void *dev, struct qed_link_output *link) |
|---|
| 1085 | 1182 | { |
|---|
| 1086 | 1183 | struct qedi_ctx *qedi = (struct qedi_ctx *)dev; |
|---|
| .. | .. |
|---|
| 1092 | 1189 | QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, |
|---|
| 1093 | 1190 | "Link Down event.\n"); |
|---|
| 1094 | 1191 | atomic_set(&qedi->link_state, QEDI_LINK_DOWN); |
|---|
| 1192 | + iscsi_host_for_each_session(qedi->shost, qedi_set_conn_recovery); |
|---|
| 1095 | 1193 | } |
|---|
| 1096 | 1194 | } |
|---|
| 1097 | 1195 | |
|---|
| 1098 | 1196 | static struct qed_iscsi_cb_ops qedi_cb_ops = { |
|---|
| 1099 | 1197 | { |
|---|
| 1100 | 1198 | .link_update = qedi_link_update, |
|---|
| 1199 | + .schedule_recovery_handler = qedi_schedule_recovery_handler, |
|---|
| 1200 | + .schedule_hw_err_handler = qedi_schedule_hw_err_handler, |
|---|
| 1101 | 1201 | .get_protocol_tlv_data = qedi_get_protocol_tlv_data, |
|---|
| 1102 | 1202 | .get_generic_tlv_data = qedi_get_generic_tlv_data, |
|---|
| 1103 | 1203 | } |
|---|
| .. | .. |
|---|
| 1108 | 1208 | { |
|---|
| 1109 | 1209 | struct qedi_work *qedi_work; |
|---|
| 1110 | 1210 | struct qedi_conn *q_conn; |
|---|
| 1111 | | - struct iscsi_conn *conn; |
|---|
| 1112 | 1211 | struct qedi_cmd *qedi_cmd; |
|---|
| 1113 | 1212 | u32 iscsi_cid; |
|---|
| 1114 | 1213 | int rc = 0; |
|---|
| .. | .. |
|---|
| 1121 | 1220 | iscsi_cid); |
|---|
| 1122 | 1221 | return -1; |
|---|
| 1123 | 1222 | } |
|---|
| 1124 | | - conn = q_conn->cls_conn->dd_data; |
|---|
| 1125 | 1223 | |
|---|
| 1126 | 1224 | switch (cqe->cqe_common.cqe_type) { |
|---|
| 1127 | 1225 | case ISCSI_CQE_TYPE_SOLICITED: |
|---|
| .. | .. |
|---|
| 1254 | 1352 | "process already running\n"); |
|---|
| 1255 | 1353 | } |
|---|
| 1256 | 1354 | |
|---|
| 1257 | | - if (qedi_fp_has_work(fp) == 0) |
|---|
| 1355 | + if (!qedi_fp_has_work(fp)) |
|---|
| 1258 | 1356 | qed_sb_update_sb_idx(fp->sb_info); |
|---|
| 1259 | 1357 | |
|---|
| 1260 | 1358 | /* Check for more work */ |
|---|
| 1261 | 1359 | rmb(); |
|---|
| 1262 | 1360 | |
|---|
| 1263 | | - if (qedi_fp_has_work(fp) == 0) |
|---|
| 1361 | + if (!qedi_fp_has_work(fp)) |
|---|
| 1264 | 1362 | qed_sb_ack(fp->sb_info, IGU_INT_ENABLE, 1); |
|---|
| 1265 | 1363 | else |
|---|
| 1266 | 1364 | goto process_again; |
|---|
| .. | .. |
|---|
| 1281 | 1379 | static void qedi_sync_free_irqs(struct qedi_ctx *qedi) |
|---|
| 1282 | 1380 | { |
|---|
| 1283 | 1381 | int i; |
|---|
| 1382 | + u16 idx; |
|---|
| 1284 | 1383 | |
|---|
| 1285 | 1384 | if (qedi->int_info.msix_cnt) { |
|---|
| 1286 | 1385 | for (i = 0; i < qedi->int_info.used_cnt; i++) { |
|---|
| 1287 | | - synchronize_irq(qedi->int_info.msix[i].vector); |
|---|
| 1288 | | - irq_set_affinity_hint(qedi->int_info.msix[i].vector, |
|---|
| 1386 | + idx = i * qedi->dev_info.common.num_hwfns + |
|---|
| 1387 | + qedi_ops->common->get_affin_hwfn_idx(qedi->cdev); |
|---|
| 1388 | + |
|---|
| 1389 | + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, |
|---|
| 1390 | + "Freeing IRQ #%d vector_idx=%d.\n", i, idx); |
|---|
| 1391 | + |
|---|
| 1392 | + synchronize_irq(qedi->int_info.msix[idx].vector); |
|---|
| 1393 | + irq_set_affinity_hint(qedi->int_info.msix[idx].vector, |
|---|
| 1289 | 1394 | NULL); |
|---|
| 1290 | | - free_irq(qedi->int_info.msix[i].vector, |
|---|
| 1395 | + free_irq(qedi->int_info.msix[idx].vector, |
|---|
| 1291 | 1396 | &qedi->fp_array[i]); |
|---|
| 1292 | 1397 | } |
|---|
| 1293 | 1398 | } else { |
|---|
| .. | .. |
|---|
| 1302 | 1407 | static int qedi_request_msix_irq(struct qedi_ctx *qedi) |
|---|
| 1303 | 1408 | { |
|---|
| 1304 | 1409 | int i, rc, cpu; |
|---|
| 1410 | + u16 idx; |
|---|
| 1305 | 1411 | |
|---|
| 1306 | 1412 | cpu = cpumask_first(cpu_online_mask); |
|---|
| 1307 | | - for (i = 0; i < MIN_NUM_CPUS_MSIX(qedi); i++) { |
|---|
| 1308 | | - rc = request_irq(qedi->int_info.msix[i].vector, |
|---|
| 1413 | + for (i = 0; i < qedi->msix_count; i++) { |
|---|
| 1414 | + idx = i * qedi->dev_info.common.num_hwfns + |
|---|
| 1415 | + qedi_ops->common->get_affin_hwfn_idx(qedi->cdev); |
|---|
| 1416 | + |
|---|
| 1417 | + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, |
|---|
| 1418 | + "dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n", |
|---|
| 1419 | + qedi->dev_info.common.num_hwfns, |
|---|
| 1420 | + qedi_ops->common->get_affin_hwfn_idx(qedi->cdev)); |
|---|
| 1421 | + |
|---|
| 1422 | + rc = request_irq(qedi->int_info.msix[idx].vector, |
|---|
| 1309 | 1423 | qedi_msix_handler, 0, "qedi", |
|---|
| 1310 | 1424 | &qedi->fp_array[i]); |
|---|
| 1311 | | - |
|---|
| 1312 | 1425 | if (rc) { |
|---|
| 1313 | 1426 | QEDI_WARN(&qedi->dbg_ctx, "request_irq failed.\n"); |
|---|
| 1314 | 1427 | qedi_sync_free_irqs(qedi); |
|---|
| 1315 | 1428 | return rc; |
|---|
| 1316 | 1429 | } |
|---|
| 1317 | 1430 | qedi->int_info.used_cnt++; |
|---|
| 1318 | | - rc = irq_set_affinity_hint(qedi->int_info.msix[i].vector, |
|---|
| 1431 | + rc = irq_set_affinity_hint(qedi->int_info.msix[idx].vector, |
|---|
| 1319 | 1432 | get_cpu_mask(cpu)); |
|---|
| 1320 | 1433 | cpu = cpumask_next(cpu, cpu_online_mask); |
|---|
| 1321 | 1434 | } |
|---|
| .. | .. |
|---|
| 1327 | 1440 | { |
|---|
| 1328 | 1441 | int rc = 0; |
|---|
| 1329 | 1442 | |
|---|
| 1330 | | - rc = qedi_ops->common->set_fp_int(qedi->cdev, num_online_cpus()); |
|---|
| 1443 | + rc = qedi_ops->common->set_fp_int(qedi->cdev, qedi->num_queues); |
|---|
| 1444 | + if (rc < 0) |
|---|
| 1445 | + goto exit_setup_int; |
|---|
| 1446 | + |
|---|
| 1447 | + qedi->msix_count = rc; |
|---|
| 1448 | + |
|---|
| 1331 | 1449 | rc = qedi_ops->common->get_fp_int(qedi->cdev, &qedi->int_info); |
|---|
| 1332 | 1450 | if (rc) |
|---|
| 1333 | 1451 | goto exit_setup_int; |
|---|
| .. | .. |
|---|
| 1360 | 1478 | |
|---|
| 1361 | 1479 | static int qedi_alloc_nvm_iscsi_cfg(struct qedi_ctx *qedi) |
|---|
| 1362 | 1480 | { |
|---|
| 1363 | | - struct qedi_nvm_iscsi_image nvm_image; |
|---|
| 1364 | | - |
|---|
| 1365 | | - qedi->iscsi_image = dma_zalloc_coherent(&qedi->pdev->dev, |
|---|
| 1366 | | - sizeof(nvm_image), |
|---|
| 1367 | | - &qedi->nvm_buf_dma, |
|---|
| 1368 | | - GFP_KERNEL); |
|---|
| 1481 | + qedi->iscsi_image = dma_alloc_coherent(&qedi->pdev->dev, |
|---|
| 1482 | + sizeof(struct qedi_nvm_iscsi_image), |
|---|
| 1483 | + &qedi->nvm_buf_dma, GFP_KERNEL); |
|---|
| 1369 | 1484 | if (!qedi->iscsi_image) { |
|---|
| 1370 | 1485 | QEDI_ERR(&qedi->dbg_ctx, "Could not allocate NVM BUF.\n"); |
|---|
| 1371 | 1486 | return -ENOMEM; |
|---|
| .. | .. |
|---|
| 1382 | 1497 | int i; |
|---|
| 1383 | 1498 | |
|---|
| 1384 | 1499 | if (qedi->bdq_pbl_list) |
|---|
| 1385 | | - dma_free_coherent(&qedi->pdev->dev, PAGE_SIZE, |
|---|
| 1500 | + dma_free_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE, |
|---|
| 1386 | 1501 | qedi->bdq_pbl_list, qedi->bdq_pbl_list_dma); |
|---|
| 1387 | 1502 | |
|---|
| 1388 | 1503 | if (qedi->bdq_pbl) |
|---|
| .. | .. |
|---|
| 1443 | 1558 | |
|---|
| 1444 | 1559 | /* Alloc dma memory for BDQ page buffer list */ |
|---|
| 1445 | 1560 | qedi->bdq_pbl_mem_size = QEDI_BDQ_NUM * sizeof(struct scsi_bd); |
|---|
| 1446 | | - qedi->bdq_pbl_mem_size = ALIGN(qedi->bdq_pbl_mem_size, PAGE_SIZE); |
|---|
| 1561 | + qedi->bdq_pbl_mem_size = ALIGN(qedi->bdq_pbl_mem_size, QEDI_PAGE_SIZE); |
|---|
| 1447 | 1562 | qedi->rq_num_entries = qedi->bdq_pbl_mem_size / sizeof(struct scsi_bd); |
|---|
| 1448 | 1563 | |
|---|
| 1449 | 1564 | QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, "rq_num_entries = %d.\n", |
|---|
| .. | .. |
|---|
| 1478 | 1593 | } |
|---|
| 1479 | 1594 | |
|---|
| 1480 | 1595 | /* Allocate list of PBL pages */ |
|---|
| 1481 | | - qedi->bdq_pbl_list = dma_zalloc_coherent(&qedi->pdev->dev, PAGE_SIZE, |
|---|
| 1482 | | - &qedi->bdq_pbl_list_dma, |
|---|
| 1483 | | - GFP_KERNEL); |
|---|
| 1596 | + qedi->bdq_pbl_list = dma_alloc_coherent(&qedi->pdev->dev, |
|---|
| 1597 | + QEDI_PAGE_SIZE, |
|---|
| 1598 | + &qedi->bdq_pbl_list_dma, |
|---|
| 1599 | + GFP_KERNEL); |
|---|
| 1484 | 1600 | if (!qedi->bdq_pbl_list) { |
|---|
| 1485 | 1601 | QEDI_ERR(&qedi->dbg_ctx, |
|---|
| 1486 | 1602 | "Could not allocate list of PBL pages.\n"); |
|---|
| .. | .. |
|---|
| 1491 | 1607 | * Now populate PBL list with pages that contain pointers to the |
|---|
| 1492 | 1608 | * individual buffers. |
|---|
| 1493 | 1609 | */ |
|---|
| 1494 | | - qedi->bdq_pbl_list_num_entries = qedi->bdq_pbl_mem_size / PAGE_SIZE; |
|---|
| 1610 | + qedi->bdq_pbl_list_num_entries = qedi->bdq_pbl_mem_size / |
|---|
| 1611 | + QEDI_PAGE_SIZE; |
|---|
| 1495 | 1612 | list = (u64 *)qedi->bdq_pbl_list; |
|---|
| 1496 | 1613 | page = qedi->bdq_pbl_list_dma; |
|---|
| 1497 | 1614 | for (i = 0; i < qedi->bdq_pbl_list_num_entries; i++) { |
|---|
| 1498 | 1615 | *list = qedi->bdq_pbl_dma; |
|---|
| 1499 | 1616 | list++; |
|---|
| 1500 | | - page += PAGE_SIZE; |
|---|
| 1617 | + page += QEDI_PAGE_SIZE; |
|---|
| 1501 | 1618 | } |
|---|
| 1502 | 1619 | |
|---|
| 1503 | 1620 | return 0; |
|---|
| .. | .. |
|---|
| 1576 | 1693 | (qedi->global_queues[i]->cq_pbl_size + |
|---|
| 1577 | 1694 | (QEDI_PAGE_SIZE - 1)); |
|---|
| 1578 | 1695 | |
|---|
| 1579 | | - qedi->global_queues[i]->cq = dma_zalloc_coherent(&qedi->pdev->dev, |
|---|
| 1580 | | - qedi->global_queues[i]->cq_mem_size, |
|---|
| 1581 | | - &qedi->global_queues[i]->cq_dma, |
|---|
| 1582 | | - GFP_KERNEL); |
|---|
| 1696 | + qedi->global_queues[i]->cq = dma_alloc_coherent(&qedi->pdev->dev, |
|---|
| 1697 | + qedi->global_queues[i]->cq_mem_size, |
|---|
| 1698 | + &qedi->global_queues[i]->cq_dma, |
|---|
| 1699 | + GFP_KERNEL); |
|---|
| 1583 | 1700 | |
|---|
| 1584 | 1701 | if (!qedi->global_queues[i]->cq) { |
|---|
| 1585 | 1702 | QEDI_WARN(&qedi->dbg_ctx, |
|---|
| .. | .. |
|---|
| 1587 | 1704 | status = -ENOMEM; |
|---|
| 1588 | 1705 | goto mem_alloc_failure; |
|---|
| 1589 | 1706 | } |
|---|
| 1590 | | - qedi->global_queues[i]->cq_pbl = dma_zalloc_coherent(&qedi->pdev->dev, |
|---|
| 1591 | | - qedi->global_queues[i]->cq_pbl_size, |
|---|
| 1592 | | - &qedi->global_queues[i]->cq_pbl_dma, |
|---|
| 1593 | | - GFP_KERNEL); |
|---|
| 1707 | + qedi->global_queues[i]->cq_pbl = dma_alloc_coherent(&qedi->pdev->dev, |
|---|
| 1708 | + qedi->global_queues[i]->cq_pbl_size, |
|---|
| 1709 | + &qedi->global_queues[i]->cq_pbl_dma, |
|---|
| 1710 | + GFP_KERNEL); |
|---|
| 1594 | 1711 | |
|---|
| 1595 | 1712 | if (!qedi->global_queues[i]->cq_pbl) { |
|---|
| 1596 | 1713 | QEDI_WARN(&qedi->dbg_ctx, |
|---|
| .. | .. |
|---|
| 1658 | 1775 | ep->sq_pbl_size = (ep->sq_mem_size / QEDI_PAGE_SIZE) * sizeof(void *); |
|---|
| 1659 | 1776 | ep->sq_pbl_size = ep->sq_pbl_size + QEDI_PAGE_SIZE; |
|---|
| 1660 | 1777 | |
|---|
| 1661 | | - ep->sq = dma_zalloc_coherent(&qedi->pdev->dev, ep->sq_mem_size, |
|---|
| 1662 | | - &ep->sq_dma, GFP_KERNEL); |
|---|
| 1778 | + ep->sq = dma_alloc_coherent(&qedi->pdev->dev, ep->sq_mem_size, |
|---|
| 1779 | + &ep->sq_dma, GFP_KERNEL); |
|---|
| 1663 | 1780 | if (!ep->sq) { |
|---|
| 1664 | 1781 | QEDI_WARN(&qedi->dbg_ctx, |
|---|
| 1665 | 1782 | "Could not allocate send queue.\n"); |
|---|
| 1666 | 1783 | rval = -ENOMEM; |
|---|
| 1667 | 1784 | goto out; |
|---|
| 1668 | 1785 | } |
|---|
| 1669 | | - ep->sq_pbl = dma_zalloc_coherent(&qedi->pdev->dev, ep->sq_pbl_size, |
|---|
| 1670 | | - &ep->sq_pbl_dma, GFP_KERNEL); |
|---|
| 1786 | + ep->sq_pbl = dma_alloc_coherent(&qedi->pdev->dev, ep->sq_pbl_size, |
|---|
| 1787 | + &ep->sq_pbl_dma, GFP_KERNEL); |
|---|
| 1671 | 1788 | if (!ep->sq_pbl) { |
|---|
| 1672 | 1789 | QEDI_WARN(&qedi->dbg_ctx, |
|---|
| 1673 | 1790 | "Could not allocate send queue PBL.\n"); |
|---|
| .. | .. |
|---|
| 1864 | 1981 | struct qedi_percpu_s *p = this_cpu_ptr(&qedi_percpu); |
|---|
| 1865 | 1982 | struct qedi_work *work, *tmp; |
|---|
| 1866 | 1983 | struct task_struct *thread; |
|---|
| 1984 | + unsigned long flags; |
|---|
| 1867 | 1985 | |
|---|
| 1868 | | - spin_lock_bh(&p->p_work_lock); |
|---|
| 1986 | + spin_lock_irqsave(&p->p_work_lock, flags); |
|---|
| 1869 | 1987 | thread = p->iothread; |
|---|
| 1870 | 1988 | p->iothread = NULL; |
|---|
| 1871 | 1989 | |
|---|
| .. | .. |
|---|
| 1876 | 1994 | kfree(work); |
|---|
| 1877 | 1995 | } |
|---|
| 1878 | 1996 | |
|---|
| 1879 | | - spin_unlock_bh(&p->p_work_lock); |
|---|
| 1997 | + spin_unlock_irqrestore(&p->p_work_lock, flags); |
|---|
| 1880 | 1998 | if (thread) |
|---|
| 1881 | 1999 | kthread_stop(thread); |
|---|
| 1882 | 2000 | return 0; |
|---|
| .. | .. |
|---|
| 1902 | 2020 | qedi_ops->ll2->start(qedi->cdev, ¶ms); |
|---|
| 1903 | 2021 | } |
|---|
| 1904 | 2022 | |
|---|
| 1905 | | -/** |
|---|
| 2023 | +/* |
|---|
| 1906 | 2024 | * qedi_get_nvram_block: - Scan through the iSCSI NVRAM block (while accounting |
|---|
| 1907 | 2025 | * for gaps) for the matching absolute-pf-id of the QEDI device. |
|---|
| 1908 | 2026 | */ |
|---|
| .. | .. |
|---|
| 2204 | 2322 | static int qedi_get_boot_info(struct qedi_ctx *qedi) |
|---|
| 2205 | 2323 | { |
|---|
| 2206 | 2324 | int ret = 1; |
|---|
| 2207 | | - struct qedi_nvm_iscsi_image nvm_image; |
|---|
| 2208 | 2325 | |
|---|
| 2209 | 2326 | QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, |
|---|
| 2210 | 2327 | "Get NVM iSCSI CFG image\n"); |
|---|
| 2211 | 2328 | ret = qedi_ops->common->nvm_get_image(qedi->cdev, |
|---|
| 2212 | 2329 | QED_NVM_IMAGE_ISCSI_CFG, |
|---|
| 2213 | 2330 | (char *)qedi->iscsi_image, |
|---|
| 2214 | | - sizeof(nvm_image)); |
|---|
| 2331 | + sizeof(struct qedi_nvm_iscsi_image)); |
|---|
| 2215 | 2332 | if (ret) |
|---|
| 2216 | 2333 | QEDI_ERR(&qedi->dbg_ctx, |
|---|
| 2217 | 2334 | "Could not get NVM image. ret = %d\n", ret); |
|---|
| .. | .. |
|---|
| 2279 | 2396 | return -ENOMEM; |
|---|
| 2280 | 2397 | } |
|---|
| 2281 | 2398 | |
|---|
| 2399 | +static pci_ers_result_t qedi_io_error_detected(struct pci_dev *pdev, |
|---|
| 2400 | + pci_channel_state_t state) |
|---|
| 2401 | +{ |
|---|
| 2402 | + struct qedi_ctx *qedi = pci_get_drvdata(pdev); |
|---|
| 2403 | + |
|---|
| 2404 | + QEDI_ERR(&qedi->dbg_ctx, "%s: PCI error detected [%d]\n", |
|---|
| 2405 | + __func__, state); |
|---|
| 2406 | + |
|---|
| 2407 | + if (test_and_set_bit(QEDI_IN_RECOVERY, &qedi->flags)) { |
|---|
| 2408 | + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, |
|---|
| 2409 | + "Recovery already in progress.\n"); |
|---|
| 2410 | + return PCI_ERS_RESULT_NONE; |
|---|
| 2411 | + } |
|---|
| 2412 | + |
|---|
| 2413 | + qedi_ops->common->recovery_process(qedi->cdev); |
|---|
| 2414 | + |
|---|
| 2415 | + return PCI_ERS_RESULT_CAN_RECOVER; |
|---|
| 2416 | +} |
|---|
| 2417 | + |
|---|
| 2282 | 2418 | static void __qedi_remove(struct pci_dev *pdev, int mode) |
|---|
| 2283 | 2419 | { |
|---|
| 2284 | 2420 | struct qedi_ctx *qedi = pci_get_drvdata(pdev); |
|---|
| 2285 | 2421 | int rval; |
|---|
| 2422 | + u16 retry = 10; |
|---|
| 2286 | 2423 | |
|---|
| 2287 | | - if (qedi->tmf_thread) { |
|---|
| 2288 | | - flush_workqueue(qedi->tmf_thread); |
|---|
| 2289 | | - destroy_workqueue(qedi->tmf_thread); |
|---|
| 2290 | | - qedi->tmf_thread = NULL; |
|---|
| 2291 | | - } |
|---|
| 2424 | + if (mode == QEDI_MODE_SHUTDOWN) |
|---|
| 2425 | + iscsi_host_for_each_session(qedi->shost, |
|---|
| 2426 | + qedi_clear_session_ctx); |
|---|
| 2292 | 2427 | |
|---|
| 2293 | | - if (qedi->offload_thread) { |
|---|
| 2294 | | - flush_workqueue(qedi->offload_thread); |
|---|
| 2295 | | - destroy_workqueue(qedi->offload_thread); |
|---|
| 2296 | | - qedi->offload_thread = NULL; |
|---|
| 2428 | + if (mode == QEDI_MODE_NORMAL || mode == QEDI_MODE_SHUTDOWN) { |
|---|
| 2429 | + if (qedi->tmf_thread) { |
|---|
| 2430 | + flush_workqueue(qedi->tmf_thread); |
|---|
| 2431 | + destroy_workqueue(qedi->tmf_thread); |
|---|
| 2432 | + qedi->tmf_thread = NULL; |
|---|
| 2433 | + } |
|---|
| 2434 | + |
|---|
| 2435 | + if (qedi->offload_thread) { |
|---|
| 2436 | + flush_workqueue(qedi->offload_thread); |
|---|
| 2437 | + destroy_workqueue(qedi->offload_thread); |
|---|
| 2438 | + qedi->offload_thread = NULL; |
|---|
| 2439 | + } |
|---|
| 2297 | 2440 | } |
|---|
| 2298 | 2441 | |
|---|
| 2299 | 2442 | #ifdef CONFIG_DEBUG_FS |
|---|
| .. | .. |
|---|
| 2305 | 2448 | qedi_sync_free_irqs(qedi); |
|---|
| 2306 | 2449 | |
|---|
| 2307 | 2450 | if (!test_bit(QEDI_IN_OFFLINE, &qedi->flags)) { |
|---|
| 2308 | | - qedi_ops->stop(qedi->cdev); |
|---|
| 2451 | + while (retry--) { |
|---|
| 2452 | + rval = qedi_ops->stop(qedi->cdev); |
|---|
| 2453 | + if (rval < 0) |
|---|
| 2454 | + msleep(1000); |
|---|
| 2455 | + else |
|---|
| 2456 | + break; |
|---|
| 2457 | + } |
|---|
| 2309 | 2458 | qedi_ops->ll2->stop(qedi->cdev); |
|---|
| 2310 | 2459 | } |
|---|
| 2311 | 2460 | |
|---|
| 2312 | | - if (mode == QEDI_MODE_NORMAL) |
|---|
| 2313 | | - qedi_free_iscsi_pf_param(qedi); |
|---|
| 2461 | + cancel_delayed_work_sync(&qedi->recovery_work); |
|---|
| 2462 | + cancel_delayed_work_sync(&qedi->board_disable_work); |
|---|
| 2463 | + |
|---|
| 2464 | + qedi_free_iscsi_pf_param(qedi); |
|---|
| 2314 | 2465 | |
|---|
| 2315 | 2466 | rval = qedi_ops->common->update_drv_state(qedi->cdev, false); |
|---|
| 2316 | 2467 | if (rval) |
|---|
| .. | .. |
|---|
| 2323 | 2474 | |
|---|
| 2324 | 2475 | qedi_destroy_fp(qedi); |
|---|
| 2325 | 2476 | |
|---|
| 2326 | | - if (mode == QEDI_MODE_NORMAL) { |
|---|
| 2477 | + if (mode == QEDI_MODE_NORMAL || mode == QEDI_MODE_SHUTDOWN) { |
|---|
| 2327 | 2478 | qedi_release_cid_que(qedi); |
|---|
| 2328 | 2479 | qedi_cm_free_mem(qedi); |
|---|
| 2329 | 2480 | qedi_free_uio(qedi->udev); |
|---|
| 2330 | 2481 | qedi_free_itt(qedi); |
|---|
| 2331 | | - |
|---|
| 2332 | | - iscsi_host_remove(qedi->shost); |
|---|
| 2333 | | - iscsi_host_free(qedi->shost); |
|---|
| 2334 | 2482 | |
|---|
| 2335 | 2483 | if (qedi->ll2_recv_thread) { |
|---|
| 2336 | 2484 | kthread_stop(qedi->ll2_recv_thread); |
|---|
| .. | .. |
|---|
| 2340 | 2488 | |
|---|
| 2341 | 2489 | if (qedi->boot_kset) |
|---|
| 2342 | 2490 | iscsi_boot_destroy_kset(qedi->boot_kset); |
|---|
| 2491 | + |
|---|
| 2492 | + iscsi_host_remove(qedi->shost); |
|---|
| 2493 | + iscsi_host_free(qedi->shost); |
|---|
| 2343 | 2494 | } |
|---|
| 2495 | +} |
|---|
| 2496 | + |
|---|
| 2497 | +static void qedi_board_disable_work(struct work_struct *work) |
|---|
| 2498 | +{ |
|---|
| 2499 | + struct qedi_ctx *qedi = |
|---|
| 2500 | + container_of(work, struct qedi_ctx, |
|---|
| 2501 | + board_disable_work.work); |
|---|
| 2502 | + |
|---|
| 2503 | + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, |
|---|
| 2504 | + "Fan failure, Unloading firmware context.\n"); |
|---|
| 2505 | + |
|---|
| 2506 | + if (test_and_set_bit(QEDI_IN_SHUTDOWN, &qedi->flags)) |
|---|
| 2507 | + return; |
|---|
| 2508 | + |
|---|
| 2509 | + __qedi_remove(qedi->pdev, QEDI_MODE_SHUTDOWN); |
|---|
| 2510 | +} |
|---|
| 2511 | + |
|---|
| 2512 | +static void qedi_shutdown(struct pci_dev *pdev) |
|---|
| 2513 | +{ |
|---|
| 2514 | + struct qedi_ctx *qedi = pci_get_drvdata(pdev); |
|---|
| 2515 | + |
|---|
| 2516 | + QEDI_ERR(&qedi->dbg_ctx, "%s: Shutdown qedi\n", __func__); |
|---|
| 2517 | + if (test_and_set_bit(QEDI_IN_SHUTDOWN, &qedi->flags)) |
|---|
| 2518 | + return; |
|---|
| 2519 | + __qedi_remove(pdev, QEDI_MODE_SHUTDOWN); |
|---|
| 2520 | +} |
|---|
| 2521 | + |
|---|
| 2522 | +static int qedi_suspend(struct pci_dev *pdev, pm_message_t state) |
|---|
| 2523 | +{ |
|---|
| 2524 | + struct qedi_ctx *qedi; |
|---|
| 2525 | + |
|---|
| 2526 | + if (!pdev) { |
|---|
| 2527 | + QEDI_ERR(NULL, "pdev is NULL.\n"); |
|---|
| 2528 | + return -ENODEV; |
|---|
| 2529 | + } |
|---|
| 2530 | + |
|---|
| 2531 | + qedi = pci_get_drvdata(pdev); |
|---|
| 2532 | + |
|---|
| 2533 | + QEDI_ERR(&qedi->dbg_ctx, "%s: Device does not support suspend operation\n", __func__); |
|---|
| 2534 | + |
|---|
| 2535 | + return -EPERM; |
|---|
| 2344 | 2536 | } |
|---|
| 2345 | 2537 | |
|---|
| 2346 | 2538 | static int __qedi_probe(struct pci_dev *pdev, int mode) |
|---|
| 2347 | 2539 | { |
|---|
| 2348 | 2540 | struct qedi_ctx *qedi; |
|---|
| 2349 | 2541 | struct qed_ll2_params params; |
|---|
| 2350 | | - u32 dp_module = 0; |
|---|
| 2351 | 2542 | u8 dp_level = 0; |
|---|
| 2352 | 2543 | bool is_vf = false; |
|---|
| 2353 | 2544 | char host_buf[16]; |
|---|
| .. | .. |
|---|
| 2356 | 2547 | struct qed_probe_params qed_params; |
|---|
| 2357 | 2548 | void *task_start, *task_end; |
|---|
| 2358 | 2549 | int rc; |
|---|
| 2359 | | - u16 tmp; |
|---|
| 2550 | + u16 retry = 10; |
|---|
| 2360 | 2551 | |
|---|
| 2361 | 2552 | if (mode != QEDI_MODE_RECOVERY) { |
|---|
| 2362 | 2553 | qedi = qedi_host_alloc(pdev); |
|---|
| .. | .. |
|---|
| 2368 | 2559 | qedi = pci_get_drvdata(pdev); |
|---|
| 2369 | 2560 | } |
|---|
| 2370 | 2561 | |
|---|
| 2562 | +retry_probe: |
|---|
| 2563 | + if (mode == QEDI_MODE_RECOVERY) |
|---|
| 2564 | + msleep(2000); |
|---|
| 2565 | + |
|---|
| 2371 | 2566 | memset(&qed_params, 0, sizeof(qed_params)); |
|---|
| 2372 | 2567 | qed_params.protocol = QED_PROTOCOL_ISCSI; |
|---|
| 2373 | | - qed_params.dp_module = dp_module; |
|---|
| 2568 | + qed_params.dp_module = qedi_qed_debug; |
|---|
| 2374 | 2569 | qed_params.dp_level = dp_level; |
|---|
| 2375 | 2570 | qed_params.is_vf = is_vf; |
|---|
| 2376 | 2571 | qedi->cdev = qedi_ops->common->probe(pdev, &qed_params); |
|---|
| 2377 | 2572 | if (!qedi->cdev) { |
|---|
| 2573 | + if (mode == QEDI_MODE_RECOVERY && retry) { |
|---|
| 2574 | + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, |
|---|
| 2575 | + "Retry %d initialize hardware\n", retry); |
|---|
| 2576 | + retry--; |
|---|
| 2577 | + goto retry_probe; |
|---|
| 2578 | + } |
|---|
| 2579 | + |
|---|
| 2378 | 2580 | rc = -ENODEV; |
|---|
| 2379 | 2581 | QEDI_ERR(&qedi->dbg_ctx, "Cannot initialize hardware\n"); |
|---|
| 2380 | 2582 | goto free_host; |
|---|
| 2381 | 2583 | } |
|---|
| 2382 | 2584 | |
|---|
| 2585 | + set_bit(QEDI_ERR_ATTN_CLR_EN, &qedi->qedi_err_flags); |
|---|
| 2586 | + set_bit(QEDI_ERR_IS_RECOVERABLE, &qedi->qedi_err_flags); |
|---|
| 2383 | 2587 | atomic_set(&qedi->link_state, QEDI_LINK_DOWN); |
|---|
| 2384 | 2588 | |
|---|
| 2385 | 2589 | rc = qedi_ops->fill_dev_info(qedi->cdev, &qedi->dev_info); |
|---|
| 2386 | 2590 | if (rc) |
|---|
| 2387 | 2591 | goto free_host; |
|---|
| 2388 | 2592 | |
|---|
| 2389 | | - if (mode != QEDI_MODE_RECOVERY) { |
|---|
| 2390 | | - rc = qedi_set_iscsi_pf_param(qedi); |
|---|
| 2391 | | - if (rc) { |
|---|
| 2392 | | - rc = -ENOMEM; |
|---|
| 2393 | | - QEDI_ERR(&qedi->dbg_ctx, |
|---|
| 2394 | | - "Set iSCSI pf param fail\n"); |
|---|
| 2395 | | - goto free_host; |
|---|
| 2396 | | - } |
|---|
| 2593 | + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, |
|---|
| 2594 | + "dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n", |
|---|
| 2595 | + qedi->dev_info.common.num_hwfns, |
|---|
| 2596 | + qedi_ops->common->get_affin_hwfn_idx(qedi->cdev)); |
|---|
| 2597 | + |
|---|
| 2598 | + rc = qedi_set_iscsi_pf_param(qedi); |
|---|
| 2599 | + if (rc) { |
|---|
| 2600 | + rc = -ENOMEM; |
|---|
| 2601 | + QEDI_ERR(&qedi->dbg_ctx, |
|---|
| 2602 | + "Set iSCSI pf param fail\n"); |
|---|
| 2603 | + goto free_host; |
|---|
| 2397 | 2604 | } |
|---|
| 2398 | 2605 | |
|---|
| 2399 | 2606 | qedi_ops->common->update_pf_params(qedi->cdev, &qedi->pf_params); |
|---|
| .. | .. |
|---|
| 2452 | 2659 | "Writing %d to primary and secondary BDQ doorbell registers.\n", |
|---|
| 2453 | 2660 | qedi->bdq_prod_idx); |
|---|
| 2454 | 2661 | writew(qedi->bdq_prod_idx, qedi->bdq_primary_prod); |
|---|
| 2455 | | - tmp = readw(qedi->bdq_primary_prod); |
|---|
| 2662 | + readw(qedi->bdq_primary_prod); |
|---|
| 2456 | 2663 | writew(qedi->bdq_prod_idx, qedi->bdq_secondary_prod); |
|---|
| 2457 | | - tmp = readw(qedi->bdq_secondary_prod); |
|---|
| 2664 | + readw(qedi->bdq_secondary_prod); |
|---|
| 2458 | 2665 | |
|---|
| 2459 | 2666 | ether_addr_copy(qedi->mac, qedi->dev_info.common.hw_mac); |
|---|
| 2460 | 2667 | QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, "MAC address is %pM.\n", |
|---|
| 2461 | 2668 | qedi->mac); |
|---|
| 2462 | 2669 | |
|---|
| 2463 | | - sprintf(host_buf, "host_%d", qedi->shost->host_no); |
|---|
| 2670 | + snprintf(host_buf, sizeof(host_buf), "host_%d", qedi->shost->host_no); |
|---|
| 2464 | 2671 | qedi_ops->common->set_name(qedi->cdev, host_buf); |
|---|
| 2465 | 2672 | |
|---|
| 2466 | 2673 | qedi_ops->register_ops(qedi->cdev, &qedi_cb_ops, qedi); |
|---|
| .. | .. |
|---|
| 2584 | 2791 | goto free_tmf_thread; |
|---|
| 2585 | 2792 | } |
|---|
| 2586 | 2793 | |
|---|
| 2794 | + INIT_DELAYED_WORK(&qedi->recovery_work, qedi_recovery_handler); |
|---|
| 2795 | + INIT_DELAYED_WORK(&qedi->board_disable_work, |
|---|
| 2796 | + qedi_board_disable_work); |
|---|
| 2797 | + |
|---|
| 2587 | 2798 | /* F/w needs 1st task context memory entry for performance */ |
|---|
| 2588 | 2799 | set_bit(QEDI_RESERVE_TASK_ID, qedi->task_idx_map); |
|---|
| 2589 | 2800 | atomic_set(&qedi->num_offloads, 0); |
|---|
| .. | .. |
|---|
| 2626 | 2837 | return rc; |
|---|
| 2627 | 2838 | } |
|---|
| 2628 | 2839 | |
|---|
| 2840 | +static void qedi_mark_conn_recovery(struct iscsi_cls_session *cls_session) |
|---|
| 2841 | +{ |
|---|
| 2842 | + struct iscsi_session *session = cls_session->dd_data; |
|---|
| 2843 | + struct iscsi_conn *conn = session->leadconn; |
|---|
| 2844 | + struct qedi_conn *qedi_conn = conn->dd_data; |
|---|
| 2845 | + |
|---|
| 2846 | + iscsi_conn_failure(qedi_conn->cls_conn->dd_data, ISCSI_ERR_CONN_FAILED); |
|---|
| 2847 | +} |
|---|
| 2848 | + |
|---|
| 2849 | +static void qedi_recovery_handler(struct work_struct *work) |
|---|
| 2850 | +{ |
|---|
| 2851 | + struct qedi_ctx *qedi = |
|---|
| 2852 | + container_of(work, struct qedi_ctx, recovery_work.work); |
|---|
| 2853 | + |
|---|
| 2854 | + iscsi_host_for_each_session(qedi->shost, qedi_mark_conn_recovery); |
|---|
| 2855 | + |
|---|
| 2856 | + /* Call common_ops->recovery_prolog to allow the MFW to quiesce |
|---|
| 2857 | + * any PCI transactions. |
|---|
| 2858 | + */ |
|---|
| 2859 | + qedi_ops->common->recovery_prolog(qedi->cdev); |
|---|
| 2860 | + |
|---|
| 2861 | + __qedi_remove(qedi->pdev, QEDI_MODE_RECOVERY); |
|---|
| 2862 | + __qedi_probe(qedi->pdev, QEDI_MODE_RECOVERY); |
|---|
| 2863 | + clear_bit(QEDI_IN_RECOVERY, &qedi->flags); |
|---|
| 2864 | +} |
|---|
| 2865 | + |
|---|
| 2629 | 2866 | static int qedi_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
|---|
| 2630 | 2867 | { |
|---|
| 2631 | 2868 | return __qedi_probe(pdev, QEDI_MODE_NORMAL); |
|---|
| .. | .. |
|---|
| 2645 | 2882 | |
|---|
| 2646 | 2883 | static enum cpuhp_state qedi_cpuhp_state; |
|---|
| 2647 | 2884 | |
|---|
| 2885 | +static struct pci_error_handlers qedi_err_handler = { |
|---|
| 2886 | + .error_detected = qedi_io_error_detected, |
|---|
| 2887 | +}; |
|---|
| 2888 | + |
|---|
| 2648 | 2889 | static struct pci_driver qedi_pci_driver = { |
|---|
| 2649 | 2890 | .name = QEDI_MODULE_NAME, |
|---|
| 2650 | 2891 | .id_table = qedi_pci_tbl, |
|---|
| 2651 | 2892 | .probe = qedi_probe, |
|---|
| 2652 | 2893 | .remove = qedi_remove, |
|---|
| 2894 | + .shutdown = qedi_shutdown, |
|---|
| 2895 | + .err_handler = &qedi_err_handler, |
|---|
| 2896 | + .suspend = qedi_suspend, |
|---|
| 2653 | 2897 | }; |
|---|
| 2654 | 2898 | |
|---|
| 2655 | 2899 | static int __init qedi_init(void) |
|---|