in qedf/qedf_main.c [3260:3694]
static int __qedf_probe(struct pci_dev *pdev, int mode)
{
int rc = -EINVAL;
struct fc_lport *lport;
struct qedf_ctx *qedf = NULL;
struct Scsi_Host *host;
bool is_vf = false;
struct qed_ll2_params params;
char host_buf[20];
struct qed_link_params link_params;
int status;
void *task_start, *task_end;
struct qed_slowpath_params slowpath_params;
struct qed_probe_params qed_params;
u16 retry_cnt = 10;
/*
* When doing error recovery we didn't reap the lport so don't try
* to reallocate it.
*/
retry_probe:
if (mode == QEDF_MODE_RECOVERY)
msleep(2000);
if (mode != QEDF_MODE_RECOVERY) {
lport = libfc_host_alloc(&qedf_host_template,
sizeof(struct qedf_ctx));
if (!lport) {
QEDF_ERR(NULL, "Could not allocate lport.\n");
rc = -ENOMEM;
goto err0;
}
fc_disc_init(lport);
/* Initialize qedf_ctx */
qedf = lport_priv(lport);
set_bit(QEDF_PROBING, &qedf->flags);
qedf->lport = lport;
qedf->ctlr.lp = lport;
qedf->pdev = pdev;
qedf->dbg_ctx.pdev = pdev;
qedf->dbg_ctx.host_no = lport->host->host_no;
spin_lock_init(&qedf->hba_lock);
INIT_LIST_HEAD(&qedf->fcports);
qedf->curr_conn_id = QEDF_MAX_SESSIONS - 1;
atomic_set(&qedf->num_offloads, 0);
qedf->stop_io_on_error = false;
pci_set_drvdata(pdev, qedf);
init_completion(&qedf->fipvlan_compl);
mutex_init(&qedf->stats_mutex);
mutex_init(&qedf->flush_mutex);
qedf->flogi_pending = 0;
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_INFO,
"QLogic FastLinQ FCoE Module qedf %s, "
"FW %d.%d.%d.%d\n", QEDF_VERSION,
FW_MAJOR_VERSION, FW_MINOR_VERSION, FW_REVISION_VERSION,
FW_ENGINEERING_VERSION);
} else {
/* Init pointers during recovery */
qedf = pci_get_drvdata(pdev);
set_bit(QEDF_PROBING, &qedf->flags);
lport = qedf->lport;
}
QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, "Probe started.\n");
host = lport->host;
/* Allocate mempool for qedf_io_work structs */
qedf->io_mempool = mempool_create_slab_pool(QEDF_IO_WORK_MIN,
qedf_io_work_cache);
if (qedf->io_mempool == NULL) {
QEDF_ERR(&(qedf->dbg_ctx), "qedf->io_mempool is NULL.\n");
goto err1;
}
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_INFO, "qedf->io_mempool=%p.\n",
qedf->io_mempool);
sprintf(host_buf, "qedf_%u_link",
qedf->lport->host->host_no);
qedf->link_update_wq = create_workqueue(host_buf);
INIT_DELAYED_WORK(&qedf->link_update, qedf_handle_link_update);
INIT_DELAYED_WORK(&qedf->link_recovery, qedf_link_recovery);
INIT_DELAYED_WORK(&qedf->grcdump_work, qedf_wq_grcdump);
INIT_DELAYED_WORK(&qedf->stag_work, qedf_stag_change_work);
qedf->fipvlan_retries = qedf_fipvlan_retries;
/* Set a default prio in case DCBX doesn't converge */
if (qedf_default_prio > -1) {
/*
* This is the case where we pass a modparam in so we want to
* honor it even if dcbx doesn't converge.
*/
qedf->prio = qedf_default_prio;
} else
qedf->prio = QEDF_DEFAULT_PRIO;
/*
* Common probe. Takes care of basic hardware init and pci_*
* functions.
*/
memset(&qed_params, 0, sizeof(qed_params));
qed_params.protocol = QED_PROTOCOL_FCOE;
qed_params.dp_module = qedf_dp_module;
qed_params.dp_level = qedf_dp_level;
qed_params.is_vf = is_vf;
qedf->cdev = qed_ops->common->probe(pdev, &qed_params);
if (!qedf->cdev) {
if ((mode == QEDF_MODE_RECOVERY) && retry_cnt) {
QEDF_ERR(&qedf->dbg_ctx,
"Retry %d initialize hardware\n", retry_cnt);
retry_cnt--;
goto retry_probe;
}
QEDF_ERR(&qedf->dbg_ctx, "common probe failed.\n");
rc = -ENODEV;
goto err1;
}
/* Learn information crucial for qedf to progress */
rc = qed_ops->fill_dev_info(qedf->cdev, &qedf->dev_info);
if (rc) {
QEDF_ERR(&(qedf->dbg_ctx), "Failed to dev info.\n");
goto err1;
}
QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
"dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n",
qedf->dev_info.common.num_hwfns,
qed_ops->common->get_affin_hwfn_idx(qedf->cdev));
/* queue allocation code should come here
* order should be
* slowpath_start
* status block allocation
* interrupt registration (to get min number of queues)
* set_fcoe_pf_param
* qed_sp_fcoe_func_start
*/
rc = qedf_set_fcoe_pf_param(qedf);
if (rc) {
QEDF_ERR(&(qedf->dbg_ctx), "Cannot set fcoe pf param.\n");
goto err2;
}
qed_ops->common->update_pf_params(qedf->cdev, &qedf->pf_params);
/* Learn information crucial for qedf to progress */
rc = qed_ops->fill_dev_info(qedf->cdev, &qedf->dev_info);
if (rc) {
QEDF_ERR(&qedf->dbg_ctx, "Failed to fill dev info.\n");
goto err2;
}
if (mode != QEDF_MODE_RECOVERY) {
qedf->devlink = qed_ops->common->devlink_register(qedf->cdev);
if (IS_ERR(qedf->devlink)) {
QEDF_ERR(&qedf->dbg_ctx, "Cannot register devlink\n");
rc = PTR_ERR(qedf->devlink);
qedf->devlink = NULL;
goto err2;
}
}
/* Record BDQ producer doorbell addresses */
qedf->bdq_primary_prod = qedf->dev_info.primary_dbq_rq_addr;
qedf->bdq_secondary_prod = qedf->dev_info.secondary_bdq_rq_addr;
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC,
"BDQ primary_prod=%p secondary_prod=%p.\n", qedf->bdq_primary_prod,
qedf->bdq_secondary_prod);
qed_ops->register_ops(qedf->cdev, &qedf_cb_ops, qedf);
rc = qedf_prepare_sb(qedf);
if (rc) {
QEDF_ERR(&(qedf->dbg_ctx), "Cannot start slowpath.\n");
goto err2;
}
/* Start the Slowpath-process */
slowpath_params.int_mode = QED_INT_MODE_MSIX;
slowpath_params.drv_major = QEDF_DRIVER_MAJOR_VER;
slowpath_params.drv_minor = QEDF_DRIVER_MINOR_VER;
slowpath_params.drv_rev = QEDF_DRIVER_REV_VER;
slowpath_params.drv_eng = QEDF_DRIVER_ENG_VER;
strncpy(slowpath_params.name, "qedf", QED_DRV_VER_STR_SIZE);
rc = qed_ops->common->slowpath_start(qedf->cdev, &slowpath_params);
if (rc) {
QEDF_ERR(&(qedf->dbg_ctx), "Cannot start slowpath.\n");
goto err2;
}
/*
* update_pf_params needs to be called before and after slowpath
* start
*/
qed_ops->common->update_pf_params(qedf->cdev, &qedf->pf_params);
/* Setup interrupts */
rc = qedf_setup_int(qedf);
if (rc) {
QEDF_ERR(&qedf->dbg_ctx, "Setup interrupts failed.\n");
goto err3;
}
rc = qed_ops->start(qedf->cdev, &qedf->tasks);
if (rc) {
QEDF_ERR(&(qedf->dbg_ctx), "Cannot start FCoE function.\n");
goto err4;
}
task_start = qedf_get_task_mem(&qedf->tasks, 0);
task_end = qedf_get_task_mem(&qedf->tasks, MAX_TID_BLOCKS_FCOE - 1);
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "Task context start=%p, "
"end=%p block_size=%u.\n", task_start, task_end,
qedf->tasks.size);
/*
* 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.
*/
qedf->bdq_prod_idx = QEDF_BDQ_SIZE;
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC,
"Writing %d to primary and secondary BDQ doorbell registers.\n",
qedf->bdq_prod_idx);
writew(qedf->bdq_prod_idx, qedf->bdq_primary_prod);
readw(qedf->bdq_primary_prod);
writew(qedf->bdq_prod_idx, qedf->bdq_secondary_prod);
readw(qedf->bdq_secondary_prod);
qed_ops->common->set_power_state(qedf->cdev, PCI_D0);
/* Now that the dev_info struct has been filled in set the MAC
* address
*/
ether_addr_copy(qedf->mac, qedf->dev_info.common.hw_mac);
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "MAC address is %pM.\n",
qedf->mac);
/*
* Set the WWNN and WWPN in the following way:
*
* If the info we get from qed is non-zero then use that to set the
* WWPN and WWNN. Otherwise fall back to use fcoe_wwn_from_mac() based
* on the MAC address.
*/
if (qedf->dev_info.wwnn != 0 && qedf->dev_info.wwpn != 0) {
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC,
"Setting WWPN and WWNN from qed dev_info.\n");
qedf->wwnn = qedf->dev_info.wwnn;
qedf->wwpn = qedf->dev_info.wwpn;
} else {
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC,
"Setting WWPN and WWNN using fcoe_wwn_from_mac().\n");
qedf->wwnn = fcoe_wwn_from_mac(qedf->mac, 1, 0);
qedf->wwpn = fcoe_wwn_from_mac(qedf->mac, 2, 0);
}
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "WWNN=%016llx "
"WWPN=%016llx.\n", qedf->wwnn, qedf->wwpn);
sprintf(host_buf, "host_%d", host->host_no);
qed_ops->common->set_name(qedf->cdev, host_buf);
/* Allocate cmd mgr */
qedf->cmd_mgr = qedf_cmd_mgr_alloc(qedf);
if (!qedf->cmd_mgr) {
QEDF_ERR(&(qedf->dbg_ctx), "Failed to allocate cmd mgr.\n");
rc = -ENOMEM;
goto err5;
}
if (mode != QEDF_MODE_RECOVERY) {
host->transportt = qedf_fc_transport_template;
host->max_lun = qedf_max_lun;
host->max_cmd_len = QEDF_MAX_CDB_LEN;
host->max_id = QEDF_MAX_SESSIONS;
host->can_queue = FCOE_PARAMS_NUM_TASKS;
rc = scsi_add_host(host, &pdev->dev);
if (rc) {
QEDF_WARN(&qedf->dbg_ctx,
"Error adding Scsi_Host rc=0x%x.\n", rc);
goto err6;
}
}
memset(¶ms, 0, sizeof(params));
params.mtu = QEDF_LL2_BUF_SIZE;
ether_addr_copy(params.ll2_mac_address, qedf->mac);
/* Start LL2 processing thread */
snprintf(host_buf, 20, "qedf_%d_ll2", host->host_no);
qedf->ll2_recv_wq =
create_workqueue(host_buf);
if (!qedf->ll2_recv_wq) {
QEDF_ERR(&(qedf->dbg_ctx), "Failed to LL2 workqueue.\n");
rc = -ENOMEM;
goto err7;
}
#ifdef CONFIG_DEBUG_FS
qedf_dbg_host_init(&(qedf->dbg_ctx), qedf_debugfs_ops,
qedf_dbg_fops);
#endif
/* Start LL2 */
qed_ops->ll2->register_cb_ops(qedf->cdev, &qedf_ll2_cb_ops, qedf);
rc = qed_ops->ll2->start(qedf->cdev, ¶ms);
if (rc) {
QEDF_ERR(&(qedf->dbg_ctx), "Could not start Light L2.\n");
goto err7;
}
set_bit(QEDF_LL2_STARTED, &qedf->flags);
/* Set initial FIP/FCoE VLAN to NULL */
qedf->vlan_id = 0;
/*
* No need to setup fcoe_ctlr or fc_lport objects during recovery since
* they were not reaped during the unload process.
*/
if (mode != QEDF_MODE_RECOVERY) {
/* Setup imbedded fcoe controller */
qedf_fcoe_ctlr_setup(qedf);
/* Setup lport */
rc = qedf_lport_setup(qedf);
if (rc) {
QEDF_ERR(&(qedf->dbg_ctx),
"qedf_lport_setup failed.\n");
goto err7;
}
}
sprintf(host_buf, "qedf_%u_timer", qedf->lport->host->host_no);
qedf->timer_work_queue =
create_workqueue(host_buf);
if (!qedf->timer_work_queue) {
QEDF_ERR(&(qedf->dbg_ctx), "Failed to start timer "
"workqueue.\n");
rc = -ENOMEM;
goto err7;
}
/* DPC workqueue is not reaped during recovery unload */
if (mode != QEDF_MODE_RECOVERY) {
sprintf(host_buf, "qedf_%u_dpc",
qedf->lport->host->host_no);
qedf->dpc_wq = create_workqueue(host_buf);
}
INIT_DELAYED_WORK(&qedf->recovery_work, qedf_recovery_handler);
/*
* GRC dump and sysfs parameters are not reaped during the recovery
* unload process.
*/
if (mode != QEDF_MODE_RECOVERY) {
qedf->grcdump_size =
qed_ops->common->dbg_all_data_size(qedf->cdev);
if (qedf->grcdump_size) {
rc = qedf_alloc_grc_dump_buf(&qedf->grcdump,
qedf->grcdump_size);
if (rc) {
QEDF_ERR(&(qedf->dbg_ctx),
"GRC Dump buffer alloc failed.\n");
qedf->grcdump = NULL;
}
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC,
"grcdump: addr=%p, size=%u.\n",
qedf->grcdump, qedf->grcdump_size);
}
qedf_create_sysfs_ctx_attr(qedf);
/* Initialize I/O tracing for this adapter */
spin_lock_init(&qedf->io_trace_lock);
qedf->io_trace_idx = 0;
}
init_completion(&qedf->flogi_compl);
status = qed_ops->common->update_drv_state(qedf->cdev, true);
if (status)
QEDF_ERR(&(qedf->dbg_ctx),
"Failed to send drv state to MFW.\n");
memset(&link_params, 0, sizeof(struct qed_link_params));
link_params.link_up = true;
status = qed_ops->common->set_link(qedf->cdev, &link_params);
if (status)
QEDF_WARN(&(qedf->dbg_ctx), "set_link failed.\n");
/* Start/restart discovery */
if (mode == QEDF_MODE_RECOVERY)
fcoe_ctlr_link_up(&qedf->ctlr);
else
fc_fabric_login(lport);
QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, "Probe done.\n");
clear_bit(QEDF_PROBING, &qedf->flags);
/* All good */
return 0;
err7:
if (qedf->ll2_recv_wq)
destroy_workqueue(qedf->ll2_recv_wq);
fc_remove_host(qedf->lport->host);
scsi_remove_host(qedf->lport->host);
#ifdef CONFIG_DEBUG_FS
qedf_dbg_host_exit(&(qedf->dbg_ctx));
#endif
err6:
qedf_cmd_mgr_free(qedf->cmd_mgr);
err5:
qed_ops->stop(qedf->cdev);
err4:
qedf_free_fcoe_pf_param(qedf);
qedf_sync_free_irqs(qedf);
err3:
qed_ops->common->slowpath_stop(qedf->cdev);
err2:
qed_ops->common->remove(qedf->cdev);
err1:
scsi_host_put(lport->host);
err0:
if (qedf) {
QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, "Probe done.\n");
clear_bit(QEDF_PROBING, &qedf->flags);
}
return rc;
}