  switch (recv_into_rbuf (h)) {
  case -1: SET_NEXT_STATE (%.DEAD); return 0;
  case 1:
    save_reply_state (h);
    SET_NEXT_STATE (%.READY);
    return 0;
  case 0:
    error = be32toh (h->sbuf.sr.payload.error.error.error);
    type = be16toh (h->sbuf.sr.structured_reply.type);

    assert (cmd); /* guaranteed by CHECK */
    error = nbd_internal_errno_of_nbd_error (error);

    /* The spec requires the server to send a non-zero error */
    if (error == NBD_SUCCESS) {
      debug (h, "server forgot to set error; using EINVAL");
      error = NBD_EINVAL;
    }
    error = nbd_internal_errno_of_nbd_error (error);

    /* Sanity check that any error offset is in range, then invoke
     * user callback if present.
     */
    if (type == NBD_REPLY_TYPE_ERROR_OFFSET) {
      offset = be64toh (h->sbuf.sr.payload.error.offset);
      if (! structured_reply_in_bounds (offset, 0, cmd)) {
        SET_NEXT_STATE (%.DEAD);
        return 0;
      }
      if (cmd->type == NBD_CMD_READ &&
          CALLBACK_IS_NOT_NULL (cmd->cb.fn.chunk)) {
        int scratch = error;

        /* Different from successful reads: inform the callback about the
         * current error rather than any earlier one. If the callback fails
         * without setting errno, then use the server's error below.
         */
        if (CALL_CALLBACK (cmd->cb.fn.chunk,
                           cmd->data + (offset - cmd->offset),
                           0, offset, LIBNBD_READ_ERROR,
                           &scratch) == -1)
          if (cmd->error == 0)
            cmd->error = scratch;
      }
    }

    /* Preserve first error encountered */
    if (cmd->error == 0)
      cmd->error = error;

    SET_NEXT_STATE(%FINISH);
  }
  switch (recv_into_rbuf (h)) {
  case -1: SET_NEXT_STATE (%.DEAD); return 0;
  case 1:
    save_reply_state (h);
    SET_NEXT_STATE (%.READY);
    return 0;
  case 0:
    error = be32toh (h->sbuf.sr.payload.error.error.error);
    type = be16toh (h->sbuf.sr.structured_reply.type);

    assert (cmd);  
    error = nbd_internal_errno_of_nbd_error (error);

     
    if (error == NBD_SUCCESS) {
      debug (h, "server forgot to set error; using EINVAL");
      error = NBD_EINVAL;
    }
    error = nbd_internal_errno_of_nbd_error (error);

     
    if (type == NBD_REPLY_TYPE_ERROR_OFFSET) {
      offset = be64toh (h->sbuf.sr.payload.error.offset);
      if (! structured_reply_in_bounds (offset, 0, cmd)) {
        SET_NEXT_STATE (%.DEAD);
        return 0;
      }
      if (cmd->type == NBD_CMD_READ &&
          CALLBACK_IS_NOT_NULL (cmd->cb.fn.chunk)) {
        int scratch = error;

         
        if (CALL_CALLBACK (cmd->cb.fn.chunk,
                           cmd->data + (offset - cmd->offset),
                           0, offset, LIBNBD_READ_ERROR,
                           &scratch) == -1)
          if (cmd->error == 0)
            cmd->error = scratch;
      }
    }

     
    if (cmd->error == 0)
      cmd->error = error;

    SET_NEXT_STATE(%FINISH);
  }