In reply to Srinadh:
An analogy to the uvm_config_db is the Linux file system. The DB is made of name-value pairs while Linux has file-contents. The first two arguments to uvm_config_db form a scope, which is like a Linux directory. The first must be a uvm_component handle, usually this, or null. The handle this is like the current directory, while null is like Linux root or /. A callback class is not derived from uvm_component, so it can't pass this as the first argument.
When your agent makes the following call, it is using the scope uvm_test_top.env_h.agent_h.callback_h
// In agent
uvm_config_db #(virtual vif)::set(this, "callback_h", "Interface", uvc_if);
That is like the Linux file
/uvm_test_top/callback_h/Interface with the contents
uvc_if.
The problem is that a callback is not a component. In your code,
callback_h seems to be a property under the agent or driver. So you should use a global scope. If you start the scope with
null, that is like the Linux root.
// In test class
uvm_config_db#(virtual vif)::set(null, "Callback", "Interface", uvc_if);
This is like the Linux file
/Callback/Interface Then get the value in the callback class with the matching call.
// In callback
uvm_config_db#(virtual vif)::get(null, "Callback", "Interface", uvc_if);
This works great if every agent has the same callback. If you need different callbacks for different agents ... see what you can uniquify that second argument.