ZVOLs are "created" through zvol_create_minor(name, dev) (by ioctls on /dev/zfs, and therefore zfs_ioctl.c). NetBSD's implementations uses namei(9) to find the vnode of the device node of the given volume, and then the minor number is determined with VOP_GETATTR(9).
Each ZVOL's soft state (struct zvol_softc, which is based on Solaris's struct zvol_state) is stored in an array, zvol_softcs, of pointers. Individual softcs are accessed and manipulated, by minor number, through zvol_softc_get(minor), zvol_softc_zalloc(minor), zvol_softc_free(minor). This behaviour is largely based on that of cgd(4).
However, I have to say that I have not been able to fully make top and bottom of how a disk driver like this should work. Though, for instance, cgd and vnd both provide virtual disk drivers through pre-configured device nodes, they accomplish this (seemingly) differently. To wit, cgd maintains an array of softcs, as I currently do in zvol, and uses neither CFATTACH nor CFDRIVER_DECL (as is the same for ccd). The vnd driver does, and it accesses each zvol with driver_lookup(). Having to pick one approach, I'll go with c.?d(4)'s (because I've already implemented that). However, vnd is the only one loadable as an LKM.
A lot of other things have happened since I've last posted, which has been a long time. Rather than try to recap everything at once, I'd prefer to focus on moving forward.