qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Maxim Levitsky <mlevitsk@redhat.com>
To: Klaus Jensen <its@irrelevant.dk>, qemu-block@nongnu.org
Cc: Kevin Wolf <kwolf@redhat.com>,
	Beata Michalska <beata.michalska@linaro.org>,
	qemu-devel@nongnu.org, Max Reitz <mreitz@redhat.com>,
	Keith Busch <kbusch@kernel.org>,
	Javier Gonzalez <javier.gonz@samsung.com>
Subject: Re: [PATCH v6 12/42] nvme: add support for the get log page command
Date: Wed, 25 Mar 2020 12:40:53 +0200	[thread overview]
Message-ID: <a7c92a47957a8185a9bd8d7d8b919072d757ff3a.camel@redhat.com> (raw)
In-Reply-To: <20200316142928.153431-13-its@irrelevant.dk>

On Mon, 2020-03-16 at 07:28 -0700, Klaus Jensen wrote:
> From: Klaus Jensen <k.jensen@samsung.com>
> 
> Add support for the Get Log Page command and basic implementations of
> the mandatory Error Information, SMART / Health Information and Firmware
> Slot Information log pages.
> 
> In violation of the specification, the SMART / Health Information log
> page does not persist information over the lifetime of the controller
> because the device has no place to store such persistent state.
> 
> Note that the LPA field in the Identify Controller data structure
> intentionally has bit 0 cleared because there is no namespace specific
> information in the SMART / Health information log page.
> 
> Required for compliance with NVMe revision 1.2.1. See NVM Express 1.2.1,
> Section 5.10 ("Get Log Page command").
> 
> Signed-off-by: Klaus Jensen <klaus.jensen@cnexlabs.com>
> Acked-by: Keith Busch <kbusch@kernel.org>
> ---
>  hw/block/nvme.c       | 138 +++++++++++++++++++++++++++++++++++++++++-
>  hw/block/nvme.h       |  10 +++
>  hw/block/trace-events |   2 +
>  3 files changed, 149 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index 64c42101df5c..83ff3fbfb463 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -569,6 +569,138 @@ static uint16_t nvme_create_sq(NvmeCtrl *n, NvmeCmd *cmd)
>      return NVME_SUCCESS;
>  }
>  
> +static uint16_t nvme_smart_info(NvmeCtrl *n, NvmeCmd *cmd, uint32_t buf_len,
> +                                uint64_t off, NvmeRequest *req)
> +{
> +    uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
> +    uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
> +    uint32_t nsid = le32_to_cpu(cmd->nsid);
> +
> +    uint32_t trans_len;
> +    time_t current_ms;
> +    uint64_t units_read = 0, units_written = 0;
> +    uint64_t read_commands = 0, write_commands = 0;
> +    NvmeSmartLog smart;
> +    BlockAcctStats *s;
> +
> +    if (nsid && nsid != 0xffffffff) {
> +        return NVME_INVALID_FIELD | NVME_DNR;
> +    }
> +
> +    s = blk_get_stats(n->conf.blk);
> +
> +    units_read = s->nr_bytes[BLOCK_ACCT_READ] >> BDRV_SECTOR_BITS;
> +    units_written = s->nr_bytes[BLOCK_ACCT_WRITE] >> BDRV_SECTOR_BITS;
> +    read_commands = s->nr_ops[BLOCK_ACCT_READ];
> +    write_commands = s->nr_ops[BLOCK_ACCT_WRITE];
> +
> +    if (off > sizeof(smart)) {
> +        return NVME_INVALID_FIELD | NVME_DNR;
> +    }
> +
> +    trans_len = MIN(sizeof(smart) - off, buf_len);
> +
> +    memset(&smart, 0x0, sizeof(smart));
> +
> +    smart.data_units_read[0] = cpu_to_le64(units_read / 1000);
> +    smart.data_units_written[0] = cpu_to_le64(units_written / 1000);
> +    smart.host_read_commands[0] = cpu_to_le64(read_commands);
> +    smart.host_write_commands[0] = cpu_to_le64(write_commands);
> +
> +    smart.temperature[0] = n->temperature & 0xff;
> +    smart.temperature[1] = (n->temperature >> 8) & 0xff;
> +
> +    if ((n->temperature > n->features.temp_thresh_hi) ||
> +        (n->temperature < n->features.temp_thresh_low)) {
> +        smart.critical_warning |= NVME_SMART_TEMPERATURE;
> +    }
> +
> +    current_ms = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
> +    smart.power_on_hours[0] =
> +        cpu_to_le64((((current_ms - n->starttime_ms) / 1000) / 60) / 60);
OH, I didn't notice that you didn't have the endian conversion in V5, it is needed here
of course.

> +
> +    return nvme_dma_read_prp(n, (uint8_t *) &smart + off, trans_len, prp1,
> +                             prp2);
> +}
> +
> +static uint16_t nvme_fw_log_info(NvmeCtrl *n, NvmeCmd *cmd, uint32_t buf_len,
> +                                 uint64_t off, NvmeRequest *req)
> +{
> +    uint32_t trans_len;
> +    uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
> +    uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
> +    NvmeFwSlotInfoLog fw_log;
> +
> +    if (off > sizeof(fw_log)) {
> +        return NVME_INVALID_FIELD | NVME_DNR;
> +    }
> +
> +    memset(&fw_log, 0, sizeof(NvmeFwSlotInfoLog));
> +
> +    trans_len = MIN(sizeof(fw_log) - off, buf_len);
> +
> +    return nvme_dma_read_prp(n, (uint8_t *) &fw_log + off, trans_len, prp1,
> +                             prp2);
> +}
> +
> +static uint16_t nvme_error_info(NvmeCtrl *n, NvmeCmd *cmd, uint32_t buf_len,
> +                                uint64_t off, NvmeRequest *req)
> +{
> +    uint32_t trans_len;
> +    uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
> +    uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
> +    uint8_t errlog[64];
I'll would replace this with sizeof(NvmeErrorLogEntry)
(and add NvmeErrorLogEntry to the nvme.h), just for the sake of consistency,
and in case we end up reporting some errors to the log in the future.


> +
> +    if (off > sizeof(errlog)) {
> +        return NVME_INVALID_FIELD | NVME_DNR;
> +    }
> +
> +    memset(errlog, 0x0, sizeof(errlog));
> +
> +    trans_len = MIN(sizeof(errlog) - off, buf_len);
> +
> +    return nvme_dma_read_prp(n, errlog, trans_len, prp1, prp2);
> +}
Besides this, looks good now.

> +
> +static uint16_t nvme_get_log(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> +{
> +    uint32_t dw10 = le32_to_cpu(cmd->cdw10);
> +    uint32_t dw11 = le32_to_cpu(cmd->cdw11);
> +    uint32_t dw12 = le32_to_cpu(cmd->cdw12);
> +    uint32_t dw13 = le32_to_cpu(cmd->cdw13);
> +    uint8_t  lid = dw10 & 0xff;
> +    uint8_t  rae = (dw10 >> 15) & 0x1;
> +    uint32_t numdl, numdu;
> +    uint64_t off, lpol, lpou;
> +    size_t   len;
> +
> +    numdl = (dw10 >> 16);
> +    numdu = (dw11 & 0xffff);
> +    lpol = dw12;
> +    lpou = dw13;
> +
> +    len = (((numdu << 16) | numdl) + 1) << 2;
> +    off = (lpou << 32ULL) | lpol;
> +
> +    if (off & 0x3) {
> +        return NVME_INVALID_FIELD | NVME_DNR;
> +    }
> +
> +    trace_nvme_dev_get_log(nvme_cid(req), lid, rae, len, off);
> +
> +    switch (lid) {
> +    case NVME_LOG_ERROR_INFO:
> +        return nvme_error_info(n, cmd, len, off, req);
> +    case NVME_LOG_SMART_INFO:
> +        return nvme_smart_info(n, cmd, len, off, req);
> +    case NVME_LOG_FW_SLOT_INFO:
> +        return nvme_fw_log_info(n, cmd, len, off, req);
> +    default:
> +        trace_nvme_dev_err_invalid_log_page(nvme_cid(req), lid);
> +        return NVME_INVALID_FIELD | NVME_DNR;
> +    }
> +}
> +
>  static void nvme_free_cq(NvmeCQueue *cq, NvmeCtrl *n)
>  {
>      n->cq[cq->cqid] = NULL;
> @@ -914,6 +1046,8 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
>          return nvme_del_sq(n, cmd);
>      case NVME_ADM_CMD_CREATE_SQ:
>          return nvme_create_sq(n, cmd);
> +    case NVME_ADM_CMD_GET_LOG_PAGE:
> +        return nvme_get_log(n, cmd, req);
>      case NVME_ADM_CMD_DELETE_CQ:
>          return nvme_del_cq(n, cmd);
>      case NVME_ADM_CMD_CREATE_CQ:
> @@ -1416,7 +1550,9 @@ static void nvme_init_state(NvmeCtrl *n)
>      n->namespaces = g_new0(NvmeNamespace, n->num_namespaces);
>      n->sq = g_new0(NvmeSQueue *, n->params.max_ioqpairs + 1);
>      n->cq = g_new0(NvmeCQueue *, n->params.max_ioqpairs + 1);
> +    n->temperature = NVME_TEMPERATURE;
>      n->features.temp_thresh_hi = NVME_TEMPERATURE_WARNING;
> +    n->starttime_ms = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
>  }
>  
>  static void nvme_init_cmb(NvmeCtrl *n, PCIDevice *pci_dev)
> @@ -1493,7 +1629,7 @@ static void nvme_init_ctrl(NvmeCtrl *n)
>       */
>      id->acl = 3;
>      id->frmw = 7 << 1;
> -    id->lpa = 1 << 0;
> +    id->lpa = 1 << 2;
>  
>      /* recommended default value (~70 C) */
>      id->wctemp = cpu_to_le16(NVME_TEMPERATURE_WARNING);
> diff --git a/hw/block/nvme.h b/hw/block/nvme.h
> index 8cda5f02c622..ebeee2edc4f4 100644
> --- a/hw/block/nvme.h
> +++ b/hw/block/nvme.h
> @@ -109,6 +109,7 @@ typedef struct NvmeCtrl {
>      uint64_t    host_timestamp;                 /* Timestamp sent by the host */
>      uint64_t    timestamp_set_qemu_clock_ms;    /* QEMU clock time */
>      uint16_t    temperature;
> +    uint64_t    starttime_ms;
>  
>      NvmeNamespace   *namespaces;
>      NvmeSQueue      **sq;
> @@ -124,4 +125,13 @@ static inline uint64_t nvme_ns_nlbas(NvmeCtrl *n, NvmeNamespace *ns)
>      return n->ns_size >> nvme_ns_lbads(ns);
>  }
>  
> +static inline uint16_t nvme_cid(NvmeRequest *req)
> +{
> +    if (req) {
> +        return le16_to_cpu(req->cqe.cid);
> +    }
> +
> +    return 0xffff;
> +}
> +
>  #endif /* HW_NVME_H */
> diff --git a/hw/block/trace-events b/hw/block/trace-events
> index ade506ea2bb2..7da088479f39 100644
> --- a/hw/block/trace-events
> +++ b/hw/block/trace-events
> @@ -46,6 +46,7 @@ nvme_dev_getfeat_numq(int result) "get feature number of queues, result=%d"
>  nvme_dev_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
>  nvme_dev_setfeat_timestamp(uint64_t ts) "set feature timestamp = 0x%"PRIx64""
>  nvme_dev_getfeat_timestamp(uint64_t ts) "get feature timestamp = 0x%"PRIx64""
> +nvme_dev_get_log(uint16_t cid, uint8_t lid, uint8_t rae, uint32_t len, uint64_t off) "cid %"PRIu16" lid 0x%"PRIx8" rae 0x%"PRIx8" len %"PRIu32" off %"PRIu64""
>  nvme_dev_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64""
>  nvme_dev_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64""
>  nvme_dev_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64""
> @@ -85,6 +86,7 @@ nvme_dev_err_invalid_create_cq_qflags(uint16_t qflags) "failed creating completi
>  nvme_dev_err_invalid_identify_cns(uint16_t cns) "identify, invalid cns=0x%"PRIx16""
>  nvme_dev_err_invalid_getfeat(int dw10) "invalid get features, dw10=0x%"PRIx32""
>  nvme_dev_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx32""
> +nvme_dev_err_invalid_log_page(uint16_t cid, uint16_t lid) "cid %"PRIu16" lid 0x%"PRIx16""
>  nvme_dev_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues"
>  nvme_dev_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues"
>  nvme_dev_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null"


Best regards,
	Maxim Levitsky





  reply	other threads:[~2020-03-25 10:42 UTC|newest]

Thread overview: 121+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-16 14:28 [PATCH v6 00/42] nvme: support NVMe v1.3d, SGLs and multiple namespaces Klaus Jensen
2020-03-16 14:28 ` [PATCH v6 01/42] nvme: rename trace events to nvme_dev Klaus Jensen
2020-03-25 10:36   ` Maxim Levitsky
2020-03-31  5:38     ` Klaus Birkelund Jensen
2020-03-16 14:28 ` [PATCH v6 02/42] nvme: remove superfluous breaks Klaus Jensen
2020-03-16 14:28 ` [PATCH v6 03/42] nvme: move device parameters to separate struct Klaus Jensen
2020-03-25 10:36   ` Maxim Levitsky
2020-03-16 14:28 ` [PATCH v6 04/42] nvme: bump spec data structures to v1.3 Klaus Jensen
2020-03-25 10:37   ` Maxim Levitsky
2020-03-31  5:38     ` Klaus Birkelund Jensen
2020-03-31 10:43       ` Maxim Levitsky
2020-03-16 14:28 ` [PATCH v6 05/42] nvme: use constant for identify data size Klaus Jensen
2020-03-25 10:37   ` Maxim Levitsky
2020-03-31  5:38     ` Klaus Birkelund Jensen
2020-03-16 14:28 ` [PATCH v6 06/42] nvme: add identify cns values in header Klaus Jensen
2020-03-25 10:37   ` Maxim Levitsky
2020-03-31  5:39     ` Klaus Birkelund Jensen
2020-03-16 14:28 ` [PATCH v6 07/42] nvme: refactor nvme_addr_read Klaus Jensen
2020-03-25 10:38   ` Maxim Levitsky
2020-03-31  5:39     ` Klaus Birkelund Jensen
2020-03-31 10:41       ` Maxim Levitsky
2020-03-31 12:48         ` Klaus Birkelund Jensen
2020-03-31 14:46           ` Maxim Levitsky
2020-03-16 14:28 ` [PATCH v6 08/42] nvme: add support for the abort command Klaus Jensen
2020-03-25 10:38   ` Maxim Levitsky
2020-03-16 14:28 ` [PATCH v6 09/42] nvme: add max_ioqpairs device parameter Klaus Jensen
2020-03-25 10:39   ` Maxim Levitsky
2020-03-31  5:40     ` Klaus Birkelund Jensen
2020-03-31  9:48       ` Maxim Levitsky
2020-03-16 14:28 ` [PATCH v6 10/42] nvme: refactor device realization Klaus Jensen
2020-03-25 10:40   ` Maxim Levitsky
2020-03-31  5:40     ` Klaus Birkelund Jensen
2020-03-16 14:28 ` [PATCH v6 11/42] nvme: add temperature threshold feature Klaus Jensen
2020-03-25 10:40   ` Maxim Levitsky
2020-03-31  5:40     ` Klaus Birkelund Jensen
2020-03-31  9:46       ` Maxim Levitsky
2020-03-16 14:28 ` [PATCH v6 12/42] nvme: add support for the get log page command Klaus Jensen
2020-03-25 10:40   ` Maxim Levitsky [this message]
2020-03-31  5:41     ` Klaus Birkelund Jensen
2020-03-31  9:45       ` Maxim Levitsky
2020-03-31 12:49         ` Klaus Birkelund Jensen
2020-03-31 14:47           ` Maxim Levitsky
2020-03-16 14:28 ` [PATCH v6 13/42] nvme: add support for the asynchronous event request command Klaus Jensen
2020-03-25 10:41   ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 14/42] nvme: add missing mandatory features Klaus Jensen
2020-03-25 10:41   ` Maxim Levitsky
2020-03-31  5:41     ` Klaus Birkelund Jensen
2020-03-31  9:39       ` Maxim Levitsky
2020-04-08 11:28         ` Klaus Birkelund Jensen
2020-03-16 14:29 ` [PATCH v6 15/42] nvme: additional tracing Klaus Jensen
2020-03-25 10:42   ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 16/42] nvme: make sure ncqr and nsqr is valid Klaus Jensen
2020-03-25 10:42   ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 17/42] nvme: add log specific field to trace events Klaus Jensen
2020-03-25 10:43   ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 18/42] nvme: support identify namespace descriptor list Klaus Jensen
2020-03-25 10:43   ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 19/42] nvme: enforce valid queue creation sequence Klaus Jensen
2020-03-25 10:43   ` Maxim Levitsky
2020-03-31  5:41     ` Klaus Birkelund Jensen
2020-03-31  9:31       ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 20/42] nvme: provide the mandatory subnqn field Klaus Jensen
2020-03-25 10:43   ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 21/42] nvme: bump supported version to v1.3 Klaus Jensen
2020-03-25 10:44   ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 22/42] nvme: memset preallocated requests structures Klaus Jensen
2020-03-25 10:44   ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 23/42] nvme: add mapping helpers Klaus Jensen
2020-03-25 10:45   ` Maxim Levitsky
2020-03-31  5:44     ` Klaus Birkelund Jensen
2020-03-31  9:30       ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 24/42] nvme: remove redundant has_sg member Klaus Jensen
2020-03-25 10:45   ` Maxim Levitsky
2020-03-31  5:44     ` Klaus Birkelund Jensen
2020-03-31  9:25       ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 25/42] nvme: refactor dma read/write Klaus Jensen
2020-03-25 10:46   ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 26/42] nvme: pass request along for tracing Klaus Jensen
2020-03-25 10:55   ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 27/42] nvme: add request mapping helper Klaus Jensen
2020-03-25 10:56   ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 28/42] nvme: verify validity of prp lists in the cmb Klaus Jensen
2020-03-25 10:56   ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 29/42] nvme: refactor request bounds checking Klaus Jensen
2020-03-25 10:56   ` Maxim Levitsky
2020-03-31  5:44     ` Klaus Birkelund Jensen
2020-03-31  9:23       ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 30/42] nvme: add check for mdts Klaus Jensen
2020-03-25 10:57   ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 31/42] nvme: add check for prinfo Klaus Jensen
2020-03-25 10:57   ` Maxim Levitsky
2020-03-31  5:45     ` Klaus Birkelund Jensen
2020-03-31  9:17       ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 32/42] nvme: allow multiple aios per command Klaus Jensen
2020-03-25 10:57   ` Maxim Levitsky
2020-03-31  5:47     ` Klaus Birkelund Jensen
2020-03-31  9:10       ` Maxim Levitsky
2020-04-08 15:02         ` Klaus Birkelund Jensen
2020-03-16 14:29 ` [PATCH v6 33/42] nvme: use preallocated qsg/iov in nvme_dma_prp Klaus Jensen
2020-03-25 10:58   ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 34/42] pci: pass along the return value of dma_memory_rw Klaus Jensen
2020-03-16 14:29 ` [PATCH v6 35/42] nvme: handle dma errors Klaus Jensen
2020-03-25 10:58   ` Maxim Levitsky
2020-03-31  5:47     ` Klaus Birkelund Jensen
2020-03-16 14:29 ` [PATCH v6 36/42] nvme: add support for scatter gather lists Klaus Jensen
2020-03-25 10:58   ` Maxim Levitsky
2020-03-31  5:48     ` Klaus Birkelund Jensen
2020-03-31  8:51       ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 37/42] nvme: refactor identify active namespace id list Klaus Jensen
2020-03-25 10:58   ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 38/42] nvme: support multiple namespaces Klaus Jensen
2020-03-25 10:59   ` Maxim Levitsky
2020-03-31  5:48     ` Klaus Birkelund Jensen
2020-03-31  8:47       ` Maxim Levitsky
2020-03-16 14:29 ` [PATCH v6 39/42] pci: allocate pci id for nvme Klaus Jensen
2020-03-16 14:29 ` [PATCH v6 40/42] nvme: change controller pci id Klaus Jensen
2020-03-16 14:29 ` [PATCH v6 41/42] nvme: remove redundant NvmeCmd pointer parameter Klaus Jensen
2020-03-16 14:29 ` [PATCH v6 42/42] nvme: make lba data size configurable Klaus Jensen
2020-03-25 10:59   ` Maxim Levitsky
2020-03-16 19:30 ` [PATCH v6 00/42] nvme: support NVMe v1.3d, SGLs and multiple namespaces no-reply
2020-03-25 10:35 ` Maxim Levitsky

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=a7c92a47957a8185a9bd8d7d8b919072d757ff3a.camel@redhat.com \
    --to=mlevitsk@redhat.com \
    --cc=beata.michalska@linaro.org \
    --cc=its@irrelevant.dk \
    --cc=javier.gonz@samsung.com \
    --cc=kbusch@kernel.org \
    --cc=kwolf@redhat.com \
    --cc=mreitz@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).