staticunsignedint fnic_tgt_id_binding = 1;
module_param(fnic_tgt_id_binding, uint, 0644);
MODULE_PARM_DESC(fnic_tgt_id_binding, "Target ID binding (0 for none. 1 for binding by WWPN (default))");
unsignedint io_completions = FNIC_DFLT_IO_COMPLETIONS;
module_param(io_completions, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(io_completions, "Max CQ entries to process at a time");
unsignedint fnic_fc_trace_max_pages = 64;
module_param(fnic_fc_trace_max_pages, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(fnic_fc_trace_max_pages, "Total allocated memory pages for fc trace buffer");
staticunsignedint fnic_max_qdepth = FNIC_DFLT_QUEUE_DEPTH;
module_param(fnic_max_qdepth, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(fnic_max_qdepth, "Queue depth to report for each LUN");
unsignedint pc_rscn_handling_feature_flag = PC_RSCN_HANDLING_FEATURE_ON;
module_param(pc_rscn_handling_feature_flag, uint, 0644);
MODULE_PARM_DESC(pc_rscn_handling_feature_flag, "PCRSCN handling (0 for none. 1 to handle PCRSCN (default))");
for (i = 0; i < fnic->raw_wq_count; i++) {
error_status = ioread32(&fnic->wq[i].ctrl->error_status); if (error_status)
dev_err(&fnic->pdev->dev, "WQ[%d] error_status %d\n", i, error_status);
}
for (i = 0; i < fnic->rq_count; i++) {
error_status = ioread32(&fnic->rq[i].ctrl->error_status); if (error_status)
dev_err(&fnic->pdev->dev, "RQ[%d] error_status %d\n", i, error_status);
}
for (i = 0; i < fnic->wq_copy_count; i++) {
error_status = ioread32(&fnic->hw_copy_wq[i].ctrl->error_status); if (error_status)
dev_err(&fnic->pdev->dev, "CWQ[%d] error_status %d\n", i, error_status);
}
}
staticvoid fnic_notify_timer_start(struct fnic *fnic)
{ switch (vnic_dev_get_intr_mode(fnic->vdev)) { case VNIC_DEV_INTR_MODE_MSI: /* * Schedule first timeout immediately. The driver is * initiatialized and ready to look for link up notification
*/
mod_timer(&fnic->notify_timer, jiffies); break; default: /* Using intr for notification for INTx/MSI-X */ break;
}
}
staticint fnic_dev_wait(struct vnic_dev *vdev, int (*start)(struct vnic_dev *, int), int (*finished)(struct vnic_dev *, int *), int arg)
{ unsignedlong time; int done; int err; int count;
count = 0;
err = start(vdev, arg); if (err) return err;
/* Wait for func to complete. * Sometime schedule_timeout_uninterruptible take long time * to wake up so we do not retry as we are only waiting for * 2 seconds in while loop. By adding count, we make sure * we try atleast three times before returning -ETIMEDOUT
*/
time = jiffies + (HZ * 2); do {
err = finished(vdev, &done);
count++; if (err) return err; if (done) return 0;
schedule_timeout_uninterruptible(HZ / 10);
} while (time_after(time, jiffies) || (count < 3));
return -ETIMEDOUT;
}
staticint fnic_cleanup(struct fnic *fnic)
{ unsignedint i; int err; int raw_wq_rq_counts;
vnic_dev_disable(fnic->vdev); for (i = 0; i < fnic->intr_count; i++)
vnic_intr_mask(&fnic->intr[i]);
for (i = 0; i < fnic->rq_count; i++) {
err = vnic_rq_disable(&fnic->rq[i]); if (err) return err;
} for (i = 0; i < fnic->raw_wq_count; i++) {
err = vnic_wq_disable(&fnic->wq[i]); if (err) return err;
} for (i = 0; i < fnic->wq_copy_count; i++) {
err = vnic_wq_copy_disable(&fnic->hw_copy_wq[i]); if (err) return err;
raw_wq_rq_counts = fnic->raw_wq_count + fnic->rq_count;
fnic_wq_copy_cmpl_handler(fnic, -1, i + raw_wq_rq_counts);
}
/* Clean up completed IOs and FCS frames */
fnic_wq_cmpl_handler(fnic, -1);
fnic_rq_cmpl_handler(fnic, -1);
/* Clean up the IOs and FCS frames that have not completed */ for (i = 0; i < fnic->raw_wq_count; i++)
vnic_wq_clean(&fnic->wq[i], fnic_free_wq_buf); for (i = 0; i < fnic->rq_count; i++)
vnic_rq_clean(&fnic->rq[i], fnic_free_rq_buf); for (i = 0; i < fnic->wq_copy_count; i++)
vnic_wq_copy_clean(&fnic->hw_copy_wq[i],
fnic_wq_copy_cleanup_handler);
for (i = 0; i < fnic->cq_count; i++)
vnic_cq_clean(&fnic->cq[i]); for (i = 0; i < fnic->intr_count; i++)
vnic_intr_clean(&fnic->intr[i]);
mempool_destroy(fnic->io_req_pool);
mempool_destroy(fnic->frame_pool);
mempool_destroy(fnic->frame_elem_pool); for (i = 0; i < FNIC_SGL_NUM_CACHES; i++)
mempool_destroy(fnic->io_sgl_pool[i]);
return 0;
}
staticvoid fnic_iounmap(struct fnic *fnic)
{ if (fnic->bar0.vaddr)
iounmap(fnic->bar0.vaddr);
}
/* Find model name from PCIe subsys ID */ if (fnic_get_desc_by_devid(pdev, &desc, &subsys_desc) == 0) {
dev_info(&fnic->pdev->dev, "Model: %s\n", subsys_desc);
err = fnic_dev_wait(fnic->vdev, vnic_dev_open,
vnic_dev_open_done, CMD_OPENF_RQ_ENABLE_THEN_POST); if (err) {
dev_err(&fnic->pdev->dev, "vNIC dev open failed, aborting.\n"); goto err_out_dev_open;
}
err = vnic_dev_init(fnic->vdev, 0); if (err) {
dev_err(&fnic->pdev->dev, "vNIC dev init failed, aborting.\n"); goto err_out_dev_init;
}
err = vnic_dev_mac_addr(fnic->vdev, iport->hwmac); if (err) {
dev_err(&fnic->pdev->dev, "vNIC get MAC addr failed\n"); goto err_out_dev_mac_addr;
} /* set data_src for point-to-point mode and to keep it non-zero */
memcpy(fnic->data_src_addr, iport->hwmac, ETH_ALEN);
/* Enable hardware stripping of vlan header on ingress */
fnic_set_nic_config(fnic, 0, 0, 0, 0, 0, 0, 1);
/* Setup notification buffer area */
err = fnic_notify_set(fnic); if (err) {
dev_err(&fnic->pdev->dev, "Failed to alloc notify buffer, aborting.\n"); goto err_out_fnic_notify_set;
}
/* Setup notify timer when using MSI interrupts */ if (vnic_dev_get_intr_mode(fnic->vdev) == VNIC_DEV_INTR_MODE_MSI)
timer_setup(&fnic->notify_timer, fnic_notify_timer, 0);
/* allocate RQ buffers and post them to RQ*/ for (i = 0; i < fnic->rq_count; i++) {
err = vnic_rq_fill(&fnic->rq[i], fnic_alloc_rq_frame); if (err) {
dev_err(&fnic->pdev->dev, "fnic_alloc_rq_frame can't alloc " "frame\n"); goto err_out_alloc_rq_buf;
}
}
init_completion(&fnic->reset_completion_wait);
/* Start local port initialization */
iport->max_flogi_retries = fnic->config.flogi_retries;
iport->max_plogi_retries = fnic->config.plogi_retries;
iport->plogi_timeout = fnic->config.plogi_timeout;
iport->service_params =
(FNIC_FCP_SP_INITIATOR | FNIC_FCP_SP_RD_XRDY_DIS |
FNIC_FCP_SP_CONF_CMPL); if (fnic->config.flags & VFCF_FCP_SEQ_LVL_ERR)
iport->service_params |= FNIC_FCP_SP_RETRY;
/* Initialize the oxid reclaim list and work struct */
INIT_LIST_HEAD(&iport->oxid_pool.oxid_reclaim_list);
INIT_DELAYED_WORK(&iport->oxid_pool.oxid_reclaim_work, fdls_reclaim_oxid_handler);
/* Enable all queues */ for (i = 0; i < fnic->raw_wq_count; i++)
vnic_wq_enable(&fnic->wq[i]); for (i = 0; i < fnic->rq_count; i++) { if (!ioread32(&fnic->rq[i].ctrl->enable))
vnic_rq_enable(&fnic->rq[i]);
} for (i = 0; i < fnic->wq_copy_count; i++)
vnic_wq_copy_enable(&fnic->hw_copy_wq[i]);
vnic_dev_enable(fnic->vdev);
err = fnic_request_intr(fnic); if (err) {
dev_err(&fnic->pdev->dev, "Unable to request irq.\n"); goto err_out_fnic_request_intr;
}
/* * Sometimes when probe() fails and do not exit with an error code, * remove() gets called with 'drvdata' not set. Avoid a crash by * adding a defensive check.
*/ if (!fnic) return;
/* * Flush the fnic event queue. After this call, there should * be no event queued for this fnic device in the workqueue
*/
flush_workqueue(fnic_event_queue);
fnic_scsi_unload(fnic);
if (vnic_dev_get_intr_mode(fnic->vdev) == VNIC_DEV_INTR_MODE_MSI)
timer_delete_sync(&fnic->notify_timer);
if (fnic->config.flags & VFCF_FIP_CAPABLE) {
timer_delete_sync(&fnic->retry_fip_timer);
timer_delete_sync(&fnic->fcs_ka_timer);
timer_delete_sync(&fnic->enode_ka_timer);
timer_delete_sync(&fnic->vn_ka_timer);
if ((fnic_fdmi_support == 1) && (fnic->iport.fabric.fdmi_pending > 0))
timer_delete_sync(&fnic->iport.fabric.fdmi_timer);
fnic_stats_debugfs_remove(fnic);
/* * This stops the fnic device, masks all interrupts. Completed * CQ entries are drained. Posted WQ/RQ/Copy-WQ entries are * cleaned up
*/
fnic_cleanup(fnic);
staticint __init fnic_init_module(void)
{
size_t len; int err = 0;
printk(KERN_INFO PFX "%s, ver %s\n", DRV_DESCRIPTION, DRV_VERSION);
/* Create debugfs entries for fnic */
err = fnic_debugfs_init(); if (err < 0) {
printk(KERN_ERR PFX "Failed to create fnic directory " "for tracing and stats logging\n");
fnic_debugfs_terminate();
}
/* Allocate memory for trace buffer */
err = fnic_trace_buf_init(); if (err < 0) {
printk(KERN_ERR PFX "Trace buffer initialization Failed. " "Fnic Tracing utility is disabled\n");
fnic_trace_free();
}
/* Allocate memory for fc trace buffer */
err = fnic_fc_trace_init(); if (err < 0) {
printk(KERN_ERR PFX "FC trace buffer initialization Failed " "FC frame tracing utility is disabled\n");
fnic_fc_trace_free();
}
/* Create a cache for allocation of default size sgls */
len = sizeof(struct fnic_dflt_sgl_list);
fnic_sgl_cache[FNIC_SGL_CACHE_DFLT] = kmem_cache_create
("fnic_sgl_dflt", len + FNIC_SG_DESC_ALIGN, FNIC_SG_DESC_ALIGN,
SLAB_HWCACHE_ALIGN,
NULL); if (!fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]) {
printk(KERN_ERR PFX "failed to create fnic dflt sgl slab\n");
err = -ENOMEM; goto err_create_fnic_sgl_slab_dflt;
}
/* Create a cache for allocation of max size sgls*/
len = sizeof(struct fnic_sgl_list);
fnic_sgl_cache[FNIC_SGL_CACHE_MAX] = kmem_cache_create
("fnic_sgl_max", len + FNIC_SG_DESC_ALIGN, FNIC_SG_DESC_ALIGN,
SLAB_HWCACHE_ALIGN,
NULL); if (!fnic_sgl_cache[FNIC_SGL_CACHE_MAX]) {
printk(KERN_ERR PFX "failed to create fnic max sgl slab\n");
err = -ENOMEM; goto err_create_fnic_sgl_slab_max;
}
/* Create a cache of io_req structs for use via mempool */
fnic_io_req_cache = kmem_cache_create("fnic_io_req", sizeof(struct fnic_io_req),
0, SLAB_HWCACHE_ALIGN, NULL); if (!fnic_io_req_cache) {
printk(KERN_ERR PFX "failed to create fnic io_req slab\n");
err = -ENOMEM; goto err_create_fnic_ioreq_slab;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.