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