On Tue, Oct 18, 2022 at 10:15:57AM +0200, Daniel Wagner wrote: > On Mon, Oct 10, 2022 at 07:15:08PM +0200, Klaus Jensen wrote: > > This is all upstream. Namespaces with 'shared=on' *should* all be > > automatically attached to any hotplugged controller devices. > > > > With what setup is this not working for you? > > Ah okay, I missed the 'shared=on' bit. Let me try again.
Nope, that's not enough. Maybe my setup is not okay? <qemu:commandline> <qemu:arg value='-device'/> <qemu:arg value='pcie-root-port,id=root,slot=1'/> </qemu:commandline> qemu-monitor-command tw0 --hmp drive_add 0 if=none,file=/tmp/nvme1.qcow2,format=qcow2,id=nvme1 qemu-monitor-command tw0 --hmp device_add nvme,id=nvme1,serial=nvme-1,bus=root qemu-monitor-command tw0 --hmp device_add nvme-ns,drive=nvme1,nsid=1,shared=on Error: Bus 'nvme1' does not support hotplugging With the patch below the hotplugging works. diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 87aeba0564..a09a698873 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -5711,8 +5711,6 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req) } nvme_attach_ns(ctrl, ns); - nvme_select_iocs_ns(ctrl, ns); - break; case NVME_NS_ATTACHMENT_DETACH: @@ -5720,26 +5718,12 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req) return NVME_NS_NOT_ATTACHED | NVME_DNR; } - ctrl->namespaces[nsid] = NULL; - ns->attached--; - - nvme_update_dmrsl(ctrl); - + nvme_detach_ns(ctrl, ns); break; default: return NVME_INVALID_FIELD | NVME_DNR; } - - /* - * Add namespace id to the changed namespace id list for event clearing - * via Get Log Page command. - */ - if (!test_and_set_bit(nsid, ctrl->changed_nsids)) { - nvme_enqueue_event(ctrl, NVME_AER_TYPE_NOTICE, - NVME_AER_INFO_NOTICE_NS_ATTR_CHANGED, - NVME_LOG_CHANGED_NSLIST); - } } return NVME_SUCCESS; @@ -7564,6 +7548,34 @@ void nvme_attach_ns(NvmeCtrl *n, NvmeNamespace *ns) n->dmrsl = MIN_NON_ZERO(n->dmrsl, BDRV_REQUEST_MAX_BYTES / nvme_l2b(ns, 1)); + if (NVME_CC_EN(n->bar.cc)) { + /* Ctrl is live */ + nvme_select_iocs_ns(n, ns); + if (!test_and_set_bit(nsid, n->changed_nsids)) { + nvme_enqueue_event(n, NVME_AER_TYPE_NOTICE, + NVME_AER_INFO_NOTICE_NS_ATTR_CHANGED, + NVME_LOG_CHANGED_NSLIST); + } + } +} + +void nvme_detach_ns(NvmeCtrl *n, NvmeNamespace *ns) +{ + uint32_t nsid = ns->params.nsid; + + if (ns->attached) { + n->namespaces[nsid - 1] = NULL; + ns->attached--; + } + nvme_update_dmrsl(n); + if (NVME_CC_EN(n->bar.cc)) { + /* Ctrl is live */ + if (!test_and_set_bit(nsid, n->changed_nsids)) { + nvme_enqueue_event(n, NVME_AER_TYPE_NOTICE, + NVME_AER_INFO_NOTICE_NS_ATTR_CHANGED, + NVME_LOG_CHANGED_NSLIST); + } + } } static void nvme_realize(PCIDevice *pci_dev, Error **errp) @@ -7600,6 +7612,7 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) return; } nvme_init_ctrl(n, pci_dev); + qbus_set_bus_hotplug_handler(BUS(&n->bus)); /* setup a namespace if the controller drive property was given */ if (n->namespace.blkconf.blk) { @@ -7817,10 +7830,22 @@ static const TypeInfo nvme_info = { }, }; +static void nvme_bus_class_init(ObjectClass *klass, void *data) +{ + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); + + hc->unplug = qdev_simple_device_unplug_cb; +} + static const TypeInfo nvme_bus_info = { .name = TYPE_NVME_BUS, .parent = TYPE_BUS, .instance_size = sizeof(NvmeBus), + .class_init = nvme_bus_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } + } }; static void nvme_register_types(void) diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c index 62a1f97be0..69ba08b0e7 100644 --- a/hw/nvme/ns.c +++ b/hw/nvme/ns.c @@ -530,10 +530,31 @@ void nvme_ns_cleanup(NvmeNamespace *ns) static void nvme_ns_unrealize(DeviceState *dev) { NvmeNamespace *ns = NVME_NS(dev); + BusState *s = qdev_get_parent_bus(dev); + NvmeCtrl *n = NVME(s->parent); + NvmeSubsystem *subsys = n->subsys; + uint32_t nsid = ns->params.nsid; + int i; nvme_ns_drain(ns); nvme_ns_shutdown(ns); nvme_ns_cleanup(ns); + + if (subsys) { + subsys->namespaces[nsid] = NULL; + + if (ns->params.shared) { + for (i = 0; i < ARRAY_SIZE(subsys->ctrls); i++) { + NvmeCtrl *ctrl = subsys->ctrls[i]; + + if (ctrl) { + nvme_detach_ns(ctrl, ns); + } + } + return; + } + } + nvme_detach_ns(n, ns); } static void nvme_ns_realize(DeviceState *dev, Error **errp) diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h index 79f5c281c2..7d9fc2ab28 100644 --- a/hw/nvme/nvme.h +++ b/hw/nvme/nvme.h @@ -576,6 +576,7 @@ static inline NvmeSecCtrlEntry *nvme_sctrl_for_cntlid(NvmeCtrl *n, } void nvme_attach_ns(NvmeCtrl *n, NvmeNamespace *ns); +void nvme_detach_ns(NvmeCtrl *n, NvmeNamespace *ns); uint16_t nvme_bounce_data(NvmeCtrl *n, void *ptr, uint32_t len, NvmeTxDirection dir, NvmeRequest *req); uint16_t nvme_bounce_mdata(NvmeCtrl *n, void *ptr, uint32_t len,