in qedi/qedi_main.c [2509:2809]
static int __qedi_probe(struct pci_dev *pdev, int mode)
{
struct qedi_ctx *qedi;
struct qed_ll2_params params;
u8 dp_level = 0;
bool is_vf = false;
char host_buf[16];
struct qed_link_params link_params;
struct qed_slowpath_params sp_params;
struct qed_probe_params qed_params;
void *task_start, *task_end;
int rc;
u16 retry = 10;
if (mode != QEDI_MODE_RECOVERY) {
qedi = qedi_host_alloc(pdev);
if (!qedi) {
rc = -ENOMEM;
goto exit_probe;
}
} else {
qedi = pci_get_drvdata(pdev);
}
retry_probe:
if (mode == QEDI_MODE_RECOVERY)
msleep(2000);
memset(&qed_params, 0, sizeof(qed_params));
qed_params.protocol = QED_PROTOCOL_ISCSI;
qed_params.dp_module = qedi_qed_debug;
qed_params.dp_level = dp_level;
qed_params.is_vf = is_vf;
qedi->cdev = qedi_ops->common->probe(pdev, &qed_params);
if (!qedi->cdev) {
if (mode == QEDI_MODE_RECOVERY && retry) {
QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
"Retry %d initialize hardware\n", retry);
retry--;
goto retry_probe;
}
rc = -ENODEV;
QEDI_ERR(&qedi->dbg_ctx, "Cannot initialize hardware\n");
goto free_host;
}
set_bit(QEDI_ERR_ATTN_CLR_EN, &qedi->qedi_err_flags);
set_bit(QEDI_ERR_IS_RECOVERABLE, &qedi->qedi_err_flags);
atomic_set(&qedi->link_state, QEDI_LINK_DOWN);
rc = qedi_ops->fill_dev_info(qedi->cdev, &qedi->dev_info);
if (rc)
goto free_host;
QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
"dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n",
qedi->dev_info.common.num_hwfns,
qedi_ops->common->get_affin_hwfn_idx(qedi->cdev));
rc = qedi_set_iscsi_pf_param(qedi);
if (rc) {
rc = -ENOMEM;
QEDI_ERR(&qedi->dbg_ctx,
"Set iSCSI pf param fail\n");
goto free_host;
}
qedi_ops->common->update_pf_params(qedi->cdev, &qedi->pf_params);
rc = qedi_prepare_fp(qedi);
if (rc) {
QEDI_ERR(&qedi->dbg_ctx, "Cannot start slowpath.\n");
goto free_pf_params;
}
/* Start the Slowpath-process */
memset(&sp_params, 0, sizeof(struct qed_slowpath_params));
sp_params.int_mode = QED_INT_MODE_MSIX;
sp_params.drv_major = QEDI_DRIVER_MAJOR_VER;
sp_params.drv_minor = QEDI_DRIVER_MINOR_VER;
sp_params.drv_rev = QEDI_DRIVER_REV_VER;
sp_params.drv_eng = QEDI_DRIVER_ENG_VER;
strlcpy(sp_params.name, "qedi iSCSI", QED_DRV_VER_STR_SIZE);
rc = qedi_ops->common->slowpath_start(qedi->cdev, &sp_params);
if (rc) {
QEDI_ERR(&qedi->dbg_ctx, "Cannot start slowpath\n");
goto stop_hw;
}
/* update_pf_params needs to be called before and after slowpath
* start
*/
qedi_ops->common->update_pf_params(qedi->cdev, &qedi->pf_params);
rc = qedi_setup_int(qedi);
if (rc)
goto stop_iscsi_func;
qedi_ops->common->set_power_state(qedi->cdev, PCI_D0);
/* Learn information crucial for qedi to progress */
rc = qedi_ops->fill_dev_info(qedi->cdev, &qedi->dev_info);
if (rc)
goto stop_iscsi_func;
/* Record BDQ producer doorbell addresses */
qedi->bdq_primary_prod = qedi->dev_info.primary_dbq_rq_addr;
qedi->bdq_secondary_prod = qedi->dev_info.secondary_bdq_rq_addr;
QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC,
"BDQ primary_prod=%p secondary_prod=%p.\n",
qedi->bdq_primary_prod,
qedi->bdq_secondary_prod);
/*
* We need to write the number of BDs in the BDQ we've preallocated so
* the f/w will do a prefetch and we'll get an unsolicited CQE when a
* packet arrives.
*/
qedi->bdq_prod_idx = QEDI_BDQ_NUM;
QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC,
"Writing %d to primary and secondary BDQ doorbell registers.\n",
qedi->bdq_prod_idx);
writew(qedi->bdq_prod_idx, qedi->bdq_primary_prod);
readw(qedi->bdq_primary_prod);
writew(qedi->bdq_prod_idx, qedi->bdq_secondary_prod);
readw(qedi->bdq_secondary_prod);
ether_addr_copy(qedi->mac, qedi->dev_info.common.hw_mac);
QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, "MAC address is %pM.\n",
qedi->mac);
snprintf(host_buf, sizeof(host_buf), "host_%d", qedi->shost->host_no);
qedi_ops->common->set_name(qedi->cdev, host_buf);
qedi_ops->register_ops(qedi->cdev, &qedi_cb_ops, qedi);
memset(¶ms, 0, sizeof(params));
params.mtu = DEF_PATH_MTU + IPV6_HDR_LEN + TCP_HDR_LEN;
qedi->ll2_mtu = DEF_PATH_MTU;
params.drop_ttl0_packets = 0;
params.rx_vlan_stripping = 1;
ether_addr_copy(params.ll2_mac_address, qedi->dev_info.common.hw_mac);
if (mode != QEDI_MODE_RECOVERY) {
/* set up rx path */
INIT_LIST_HEAD(&qedi->ll2_skb_list);
spin_lock_init(&qedi->ll2_lock);
/* start qedi context */
spin_lock_init(&qedi->hba_lock);
spin_lock_init(&qedi->task_idx_lock);
mutex_init(&qedi->stats_lock);
}
qedi_ops->ll2->register_cb_ops(qedi->cdev, &qedi_ll2_cb_ops, qedi);
qedi_ops->ll2->start(qedi->cdev, ¶ms);
if (mode != QEDI_MODE_RECOVERY) {
qedi->ll2_recv_thread = kthread_run(qedi_ll2_recv_thread,
(void *)qedi,
"qedi_ll2_thread");
}
rc = qedi_ops->start(qedi->cdev, &qedi->tasks,
qedi, qedi_iscsi_event_cb);
if (rc) {
rc = -ENODEV;
QEDI_ERR(&qedi->dbg_ctx, "Cannot start iSCSI function\n");
goto stop_slowpath;
}
task_start = qedi_get_task_mem(&qedi->tasks, 0);
task_end = qedi_get_task_mem(&qedi->tasks, MAX_TID_BLOCKS_ISCSI - 1);
QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC,
"Task context start=%p, end=%p block_size=%u.\n",
task_start, task_end, qedi->tasks.size);
memset(&link_params, 0, sizeof(link_params));
link_params.link_up = true;
rc = qedi_ops->common->set_link(qedi->cdev, &link_params);
if (rc) {
QEDI_WARN(&qedi->dbg_ctx, "Link set up failed.\n");
atomic_set(&qedi->link_state, QEDI_LINK_DOWN);
}
#ifdef CONFIG_DEBUG_FS
qedi_dbg_host_init(&qedi->dbg_ctx, qedi_debugfs_ops,
qedi_dbg_fops);
#endif
QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
"QLogic FastLinQ iSCSI Module qedi %s, FW %d.%d.%d.%d\n",
QEDI_MODULE_VERSION, FW_MAJOR_VERSION, FW_MINOR_VERSION,
FW_REVISION_VERSION, FW_ENGINEERING_VERSION);
if (mode == QEDI_MODE_NORMAL) {
if (iscsi_host_add(qedi->shost, &pdev->dev)) {
QEDI_ERR(&qedi->dbg_ctx,
"Could not add iscsi host\n");
rc = -ENOMEM;
goto remove_host;
}
/* Allocate uio buffers */
rc = qedi_alloc_uio_rings(qedi);
if (rc) {
QEDI_ERR(&qedi->dbg_ctx,
"UIO alloc ring failed err=%d\n", rc);
goto remove_host;
}
rc = qedi_init_uio(qedi);
if (rc) {
QEDI_ERR(&qedi->dbg_ctx,
"UIO init failed, err=%d\n", rc);
goto free_uio;
}
/* host the array on iscsi_conn */
rc = qedi_setup_cid_que(qedi);
if (rc) {
QEDI_ERR(&qedi->dbg_ctx,
"Could not setup cid que\n");
goto free_uio;
}
rc = qedi_cm_alloc_mem(qedi);
if (rc) {
QEDI_ERR(&qedi->dbg_ctx,
"Could not alloc cm memory\n");
goto free_cid_que;
}
rc = qedi_alloc_itt(qedi);
if (rc) {
QEDI_ERR(&qedi->dbg_ctx,
"Could not alloc itt memory\n");
goto free_cid_que;
}
sprintf(host_buf, "host_%d", qedi->shost->host_no);
qedi->tmf_thread = create_singlethread_workqueue(host_buf);
if (!qedi->tmf_thread) {
QEDI_ERR(&qedi->dbg_ctx,
"Unable to start tmf thread!\n");
rc = -ENODEV;
goto free_cid_que;
}
sprintf(host_buf, "qedi_ofld%d", qedi->shost->host_no);
qedi->offload_thread = create_workqueue(host_buf);
if (!qedi->offload_thread) {
QEDI_ERR(&qedi->dbg_ctx,
"Unable to start offload thread!\n");
rc = -ENODEV;
goto free_tmf_thread;
}
INIT_DELAYED_WORK(&qedi->recovery_work, qedi_recovery_handler);
INIT_DELAYED_WORK(&qedi->board_disable_work,
qedi_board_disable_work);
/* F/w needs 1st task context memory entry for performance */
set_bit(QEDI_RESERVE_TASK_ID, qedi->task_idx_map);
atomic_set(&qedi->num_offloads, 0);
if (qedi_setup_boot_info(qedi))
QEDI_ERR(&qedi->dbg_ctx,
"No iSCSI boot target configured\n");
rc = qedi_ops->common->update_drv_state(qedi->cdev, true);
if (rc)
QEDI_ERR(&qedi->dbg_ctx,
"Failed to send drv state to MFW\n");
}
return 0;
free_tmf_thread:
destroy_workqueue(qedi->tmf_thread);
free_cid_que:
qedi_release_cid_que(qedi);
free_uio:
qedi_free_uio(qedi->udev);
remove_host:
#ifdef CONFIG_DEBUG_FS
qedi_dbg_host_exit(&qedi->dbg_ctx);
#endif
iscsi_host_remove(qedi->shost);
stop_iscsi_func:
qedi_ops->stop(qedi->cdev);
stop_slowpath:
qedi_ops->common->slowpath_stop(qedi->cdev);
stop_hw:
qedi_ops->common->remove(qedi->cdev);
free_pf_params:
qedi_free_iscsi_pf_param(qedi);
free_host:
iscsi_host_free(qedi->shost);
exit_probe:
return rc;
}