From nobody Mon Feb 9 16:54:14 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1768341279; cv=none; d=zohomail.com; s=zohoarc; b=KHZDDAPffTE9zY5vWI5a6w4oHDusO3XfSCWNv+DOgniCDJ4dwrFtICgZ5M3+wnj8g7vxmMkcp8wPm8som3bYjzN8LTdnl/LFy3ybB0Kim5/aXMPCSAoU7zgBfrmp/2DVk+IBI4dTuuX5bVLpeEQ2QoaYjMuJBdx34i03XA3lu9g= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1768341279; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=xeHxLA0jffmt289A95p5Qi8M2tCa4K4MGEGLVcOdVWw=; b=Az78qhVSrlvlKSn3+hs+eh/MH9AAJEB3bLDZ6H+kRl1v5zjppKAyBXkfo3ZJIfWunb/0ZGppDtCF+/laqCB2m8ToYU38X1U2XaJ9GD28jjl9QsUYYZ94pHXBfFKljCvIFt6Six3TNFY4Nj6TxFG2GdHyxfWKJkxWnDFBpbpYfOg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1768341279383983.1055566756377; Tue, 13 Jan 2026 13:54:39 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vfmKX-0004XK-Ry; Tue, 13 Jan 2026 16:53:37 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vfmKW-0004Wg-O5 for qemu-devel@nongnu.org; Tue, 13 Jan 2026 16:53:36 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vfmKT-0001t8-Qs for qemu-devel@nongnu.org; Tue, 13 Jan 2026 16:53:36 -0500 Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-155-OUp_yQVANQud8IjIbnUKUA-1; Tue, 13 Jan 2026 16:53:26 -0500 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 1B3011800370; Tue, 13 Jan 2026 21:53:25 +0000 (UTC) Received: from localhost (unknown [10.2.16.89]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id F3D6630002D8; Tue, 13 Jan 2026 21:53:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1768341213; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=xeHxLA0jffmt289A95p5Qi8M2tCa4K4MGEGLVcOdVWw=; b=cOzl1p+4qp/Yq25xHwv26oQgYSxG/oEUHX/Q0JIcV17Xq2YavdqEO4Wc7gGQPgkoUsw1Lf lBBLDvz6g/PIfa6f0BwQzk1Dkf0QxxynJpsC1yVnZEo1SXLg70PZMwKpbH/ynadY54sxGM WXWeMcMb1eY86mjEWYCDuu8UHitcX1Y= X-MC-Unique: OUp_yQVANQud8IjIbnUKUA-1 X-Mimecast-MFC-AGG-ID: OUp_yQVANQud8IjIbnUKUA_1768341205 From: Stefan Hajnoczi To: qemu-devel@nongnu.org Cc: Fam Zheng , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , pkrempa@redhat.com, Hannes Reinecke , Yanan Wang , Kevin Wolf , Eduardo Habkost , Alberto Faria , Paolo Bonzini , Marcel Apfelbaum , qemu-block@nongnu.org, Zhao Liu , Stefan Hajnoczi Subject: [RFC 1/4] scsi: track SCSI reservation state for live migration Date: Tue, 13 Jan 2026 16:53:16 -0500 Message-ID: <20260113215320.566595-2-stefanha@redhat.com> In-Reply-To: <20260113215320.566595-1-stefanha@redhat.com> References: <20260113215320.566595-1-stefanha@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=stefanha@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1768341281421158500 Content-Type: text/plain; charset="utf-8" SCSI Persistent Reservations are stateful and external to the guest. In order to transparently move reservations to the destination host during live migration, it is necessary to track the state built up on the source host before migration. Only then can the destination host ensure an equivalent state is restored upon migration. Snoop on successful PERSISTENT RESERVE OUT commands and save the reservation key and reservation type. This will allow registered keys and reservations to be migrated. Also patch PERSISTENT RESERVE IN replies with the REPORT CAPABILITIES service action since features that involve the physical SCSI bus target ports must not be exposed to the guest (it sees a virtual SCSI bus). Usually this plays out as follows: 1. The guest invokes the REGISTER service action to register a reservation key on its I_T nexus. 2. The guest invokes the RESERVE service action to create a reservation using the previously-registered key. This commit implements the snooping and stores the reservation key and type (if any) for each LUN. The snooped PR state and the migrate_pr flag to enable PR migration will be used in later commits. Signed-off-by: Stefan Hajnoczi --- include/hw/scsi/scsi.h | 10 +++ include/scsi/constants.h | 21 +++++ hw/scsi/scsi-bus.c | 3 + hw/scsi/scsi-generic.c | 160 +++++++++++++++++++++++++++++++++++++++ hw/scsi/trace-events | 1 + 5 files changed, 195 insertions(+) diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index d26f1127bb..23bd5b4b5e 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -57,6 +57,13 @@ struct SCSIRequest { QTAILQ_ENTRY(SCSIRequest) next; }; =20 +/* Per-SCSIDevice Persistent Reservation state */ +typedef struct { + QemuMutex mutex; /* protects all fields (e.g. from multiple IOThread= s) */ + uint64_t key; /* 0 if no registered key */ + uint8_t resv_type; /* 0 if no reservation */ +} SCSIPRState; + #define TYPE_SCSI_DEVICE "scsi-device" OBJECT_DECLARE_TYPE(SCSIDevice, SCSIDeviceClass, SCSI_DEVICE) =20 @@ -97,6 +104,9 @@ struct SCSIDevice uint32_t io_timeout; bool needs_vpd_bl_emulation; bool hba_supports_iothread; + + bool migrate_pr; + SCSIPRState pr_state; }; =20 extern const VMStateDescription vmstate_scsi_device; diff --git a/include/scsi/constants.h b/include/scsi/constants.h index 9b98451912..cb97bdb636 100644 --- a/include/scsi/constants.h +++ b/include/scsi/constants.h @@ -319,4 +319,25 @@ #define IDENT_DESCR_TGT_DESCR_SIZE 32 #define XCOPY_BLK2BLK_SEG_DESC_SIZE 28 =20 +/* + * PERSISTENT RESERVATION IN service action codes + */ +#define PRI_READ_KEYS 0x00 +#define PRI_READ_RESERVATION 0x01 +#define PRI_REPORT_CAPABILITIES 0x02 +#define PRI_READ_FULL_STATUS 0x03 + +/* + * PERSISTENT RESERVATION OUT service action codes + */ +#define PRO_REGISTER 0x00 +#define PRO_RESERVE 0x01 +#define PRO_RELEASE 0x02 +#define PRO_CLEAR 0x03 +#define PRO_PREEMPT 0x04 +#define PRO_PREEMPT_AND_ABORT 0x05 +#define PRO_REGISTER_AND_IGNORE_EXISTING_KEY 0x06 +#define PRO_REGISTER_AND_MOVE 0x07 +#define PRO_REPLACE_LOST_RESERVATION 0x08 + #endif diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index f310ddafb9..9b8656dd83 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -393,6 +393,7 @@ static void scsi_qdev_realize(DeviceState *qdev, Error = **errp) } =20 qemu_mutex_init(&dev->requests_lock); + qemu_mutex_init(&dev->pr_state.mutex); QTAILQ_INIT(&dev->requests); scsi_device_realize(dev, &local_err); if (local_err) { @@ -417,6 +418,8 @@ static void scsi_qdev_unrealize(DeviceState *qdev) =20 scsi_device_unrealize(dev); =20 + qemu_mutex_destroy(&dev->pr_state.mutex); + blockdev_mark_auto_del(dev->conf.blk); } =20 diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 0a676a16fa..2ddd435856 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -264,6 +264,160 @@ static int scsi_generic_emulate_block_limits(SCSIGene= ricReq *r, SCSIDevice *s) return r->buflen; } =20 +/* + * Patch persistent reservation capabilities that are not emulated. + */ +static void scsi_handle_persistent_reserve_in_reply(SCSIGenericReq *r, + SCSIDevice *s) +{ + uint8_t service_action =3D r->req.cmd.buf[1] & 0x1f; + + if (!s->migrate_pr) { + return; /* when migration is disabled there is no need for patchin= g */ + } + + if (service_action =3D=3D PRI_REPORT_CAPABILITIES) { + assert(r->buflen >=3D 3); + + /* + * Clear specify initiator ports capable (SIP_C) and all target po= rts + * capable (ATC_C). + * + * SPEC_I_PT is not supported because the guest sees an emulated S= CSI + * bus and does not have the underlying transport IDs needed to use + * SPEC_I_PT. + * + * ALL_TG_PT is not supported because we only track the state of t= his + * emulated I_T nexus, not the underlying device's target ports. + */ + r->buf[2] &=3D ~0xc; + } +} + +static int scsi_generic_read_reservation(SCSIDevice *s, uint64_t *key, + uint8_t *resv_type, Error **errp) +{ + uint8_t cmd[10] =3D {}; + uint8_t buf[24] =3D {}; + uint32_t additional_length; + int ret; + + *key =3D 0; + *resv_type =3D 0; + + cmd[0] =3D PERSISTENT_RESERVE_IN; + cmd[1] =3D PRI_READ_RESERVATION; + cmd[8] =3D sizeof(buf); + + ret =3D scsi_SG_IO(s->conf.blk, SG_DXFER_FROM_DEV, cmd, sizeof(cmd), + buf, sizeof(buf), s->io_timeout, errp); + if (ret < 0) { + return ret; + } + + memcpy(&additional_length, &buf[4], sizeof(additional_length)); + be32_to_cpus(&additional_length); + + if (additional_length >=3D 0x10) { + memcpy(key, &buf[8], sizeof(*key)); + be64_to_cpus(key); + + *resv_type =3D buf[21] & 0xf; + } + return 0; +} + +/* + * Snoop changes to registered keys and reservations so that this informat= ion + * can be transferred during live migration. + */ +static void scsi_handle_persistent_reserve_out_reply( + SCSIGenericReq *r, + SCSIDevice *s) +{ + SCSIPRState *pr_state =3D &s->pr_state; + uint8_t service_action =3D r->req.cmd.buf[1] & 0x1f; + uint8_t resv_type =3D r->req.cmd.buf[2] & 0xf; + uint64_t old_key; + uint64_t new_key; + + assert(r->buflen >=3D 16); + memcpy(&old_key, &r->buf[0], sizeof(old_key)); + memcpy(&new_key, &r->buf[8], sizeof(new_key)); + be64_to_cpus(&old_key); + be64_to_cpus(&new_key); + + trace_scsi_generic_persistent_reserve_out_reply(service_action, resv_t= ype, + old_key, new_key); + + switch (service_action) { + case PRO_REGISTER: /* fallthrough */ + case PRO_REGISTER_AND_IGNORE_EXISTING_KEY: + if (service_action =3D=3D PRO_REGISTER && old_key =3D=3D 0 && new_= key =3D=3D 0) { + /* Do nothing */ + } else { + WITH_QEMU_LOCK_GUARD(&pr_state->mutex) { + pr_state->key =3D new_key; + if (new_key =3D=3D 0) { + pr_state->resv_type =3D 0; /* release reservation */ + } + } + } + break; + + case PRO_RESERVE: + WITH_QEMU_LOCK_GUARD(&pr_state->mutex) { + pr_state->resv_type =3D resv_type; + } + break; + + case PRO_RELEASE: + WITH_QEMU_LOCK_GUARD(&pr_state->mutex) { + pr_state->resv_type =3D 0; + } + break; + + case PRO_CLEAR: + WITH_QEMU_LOCK_GUARD(&pr_state->mutex) { + pr_state->key =3D 0; + pr_state->resv_type =3D 0; + } + break; + + case PRO_REPLACE_LOST_RESERVATION: + WITH_QEMU_LOCK_GUARD(&pr_state->mutex) { + pr_state->key =3D new_key; + pr_state->resv_type =3D resv_type; + } + break; + + case PRO_PREEMPT: /* fallthrough */ + case PRO_PREEMPT_AND_ABORT: { + uint64_t dev_key; + uint8_t dev_resv_type; + + /* Not enough information to know actual state, ask the device */ + if (!scsi_generic_read_reservation(s, &dev_key, &dev_resv_type, NU= LL)) { + WITH_QEMU_LOCK_GUARD(&pr_state->mutex) { + if (pr_state->key =3D=3D dev_key) { + pr_state->resv_type =3D dev_resv_type; + } else { + pr_state->resv_type =3D 0; + } + } + } + break; + } + + /* + * PRO_REGISTER_AND_MOVE cannot be implemented since it involves the + * physical SCSI bus target ports. + */ + default: + break; /* do nothing */ + } +} + static void scsi_read_complete(void * opaque, int ret) { SCSIGenericReq *r =3D (SCSIGenericReq *)opaque; @@ -346,6 +500,9 @@ static void scsi_read_complete(void * opaque, int ret) if (r->req.cmd.buf[0] =3D=3D INQUIRY) { len =3D scsi_handle_inquiry_reply(r, s, len); } + if (r->req.cmd.buf[0] =3D=3D PERSISTENT_RESERVE_IN) { + scsi_handle_persistent_reserve_in_reply(r, s); + } =20 req_complete: scsi_req_data(&r->req, len); @@ -395,6 +552,9 @@ static void scsi_write_complete(void * opaque, int ret) s->blocksize =3D (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11= ]; trace_scsi_generic_write_complete_blocksize(s->blocksize); } + if (r->req.cmd.buf[0] =3D=3D PERSISTENT_RESERVE_OUT) { + scsi_handle_persistent_reserve_out_reply(r, s); + } =20 scsi_command_complete_noio(r, ret); } diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events index 3e81f44dad..ff92fff7c5 100644 --- a/hw/scsi/trace-events +++ b/hw/scsi/trace-events @@ -390,3 +390,4 @@ scsi_generic_realize_blocksize(int blocksize) "block si= ze %d" scsi_generic_aio_sgio_command(uint32_t tag, uint8_t cmd, uint32_t timeout)= "generic aio sgio: tag=3D0x%x cmd=3D0x%x timeout=3D%u" scsi_generic_ioctl_sgio_command(uint8_t cmd, uint32_t timeout) "generic io= ctl sgio: cmd=3D0x%x timeout=3D%u" scsi_generic_ioctl_sgio_done(uint8_t cmd, int ret, uint8_t status, uint8_t= host_status) "generic ioctl sgio: cmd=3D0x%x ret=3D%d status=3D0x%x host_s= tatus=3D0x%x" +scsi_generic_persistent_reserve_out_reply(uint8_t service_action, uint8_t = resv_type, uint64_t old_key, uint64_t new_key) "persistent reserve out repl= y service_action=3D%u resv_type=3D%u old_key=3D0x%" PRIx64 " new_key=3D0x%"= PRIx64 --=20 2.52.0 From nobody Mon Feb 9 16:54:14 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1768341266; cv=none; d=zohomail.com; s=zohoarc; b=Yb9VzPoqUYN7sJeo5uFCsRVyS3DsE7kKuc1hV1jw2jVF67Z0xCTGBBHnzc70eFS+/HQFmBuoBUalHibeBBeaeZ5rx2WAnW9l2HMSO5lUzLidJIKZYgQJ4iw3C0ojEh6dJk3wC9N++0fA0e6tYFXymQWEcn6+sZ8buxNPsN4PPJo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1768341266; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=q0dcZXhBjmLLQUTeeJFsKlsh82Kr8vxODUFR62980Qk=; b=ELdOnfekcowq8k5HcP0CIyU/MvSTZtaQqLya5Kn1nKFZ/nfZn2LgcyD5r6cJAQc16hbC6sid7HlKvbVpqJJ9Y1QEHdd+FwI+CVLp4cvmrA0/uXZZbpmKzR7GUCbkakzXoMALwdTtvd3bUx0UfDauPPscPLNUz7LsEbd71xkyba8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1768341266842847.0114009365685; Tue, 13 Jan 2026 13:54:26 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vfmKY-0004Xu-Fl; Tue, 13 Jan 2026 16:53:38 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vfmKV-0004Vj-FL for qemu-devel@nongnu.org; Tue, 13 Jan 2026 16:53:35 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vfmKT-0001sn-Qe for qemu-devel@nongnu.org; Tue, 13 Jan 2026 16:53:35 -0500 Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-358-qj4vBpk9OB-YaSQLzt3gnQ-1; Tue, 13 Jan 2026 16:53:29 -0500 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 8F1B31956050; Tue, 13 Jan 2026 21:53:27 +0000 (UTC) Received: from localhost (unknown [10.2.16.89]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3DFCD1800285; Tue, 13 Jan 2026 21:53:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1768341213; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=q0dcZXhBjmLLQUTeeJFsKlsh82Kr8vxODUFR62980Qk=; b=e3RKdVoKPxa2oKX5rK7KqQmkNmYe4gNj1pZrn8J4DsLa7UWYXYb4vdBCNeDmESx54k2K2N 7s9bSIG+7CWTXR0v7SqlntOn6vgtNLKsQBOnEQynWLOXRK5ZBZjLEeZdJTKJbiF10k5r13 d7EmeK4ClZIJo5YW43UZbmvmYpmmhu8= X-MC-Unique: qj4vBpk9OB-YaSQLzt3gnQ-1 X-Mimecast-MFC-AGG-ID: qj4vBpk9OB-YaSQLzt3gnQ_1768341208 From: Stefan Hajnoczi To: qemu-devel@nongnu.org Cc: Fam Zheng , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , pkrempa@redhat.com, Hannes Reinecke , Yanan Wang , Kevin Wolf , Eduardo Habkost , Alberto Faria , Paolo Bonzini , Marcel Apfelbaum , qemu-block@nongnu.org, Zhao Liu , Stefan Hajnoczi Subject: [RFC 2/4] scsi: generalize scsi_SG_IO_FROM_DEV() to scsi_SG_IO() Date: Tue, 13 Jan 2026 16:53:17 -0500 Message-ID: <20260113215320.566595-3-stefanha@redhat.com> In-Reply-To: <20260113215320.566595-1-stefanha@redhat.com> References: <20260113215320.566595-1-stefanha@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=stefanha@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1768341269117158500 Content-Type: text/plain; charset="utf-8" Add a direction argument so that scsi_SG_IO() can be used for SG_DXFER_FROM_DEV and SG_DXFER_TO_DEV transfers. Signed-off-by: Stefan Hajnoczi --- include/hw/scsi/scsi.h | 4 ++-- hw/scsi/scsi-disk.c | 4 ++-- hw/scsi/scsi-generic.c | 18 ++++++++++-------- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 23bd5b4b5e..1a01842c28 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -246,8 +246,8 @@ void scsi_device_report_change(SCSIDevice *dev, SCSISen= se sense); void scsi_device_unit_attention_reported(SCSIDevice *dev); void scsi_generic_read_device_inquiry(SCSIDevice *dev); int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fix= ed); -int scsi_SG_IO_FROM_DEV(BlockBackend *blk, uint8_t *cmd, uint8_t cmd_size, - uint8_t *buf, uint8_t buf_size, uint32_t timeout); +int scsi_SG_IO(BlockBackend *blk, int direction, uint8_t *cmd, uint8_t cmd= _size, + uint8_t *buf, uint8_t buf_size, uint32_t timeout); SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lu= n); SCSIDevice *scsi_device_get(SCSIBus *bus, int channel, int target, int lun= ); =20 diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 0f896c27f4..97ae535a27 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2748,8 +2748,8 @@ static int get_device_type(SCSIDiskState *s) cmd[0] =3D INQUIRY; cmd[4] =3D sizeof(buf); =20 - ret =3D scsi_SG_IO_FROM_DEV(s->qdev.conf.blk, cmd, sizeof(cmd), - buf, sizeof(buf), s->qdev.io_timeout); + ret =3D scsi_SG_IO(s->qdev.conf.blk, SG_DXFER_FROM_DEV, cmd, sizeof(cm= d), + buf, sizeof(buf), s->qdev.io_timeout); if (ret < 0) { return -1; } diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 2ddd435856..6ef673aa4b 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -684,8 +684,9 @@ static int read_naa_id(const uint8_t *p, uint64_t *p_ww= n) return -EINVAL; } =20 -int scsi_SG_IO_FROM_DEV(BlockBackend *blk, uint8_t *cmd, uint8_t cmd_size, - uint8_t *buf, uint8_t buf_size, uint32_t timeout) +int scsi_SG_IO(BlockBackend *blk, int direction, uint8_t *cmd, + uint8_t cmd_size, uint8_t *buf, uint8_t buf_size, + uint32_t timeout) { sg_io_hdr_t io_header; uint8_t sensebuf[8]; @@ -693,7 +694,7 @@ int scsi_SG_IO_FROM_DEV(BlockBackend *blk, uint8_t *cmd= , uint8_t cmd_size, =20 memset(&io_header, 0, sizeof(io_header)); io_header.interface_id =3D 'S'; - io_header.dxfer_direction =3D SG_DXFER_FROM_DEV; + io_header.dxfer_direction =3D direction; io_header.dxfer_len =3D buf_size; io_header.dxferp =3D buf; io_header.cmdp =3D cmd; @@ -733,8 +734,8 @@ static void scsi_generic_set_vpd_bl_emulation(SCSIDevic= e *s) cmd[2] =3D 0x00; cmd[4] =3D sizeof(buf); =20 - ret =3D scsi_SG_IO_FROM_DEV(s->conf.blk, cmd, sizeof(cmd), - buf, sizeof(buf), s->io_timeout); + ret =3D scsi_SG_IO(s->conf.blk, SG_DXFER_FROM_DEV, cmd, sizeof(cmd), + buf, sizeof(buf), s->io_timeout); if (ret < 0) { /* * Do not assume anything if we can't retrieve the @@ -769,8 +770,8 @@ static void scsi_generic_read_device_identification(SCS= IDevice *s) cmd[2] =3D 0x83; cmd[4] =3D sizeof(buf); =20 - ret =3D scsi_SG_IO_FROM_DEV(s->conf.blk, cmd, sizeof(cmd), - buf, sizeof(buf), s->io_timeout); + ret =3D scsi_SG_IO(s->conf.blk, SG_DXFER_FROM_DEV, cmd, sizeof(cmd), + buf, sizeof(buf), s->io_timeout); if (ret < 0) { return; } @@ -821,7 +822,8 @@ static int get_stream_blocksize(BlockBackend *blk) cmd[0] =3D MODE_SENSE; cmd[4] =3D sizeof(buf); =20 - ret =3D scsi_SG_IO_FROM_DEV(blk, cmd, sizeof(cmd), buf, sizeof(buf), 6= ); + ret =3D scsi_SG_IO(blk, SG_DXFER_FROM_DEV, cmd, sizeof(cmd), + buf, sizeof(buf), 6); if (ret < 0) { return -1; } --=20 2.52.0 From nobody Mon Feb 9 16:54:14 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1768341256; cv=none; d=zohomail.com; s=zohoarc; b=WlvH/tctdBDJYZa88EExRCC9/vzS4E5CV/PzosBSWhn/I3ql9AyC1hJnpO9H357vFNhQAVatjkop+G8LotHuvyHUQC4nXBUe9Kt+nuMKe/flkvBWWjXbSx19/uCAnKPuR7Tj0mYW8mTzDOODq2PNG9ej4+QLMwjSmNnEwEIT/P0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1768341256; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=9NqomSuT6/W740TEO6RcpdcYiO7U/ORLpsRNggJkj7E=; b=PWaHNjFWXRriuW6lhxh2B4EBEC+JxE0B1Ss5u0e8D4lzrTGGIHCFnVr95DIXFrWvYtTXbtVaOoXoBQPprTC++DI4hmrWo9rm/l08oHInT7vzppEqwVgyl0bQBTNe/o91xNKG6vyOVXK4z2rWuMs0wQDNvu/X2FLOu2k/BGE0qdM= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1768341256597324.54202572921133; Tue, 13 Jan 2026 13:54:16 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vfmKX-0004XE-MG; Tue, 13 Jan 2026 16:53:37 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vfmKX-0004Wu-2a for qemu-devel@nongnu.org; Tue, 13 Jan 2026 16:53:37 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vfmKV-0001vG-GC for qemu-devel@nongnu.org; Tue, 13 Jan 2026 16:53:36 -0500 Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-613-Ss9Ulg9iMjaEEKQWhZFCTw-1; Tue, 13 Jan 2026 16:53:31 -0500 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 78E331956080; Tue, 13 Jan 2026 21:53:29 +0000 (UTC) Received: from localhost (unknown [10.2.16.89]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id DA85B30001A2; Tue, 13 Jan 2026 21:53:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1768341214; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9NqomSuT6/W740TEO6RcpdcYiO7U/ORLpsRNggJkj7E=; b=C2axVctbS1tSGxoCyPoDksJzt4DPsnP+p6kJH5qkTncfuPSHaEt2eqr/rf0bR50rU5L0er 1fX6XcmpGYJmP0+ISMcROcGFpVYHE5ZBC6P8FLXC5zo9OC6VOHP3Vz8rEFqfYfrLT08gpT d7lE6z/n/J448bpmVMjnrnWjR1h6mK4= X-MC-Unique: Ss9Ulg9iMjaEEKQWhZFCTw-1 X-Mimecast-MFC-AGG-ID: Ss9Ulg9iMjaEEKQWhZFCTw_1768341209 From: Stefan Hajnoczi To: qemu-devel@nongnu.org Cc: Fam Zheng , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , pkrempa@redhat.com, Hannes Reinecke , Yanan Wang , Kevin Wolf , Eduardo Habkost , Alberto Faria , Paolo Bonzini , Marcel Apfelbaum , qemu-block@nongnu.org, Zhao Liu , Stefan Hajnoczi Subject: [RFC 3/4] scsi: add error reporting to scsi_SG_IO() Date: Tue, 13 Jan 2026 16:53:18 -0500 Message-ID: <20260113215320.566595-4-stefanha@redhat.com> In-Reply-To: <20260113215320.566595-1-stefanha@redhat.com> References: <20260113215320.566595-1-stefanha@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=stefanha@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1768341259631158500 Content-Type: text/plain; charset="utf-8" Report the details of the SG_IO ioctl failure if an Error pointer is provided. This information aids troubleshooting and will be used by the SCSI Persistent Reservations migration code. Signed-off-by: Stefan Hajnoczi --- include/hw/scsi/scsi.h | 2 +- hw/scsi/scsi-disk.c | 2 +- hw/scsi/scsi-generic.c | 33 ++++++++++++++++++++++++++++----- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 1a01842c28..c5ec58089b 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -247,7 +247,7 @@ void scsi_device_unit_attention_reported(SCSIDevice *de= v); void scsi_generic_read_device_inquiry(SCSIDevice *dev); int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fix= ed); int scsi_SG_IO(BlockBackend *blk, int direction, uint8_t *cmd, uint8_t cmd= _size, - uint8_t *buf, uint8_t buf_size, uint32_t timeout); + uint8_t *buf, uint8_t buf_size, uint32_t timeout, Error **e= rrp); SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lu= n); SCSIDevice *scsi_device_get(SCSIBus *bus, int channel, int target, int lun= ); =20 diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 97ae535a27..76fe5f085b 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2749,7 +2749,7 @@ static int get_device_type(SCSIDiskState *s) cmd[4] =3D sizeof(buf); =20 ret =3D scsi_SG_IO(s->qdev.conf.blk, SG_DXFER_FROM_DEV, cmd, sizeof(cm= d), - buf, sizeof(buf), s->qdev.io_timeout); + buf, sizeof(buf), s->qdev.io_timeout, NULL); if (ret < 0) { return -1; } diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 6ef673aa4b..f22a38f725 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -686,10 +686,10 @@ static int read_naa_id(const uint8_t *p, uint64_t *p_= wwn) =20 int scsi_SG_IO(BlockBackend *blk, int direction, uint8_t *cmd, uint8_t cmd_size, uint8_t *buf, uint8_t buf_size, - uint32_t timeout) + uint32_t timeout, Error **errp) { sg_io_hdr_t io_header; - uint8_t sensebuf[8]; + uint8_t sensebuf[8] =3D {}; int ret; =20 memset(&io_header, 0, sizeof(io_header)); @@ -709,6 +709,29 @@ int scsi_SG_IO(BlockBackend *blk, int direction, uint8= _t *cmd, io_header.driver_status || io_header.host_status) { trace_scsi_generic_ioctl_sgio_done(cmd[0], ret, io_header.status, io_header.host_status); + if (ret < 0) { + error_setg_errno(errp, -ret, "SG_IO ioctl failed"); + } else { + g_autofree char *sensebuf_hex =3D + g_strdup_printf("%02x%02x%02x%02x%02x%02x%02x%02x", + sensebuf[0], + sensebuf[1], + sensebuf[2], + sensebuf[3], + sensebuf[4], + sensebuf[5], + sensebuf[6], + sensebuf[7]); + + error_setg(errp, "SG_IO SCSI command failed with status=3D0x%x= " + "driver_status=3D0x%x host_status=3D0x%x sensebuf=3D%s= " + "sb_len_wr=3D%u", + io_header.status, + io_header.driver_status, + io_header.host_status, + sensebuf_hex, + io_header.sb_len_wr); + } return -1; } return 0; @@ -735,7 +758,7 @@ static void scsi_generic_set_vpd_bl_emulation(SCSIDevic= e *s) cmd[4] =3D sizeof(buf); =20 ret =3D scsi_SG_IO(s->conf.blk, SG_DXFER_FROM_DEV, cmd, sizeof(cmd), - buf, sizeof(buf), s->io_timeout); + buf, sizeof(buf), s->io_timeout, NULL); if (ret < 0) { /* * Do not assume anything if we can't retrieve the @@ -771,7 +794,7 @@ static void scsi_generic_read_device_identification(SCS= IDevice *s) cmd[4] =3D sizeof(buf); =20 ret =3D scsi_SG_IO(s->conf.blk, SG_DXFER_FROM_DEV, cmd, sizeof(cmd), - buf, sizeof(buf), s->io_timeout); + buf, sizeof(buf), s->io_timeout, NULL); if (ret < 0) { return; } @@ -823,7 +846,7 @@ static int get_stream_blocksize(BlockBackend *blk) cmd[4] =3D sizeof(buf); =20 ret =3D scsi_SG_IO(blk, SG_DXFER_FROM_DEV, cmd, sizeof(cmd), - buf, sizeof(buf), 6); + buf, sizeof(buf), 6, NULL); if (ret < 0) { return -1; } --=20 2.52.0 From nobody Mon Feb 9 16:54:14 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1768341256; cv=none; d=zohomail.com; s=zohoarc; b=iNc61Kpo95ppYWihyVCgmJZ8G9qqn3EnKLnJQ611dbr1aOdEQXFOX0J5W9qLW3/giPCNlt0Gzk7XwOQmOd4U+DzjNTqTVk29OakVwYkWXf2sntttMhgG3ClDb7x6oEb+ZsJ56/A2onYXV0YUuumvprf8d2SKwp+SjNmR5yGfLoE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1768341256; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=tlGI82dwJ0RGmFSTomne2vOSq0GSClzlfVJXz6DWa0c=; b=QXB5PnRREZ0X5/RMgAguuhHVR8Dt/i2bu7tuf83j5jThMGfNM8GYdiSRTbcvdaywH6f0b/9O1qT06VLIAu6gZLO7CxQQ20Nt9sQytQG0f/23yc6KKLSeN0Fj50VYrjU0wzJS9kSXddnc6nNA0eAB4T/gb9ZOV3JhlkSxjgsdyNc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1768341256803935.1366271566324; Tue, 13 Jan 2026 13:54:16 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vfmKb-0004Z3-3J; Tue, 13 Jan 2026 16:53:41 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vfmKZ-0004YV-AZ for qemu-devel@nongnu.org; Tue, 13 Jan 2026 16:53:39 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vfmKX-0001xX-Gf for qemu-devel@nongnu.org; Tue, 13 Jan 2026 16:53:39 -0500 Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-193-9gMVX5RzNVSsbvPtLOLB1Q-1; Tue, 13 Jan 2026 16:53:33 -0500 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id BE24F1956067; Tue, 13 Jan 2026 21:53:31 +0000 (UTC) Received: from localhost (unknown [10.2.16.89]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E36181800285; Tue, 13 Jan 2026 21:53:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1768341216; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=tlGI82dwJ0RGmFSTomne2vOSq0GSClzlfVJXz6DWa0c=; b=T2dapTwse7yoD97vr3OsU45eKYprT0FztvO86OdXnXWkFNtTyy9jyny71cIfecnCxhbxGD YEvAXNKzmY/EoQPMnEiKAKywbTxpGhUuhI9eGilCxOGROEnh55ma+0Sb2rxO/13qjK7Gek Mb5nXp4d/bFgb3MBTdNgIzS0kfnGGG0= X-MC-Unique: 9gMVX5RzNVSsbvPtLOLB1Q-1 X-Mimecast-MFC-AGG-ID: 9gMVX5RzNVSsbvPtLOLB1Q_1768341212 From: Stefan Hajnoczi To: qemu-devel@nongnu.org Cc: Fam Zheng , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , pkrempa@redhat.com, Hannes Reinecke , Yanan Wang , Kevin Wolf , Eduardo Habkost , Alberto Faria , Paolo Bonzini , Marcel Apfelbaum , qemu-block@nongnu.org, Zhao Liu , Stefan Hajnoczi Subject: [RFC 4/4] scsi: save/load SCSI reservation state Date: Tue, 13 Jan 2026 16:53:19 -0500 Message-ID: <20260113215320.566595-5-stefanha@redhat.com> In-Reply-To: <20260113215320.566595-1-stefanha@redhat.com> References: <20260113215320.566595-1-stefanha@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=stefanha@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1768341259687158500 Content-Type: text/plain; charset="utf-8" Add a vmstate subsection to SCSIDiskState so that scsi-block devices can transfer their reservation state during live migration. Upon loading the subsection, the destination QEMU invokes the PERSISTENT RESERVE OUT command's PREEMPT service action to atomically move the reservation from the source I_T nexus to the destination I_T nexus. This results in transparent live migration of SCSI reservations. This approach is incomplete since SCSI reservations are cooperative and other hosts could interfere. Neither the source QEMU nor the destination QEMU are aware of changes made by other hosts. The assumption is that reservation is not taken over by a third host without cooperation from the source host. I considered adding the vmstate subsection to SCSIDevice instead of SCSIDiskState, since reservations are part of the SCSI Primary Commands that other devices apart from disks could support. However, due to fragility of migrating reservations, we will probably limit support to scsi-block and maybe scsi-disk in the future. In the end, I think it makes sense to place this within scsi-disk.c. Signed-off-by: Stefan Hajnoczi --- include/hw/scsi/scsi.h | 1 + hw/core/machine.c | 4 +- hw/scsi/scsi-disk.c | 49 ++++++++++++++++++++++++- hw/scsi/scsi-generic.c | 83 ++++++++++++++++++++++++++++++++++++++++++ hw/scsi/trace-events | 1 + 5 files changed, 136 insertions(+), 2 deletions(-) diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index c5ec58089b..d104557bac 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -253,6 +253,7 @@ SCSIDevice *scsi_device_get(SCSIBus *bus, int channel, = int target, int lun); =20 /* scsi-generic.c. */ extern const SCSIReqOps scsi_generic_req_ops; +bool scsi_generic_pr_state_post_load_errp(SCSIDevice *s, Error **errp); =20 /* scsi-disk.c */ #define SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR 0 diff --git a/hw/core/machine.c b/hw/core/machine.c index 6411e68856..16134f8ce5 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -38,7 +38,9 @@ #include "hw/acpi/generic_event_device.h" #include "qemu/audio.h" =20 -GlobalProperty hw_compat_10_2[] =3D {}; +GlobalProperty hw_compat_10_2[] =3D { + { "scsi-block", "migrate-pr", "off" }, +}; const size_t hw_compat_10_2_len =3D G_N_ELEMENTS(hw_compat_10_2); =20 GlobalProperty hw_compat_10_1[] =3D { diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 76fe5f085b..82e5b59534 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -3209,6 +3209,46 @@ static const Property scsi_hd_properties[] =3D { DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf), }; =20 +#ifdef __linux__ +static bool scsi_disk_pr_state_post_load_errp(void *opaque, int version_id= , Error **errp) +{ + SCSIDiskState *s =3D opaque; + SCSIDevice *dev =3D &s->qdev; + + return scsi_generic_pr_state_post_load_errp(dev, errp); +} + +static bool scsi_disk_pr_state_needed(void *opaque) +{ + SCSIDiskState *s =3D opaque; + SCSIPRState *pr_state =3D &s->qdev.pr_state; + bool ret; + + if (!s->qdev.migrate_pr) { + return false; + } + + /* A reservation requires a key, so checking this field is enough */ + WITH_QEMU_LOCK_GUARD(&pr_state->mutex) { + ret =3D pr_state->key; + } + return ret; +} + +static const VMStateDescription vmstate_scsi_disk_pr_state =3D { + .name =3D "scsi-disk/pr", + .version_id =3D 1, + .minimum_version_id =3D 1, + .post_load_errp =3D scsi_disk_pr_state_post_load_errp, + .needed =3D scsi_disk_pr_state_needed, + .fields =3D (const VMStateField[]) { + VMSTATE_UINT64(qdev.pr_state.key, SCSIDiskState), + VMSTATE_UINT8(qdev.pr_state.resv_type, SCSIDiskState), + VMSTATE_END_OF_LIST() + } +}; +#endif /* __linux__ */ + static const VMStateDescription vmstate_scsi_disk_state =3D { .name =3D "scsi-disk", .version_id =3D 1, @@ -3221,7 +3261,13 @@ static const VMStateDescription vmstate_scsi_disk_st= ate =3D { VMSTATE_BOOL(tray_open, SCSIDiskState), VMSTATE_BOOL(tray_locked, SCSIDiskState), VMSTATE_END_OF_LIST() - } + }, + .subsections =3D (const VMStateDescription * const []) { +#ifdef __linux__ + &vmstate_scsi_disk_pr_state, +#endif + NULL + }, }; =20 static void scsi_hd_class_initfn(ObjectClass *klass, const void *data) @@ -3301,6 +3347,7 @@ static const Property scsi_block_properties[] =3D { -1), DEFINE_PROP_UINT32("io_timeout", SCSIDiskState, qdev.io_timeout, DEFAULT_IO_TIMEOUT), + DEFINE_PROP_BOOL("migrate-pr", SCSIDiskState, qdev.migrate_pr, true), }; =20 static void scsi_block_class_initfn(ObjectClass *klass, const void *data) diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index f22a38f725..2acfd21232 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -418,6 +418,89 @@ static void scsi_handle_persistent_reserve_out_reply( } } =20 +static bool scsi_generic_pr_register(SCSIDevice *s, uint64_t key, Error **= errp) +{ + uint8_t cmd[10] =3D {}; + uint8_t buf[24] =3D {}; + uint64_t key_be =3D cpu_to_be64(key); + int ret; + + cmd[0] =3D PERSISTENT_RESERVE_OUT; + cmd[1] =3D PRO_REGISTER; + cmd[8] =3D sizeof(buf); + memcpy(&buf[8], &key_be, sizeof(key_be)); + + ret =3D scsi_SG_IO(s->conf.blk, SG_DXFER_TO_DEV, cmd, sizeof(cmd), + buf, sizeof(buf), s->io_timeout, errp); + if (ret < 0) { + error_prepend(errp, "PERSISTENT RESERVE OUT with REGISTER"); + return false; + } + return true; +} + +static bool scsi_generic_pr_preempt(SCSIDevice *s, uint64_t key, uint8_t r= esv_type, Error **errp) +{ + uint8_t cmd[10] =3D {}; + uint8_t buf[24] =3D {}; + uint64_t key_be =3D cpu_to_be64(key); + int ret; + + cmd[0] =3D PERSISTENT_RESERVE_OUT; + cmd[1] =3D PRO_PREEMPT; + cmd[2] =3D resv_type & 0xf; + cmd[8] =3D sizeof(buf); + memcpy(&buf[0], &key_be, sizeof(key_be)); + memcpy(&buf[8], &key_be, sizeof(key_be)); + + ret =3D scsi_SG_IO(s->conf.blk, SG_DXFER_TO_DEV, cmd, sizeof(cmd), + buf, sizeof(buf), s->io_timeout, errp); + if (ret < 0) { + error_prepend(errp, "PERSISTENT RESERVE OUT with PREEMPT"); + return false; + } + return true; +} + +/* Register keys and preempt reservations after live migration */ +bool scsi_generic_pr_state_post_load_errp(SCSIDevice *s, Error **errp) +{ + SCSIPRState *pr_state =3D &s->pr_state; + uint64_t key; + uint8_t resv_type; + + WITH_QEMU_LOCK_GUARD(&pr_state->mutex) { + key =3D pr_state->key; + resv_type =3D pr_state->resv_type; + } + + trace_scsi_generic_pr_state_post_load_errp(key, resv_type); + + if (key) { + if (!scsi_generic_pr_register(s, key, errp)) { + return false; + } + + /* + * Two cases: + * + * 1. There is no reservation (resv_type is 0) and the other I_T n= exus + * will be unregistered. This is important so the source host d= oes + * not leak registered keys across live migration. + * + * 2. There is a reservation (resv_type is not 0) and the other I_T + * nexus will be unregistered and its reservation is atomically + * taken over by us. This is the scenario where a reservation is + * migrated along with the guest. + */ + if (!scsi_generic_pr_preempt(s, key, resv_type, errp)) { + return false; + } + } + /* TODO is rollback needed on the source host if migration fails after= this point? */ + return true; +} + static void scsi_read_complete(void * opaque, int ret) { SCSIGenericReq *r =3D (SCSIGenericReq *)opaque; diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events index ff92fff7c5..cff8235e9a 100644 --- a/hw/scsi/trace-events +++ b/hw/scsi/trace-events @@ -391,3 +391,4 @@ scsi_generic_aio_sgio_command(uint32_t tag, uint8_t cmd= , uint32_t timeout) "gene scsi_generic_ioctl_sgio_command(uint8_t cmd, uint32_t timeout) "generic io= ctl sgio: cmd=3D0x%x timeout=3D%u" scsi_generic_ioctl_sgio_done(uint8_t cmd, int ret, uint8_t status, uint8_t= host_status) "generic ioctl sgio: cmd=3D0x%x ret=3D%d status=3D0x%x host_s= tatus=3D0x%x" scsi_generic_persistent_reserve_out_reply(uint8_t service_action, uint8_t = resv_type, uint64_t old_key, uint64_t new_key) "persistent reserve out repl= y service_action=3D%u resv_type=3D%u old_key=3D0x%" PRIx64 " new_key=3D0x%"= PRIx64 +scsi_generic_pr_state_post_load_errp(uint64_t key, uint8_t resv_type) "key= =3D0x%" PRIx64 " resv_type=3D%u" --=20 2.52.0