diff mbox

[3/4] SCSI-Hotdel: Implement drive_hot_del

Message ID 1253287594-12905-4-git-send-email-wolfgang.mauerer@siemens.com
State Superseded
Headers show

Commit Message

Wolfgang Mauerer Sept. 18, 2009, 3:26 p.m. UTC
This commit implements the method drive_hot_del() that allows
for hot-removing drives. It also introduces a new
monitor command drive_del, which acts as counterpart
to drive_add.

Signed-off-by: Wolfgang Mauerer <wolfgang.mauerer@siemens.com>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/pci-hotplug.c |   92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-monitor.hx  |   14 +++++++-
 sysemu.h         |    1 +
 3 files changed, 106 insertions(+), 1 deletions(-)

Comments

Gerd Hoffmann Sept. 21, 2009, 7:53 a.m. UTC | #1
Hi,

> +     dinfo = drive_get(type, bus, unit);
> +     if (!dinfo) {
> +         monitor_printf(mon, "Trying to remove non-existent device\n");
> +	 return;
> +     }

No.  Just don't do this silly if/bus/unit parsing.  At very minimum use 
drive_get_by_id() here, then have something like 'drive_del $id'.

IMHO much better would be to go qdev instead though.  We should have 
generic device_add + device_del monitor commands which work for any 
device, pretty much like the -device command line switch.

cheers,
   Gerd
Wolfgang Mauerer Sept. 30, 2009, 3:45 p.m. UTC | #2
Gerd Hoffmann wrote:
>    Hi,
> 
>> +     dinfo = drive_get(type, bus, unit);
>> +     if (!dinfo) {
>> +         monitor_printf(mon, "Trying to remove non-existent device\n");
>> +	 return;
>> +     }
> 
> No.  Just don't do this silly if/bus/unit parsing.  At very minimum use 
> drive_get_by_id() here, then have something like 'drive_del $id'.
> 
> IMHO much better would be to go qdev instead though.  We should have 
> generic device_add + device_del monitor commands which work for any 
> device, pretty much like the -device command line switch.

That makes sense, but I'd nevertheless prefer to stick with the
more traditional approach right now, replacing the
bus/unit parsing with an ID-based variant. However, is there any
standard way to get from an instance of DriveInfo to
the corresponding instance of SCSIDevice respectively
SCSIDeviceInfo? It's a bit unclear to me if there is
no such connection, of if I'm just overlooking something.

Thanks, Wolfgang
Gerd Hoffmann Sept. 30, 2009, 7:04 p.m. UTC | #3
On 09/30/09 17:45, Wolfgang Mauerer wrote:
> Gerd Hoffmann wrote:
>>     Hi,
>>
>>> +     dinfo = drive_get(type, bus, unit);
>>> +     if (!dinfo) {
>>> +         monitor_printf(mon, "Trying to remove non-existent device\n");
>>> +	 return;
>>> +     }
>>
>> No.  Just don't do this silly if/bus/unit parsing.  At very minimum use
>> drive_get_by_id() here, then have something like 'drive_del $id'.
>>
>> IMHO much better would be to go qdev instead though.  We should have
>> generic device_add + device_del monitor commands which work for any
>> device, pretty much like the -device command line switch.
>
> That makes sense, but I'd nevertheless prefer to stick with the
> more traditional approach right now, replacing the
> bus/unit parsing with an ID-based variant.

Have a look at the "qdev: bus management updates." patch series posted a 
few days ago.  It adds device_add+device_del.

> However, is there any
> standard way to get from an instance of DriveInfo to
> the corresponding instance of SCSIDevice respectively
> SCSIDeviceInfo?

No.  It is linked the other way around: The device has a reference to 
the DriveInfo.  Which is one of the reasons why I think drive_del isn't 
that a great idea.

cheers,
   Gerd
Wolfgang Mauerer Oct. 1, 2009, 7:54 a.m. UTC | #4
Gerd Hoffmann wrote:
> On 09/30/09 17:45, Wolfgang Mauerer wrote:
>> Gerd Hoffmann wrote:
>>>     Hi,
>>>
>>>> +     dinfo = drive_get(type, bus, unit);
>>>> +     if (!dinfo) {
>>>> +         monitor_printf(mon, "Trying to remove non-existent device\n");
>>>> +	 return;
>>>> +     }
>>> No.  Just don't do this silly if/bus/unit parsing.  At very minimum use
>>> drive_get_by_id() here, then have something like 'drive_del $id'.
>>>
>>> IMHO much better would be to go qdev instead though.  We should have
>>> generic device_add + device_del monitor commands which work for any
>>> device, pretty much like the -device command line switch.
>> That makes sense, but I'd nevertheless prefer to stick with the
>> more traditional approach right now, replacing the
>> bus/unit parsing with an ID-based variant.
> 
> Have a look at the "qdev: bus management updates." patch series posted a 
> few days ago.  It adds device_add+device_del.

Thanks for the pointer. The reason why I'd (still :-)) like
to stick to the non-qdev variant is because I would want
the patch to be applicable to older qemu releases for various
reasons, and backporting all the required qdev  changes does
not seem to be a reasonable option (but please tell me if you
think this would make sense)

>> However, is there any
>> standard way to get from an instance of DriveInfo to
>> the corresponding instance of SCSIDevice respectively
>> SCSIDeviceInfo?
> 
> No.  It is linked the other way around: The device has a reference to 
> the DriveInfo.  Which is one of the reasons why I think drive_del isn't 
> that a great idea.

Cheers, Wolfgang
Gerd Hoffmann Oct. 1, 2009, 8:50 a.m. UTC | #5
On 10/01/09 09:54, Wolfgang Mauerer wrote:
> Thanks for the pointer. The reason why I'd (still :-)) like
> to stick to the non-qdev variant is because I would want
> the patch to be applicable to older qemu releases for various
> reasons, and backporting all the required qdev  changes does
> not seem to be a reasonable option (but please tell me if you
> think this would make sense)

Yes, backporting all qdev isn't going to fly.

Note that support for looking up drives by name is available in 0.11+ 
only too, so you might have to stick with the lookup by pci address, 
depending on which versions you plan to backport it ...

cheers,
   Gerd
diff mbox

Patch

diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c
index b8ea9ae..4455f17 100644
--- a/hw/pci-hotplug.c
+++ b/hw/pci-hotplug.c
@@ -50,6 +50,98 @@  static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
     return pci_nic_init(&nd_table[ret], "rtl8139", devaddr);
 }
 
+void drive_hot_del(Monitor *mon, const QDict *qdict)
+{
+    int dom, pci_bus;
+    unsigned slot;
+    unsigned unit, bus; 
+    int type;
+    int success = 0;
+    PCIDevice *dev;
+    DriveInfo *dinfo;
+    BlockDriverState *bs;
+    char buf[128];
+    const char *strbuf;
+    QemuOpts *opts;
+
+    static const char * const params[] = { "bus", "unit", "if", NULL };
+    const char *pci_addr = qdict_get_str(qdict, "pci_addr");
+    const char *optstring = qdict_get_try_str(qdict, "opts");
+
+     /* strip legacy tag */
+    if (!strncmp(pci_addr, "pci_addr=", 9)) {
+        pci_addr += 9;
+    }
+
+    if (check_params(buf, sizeof(buf), params, optstring) < 0) {
+        monitor_printf(mon, "qemu: unknown parameter '%s' in '%s'\n",
+                         buf, optstring);
+	return;
+    }
+    opts = drive_add(NULL, "%s", optstring); // Just parses optstring
+
+    if (pci_read_devaddr(mon, pci_addr, &dom, &pci_bus, &slot)) {
+        monitor_printf(mon, "Invalid pci address\n");
+        return;
+    }
+
+    dev = pci_find_device(pci_bus, slot, 0);
+    if (!dev) {
+        monitor_printf(mon, "No pci device with address %s\n", pci_addr);
+        return;
+    }
+
+    bus = qemu_opt_get_number(opts, "bus", -1);
+    if (bus == -1) {
+        monitor_printf(mon, "Need to specify bus\n");
+        return;
+    }
+
+    unit = qemu_opt_get_number(opts, "unit", -1);
+    if (unit == -1) {
+        monitor_printf(mon, "Need to specify unit\n");
+        return;
+    }
+
+    if ((strbuf = qemu_opt_get(opts, "if")) != NULL) {
+        type = qemu_opt_get_if(strbuf);
+
+	if (type == IF_COUNT) {
+	    monitor_printf(mon, "Trying to remove device on invalid bus\n");
+	    return;
+	}
+     } else {
+         /* Assume SCSI for hot-remove per default */
+         type = IF_SCSI;
+     }
+
+     dinfo = drive_get(type, bus, unit);
+     if (!dinfo) {
+         monitor_printf(mon, "Trying to remove non-existent device\n");
+	 return;
+     }
+
+    switch (type) {
+    case IF_SCSI:
+        success = 1;
+        lsi_scsi_detach(&dev->qdev, dinfo->bdrv, dinfo->unit);
+
+        bs = dinfo->bdrv;
+        drive_uninit(bs);
+        bdrv_delete(bs);
+        break;
+    default:
+        monitor_printf(mon, "Hot-remove unsupported for interface type %d\n", 
+		       type);
+    }
+
+    if (success) 
+        monitor_printf(mon, "OK bus %d, unit %d\n", bus, unit);
+
+    return;
+}
+
+
 void drive_hot_add(Monitor *mon, const QDict *qdict)
 {
     int dom, pci_bus;
diff --git a/qemu-monitor.hx b/qemu-monitor.hx
index a889fed..aee5ff9 100644
--- a/qemu-monitor.hx
+++ b/qemu-monitor.hx
@@ -510,7 +510,19 @@  Add drive to PCI storage controller.
 ETEXI
 
 #if defined(TARGET_I386)
-    { "pci_add", "pci_addr:s,type:s,opts:s?", pci_device_hot_add, "auto|[[<domain>:]<bus>:]<slot> nic|storage|host [[vlan=n][,macaddr=addr][,model=type]] [file=file][,if=type][,bus=nr]... [host=02:00.0[,name=string][,dma=none]", "hot-add PCI device" },
+    { "drive_del", "ss", drive_hot_del, "[[<domain>:]<bus>:]<slot>\n"
+                                         "bus=n,unit=m[,if=type]\n",
+                                         "Delete drive from PCI storage controller" },
+#endif
+STEXI
+@item drive_del
+Delete drive from PCI storage controller. The device must be identified
+by the bus and unit parameters. Currently, only the LSI SCSI driver
+supports drive removal.
+ETEXI
+
+#if defined(TARGET_I386)
+    { "pci_add", "sss?", pci_device_hot_add, "auto|[[<domain>:]<bus>:]<slot> nic|storage|host [[vlan=n][,macaddr=addr][,model=type]] [file=file][,if=type][,bus=nr]... [host=02:00.0[,name=string][,dma=none]", "hot-add PCI device" },
 #endif
 STEXI
 @item pci_add
diff --git a/sysemu.h b/sysemu.h
index 4fabb2a..0c08b48 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -218,6 +218,7 @@  void destroy_bdrvs(dev_match_fn *match_fn, void *arg);
 /* pci-hotplug */
 void pci_device_hot_add(Monitor *mon, const QDict *qdict);
 void drive_hot_add(Monitor *mon, const QDict *qdict);
+void drive_hot_del(Monitor *mon, const QDict *qdict);
 void pci_device_hot_remove(Monitor *mon, const char *pci_addr);
 void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict);
 void pci_device_hot_remove_success(int pcibus, int slot);