From: Brian Bunker <brian@purestorage.com>
To: linux-scsi@vger.kernel.org
Cc: "Martin K . Petersen" <mkp@kernel.org>,
"Martin K . Petersen" <martin.petersen@oracle.com>,
James.Bottomley@HansenPartnership.com,
Hannes Reinecke <hare@suse.de>,
Bart Van Assche <bvanassche@acm.org>,
krishna.kant@purestorage.com,
Brian Bunker <brian@purestorage.com>,
Hannes Reinecke <hare@kernel.org>
Subject: [PATCH v6 2/5] scsi: core: Add scsi_update_inquiry_data() for updating INQUIRY data
Date: Mon, 12 Oct 2026 14:05:03 -0700 [thread overview]
Message-ID: <20261012210511.16061-3-brian@purestorage.com> (raw)
In-Reply-To: <20261012210511.16061-1-brian@purestorage.com>
Add a new function scsi_update_inquiry_data() that can safely update all
INQUIRY-derived fields for an existing SCSI device:
- Vendor, model, revision strings
- Peripheral qualifier and device type
- Capability flags (removable, lockable, tagged queuing support, etc.)
- ATA device detection and allow_restart setting
The function:
- Takes the inquiry_mutex to protect against concurrent sysfs reads
- Respects BLIST_ISROM and BLIST_NOTQ blacklist flags
- Returns 1 if device type or peripheral qualifier changed, indicating
the caller should call device_reprobe() to re-match drivers
- Returns 0 on success with no changes requiring reprobe
- Returns negative errno on failure
This is the core infrastructure needed for updating INQUIRY data during
device rescan operations, which is required for proper ALUA unavailable
state handling.
Co-developed-by: Krishna Kant <krishna.kant@purestorage.com>
Signed-off-by: Krishna Kant <krishna.kant@purestorage.com>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Signed-off-by: Brian Bunker <brian@purestorage.com>
---
drivers/scsi/scsi.c | 178 +++++++++++++++++++++++++++++++++++++
include/scsi/scsi_device.h | 13 +++
2 files changed, 191 insertions(+)
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 3af9e77847f7..b80378ecf485 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -61,6 +61,7 @@
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_device.h>
+#include <scsi/scsi_devinfo.h>
#include <scsi/scsi_driver.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_host.h>
@@ -549,6 +550,183 @@ void scsi_attach_vpd(struct scsi_device *sdev)
kfree(vpd_buf);
}
+/**
+ * scsi_update_inquiry_data - Update standard INQUIRY data for a SCSI device
+ * @sdev: The device to update
+ * @inq_result: Buffer containing new INQUIRY data
+ * @inq_len: Length of inquiry data
+ *
+ * Updates the standard INQUIRY data (vendor, model, rev, peripheral qualifier,
+ * device type, removable media flag) and capability flags derived from INQUIRY
+ * data for a SCSI device. This is used during both initial device setup and
+ * when reprobing a device to get fresh INQUIRY information. The old inquiry
+ * buffer is freed and replaced with the new data under the protection of
+ * inquiry_mutex.
+ *
+ * Blacklist flags (BLIST_ISROM, BLIST_NOTQ) are respected when updating
+ * device properties.
+ *
+ * Returns:
+ * SCSI_INQ_UNCHANGED on success
+ * SCSI_INQ_REPROBE_NEEDED if standard INQUIRY data changed (caller should reprobe)
+ * -ENOMEM on allocation failure
+ * -EINVAL if inquiry data is too short
+ */
+int scsi_update_inquiry_data(struct scsi_device *sdev,
+ unsigned char *inq_result, size_t inq_len)
+{
+ unsigned char *new_inquiry;
+ unsigned char old_type;
+ unsigned char old_periph_qual;
+ bool had_prior_inquiry;
+
+ /*
+ * Ensure we have at least the minimum standard INQUIRY data (36 bytes)
+ * to safely access device type, vendor, model, rev, and capability flags.
+ */
+ if (inq_len < 36) {
+ sdev_printk(KERN_WARNING, sdev,
+ "INQUIRY data too short (%zu bytes), need at least 36\n",
+ inq_len);
+ return -EINVAL;
+ }
+
+ /* Allocate new inquiry buffer */
+ new_inquiry = kmemdup(inq_result, inq_len, GFP_KERNEL);
+ if (!new_inquiry)
+ return -ENOMEM;
+
+ /* Update inquiry data under mutex protection */
+ mutex_lock(&sdev->inquiry_mutex);
+
+ /*
+ * Save peripheral qualifier and device type before updating all
+ * INQUIRY-derived fields. These are the only two values that
+ * determine whether device_reprobe() is needed: type controls which
+ * upper-layer driver (sd, st, sr, ...) is bound, and PQ controls
+ * whether the LUN is accessible at all (scsi_bus_match() only matches
+ * PQ == 0). Every other field — vendor, model, revision, capability
+ * flags — is refreshed in place without any driver re-matching.
+ */
+ had_prior_inquiry = (sdev->inquiry != NULL);
+ old_type = sdev->type;
+ old_periph_qual = sdev->inq_periph_qual;
+
+ kfree(sdev->inquiry);
+ sdev->inquiry = new_inquiry;
+ sdev->inquiry_len = inq_len;
+ strscpy(sdev->vendor, sdev->inquiry + INQUIRY_VENDOR_OFFSET);
+ strscpy(sdev->model, sdev->inquiry + INQUIRY_MODEL_OFFSET);
+ /*
+ * memcpy() instead of strscpy() because strscpy() would read past
+ * the end of sdev->inquiry if its length is exactly 36 bytes.
+ */
+ memcpy(sdev->rev, sdev->inquiry + INQUIRY_REVISION_OFFSET,
+ INQUIRY_REVISION_LEN);
+ sdev->rev[INQUIRY_REVISION_LEN] = '\0';
+ sdev->inq_periph_qual = (inq_result[0] >> 5) & 7;
+
+ /*
+ * Compute scsi_level from INQUIRY bytes 2 and 3. This must be
+ * updated under inquiry_mutex alongside the other INQUIRY-derived
+ * fields so sysfs readers always see a consistent snapshot.
+ */
+ sdev->scsi_level = inq_result[2] & 0x0f;
+ if (sdev->scsi_level >= 2 ||
+ (sdev->scsi_level == 1 && (inq_result[3] & 0x0f) == 1))
+ sdev->scsi_level++;
+
+ /*
+ * Check if this is an ATA device (SATA emulation layer).
+ * ATA devices need allow_restart set to work around SATL power
+ * management specifications.
+ */
+ if (strncmp(sdev->vendor, "ATA ", 8) == 0) {
+ sdev->is_ata = 1;
+ sdev->allow_restart = 1;
+ } else
+ sdev->is_ata = 0;
+
+ /*
+ * Update device type from INQUIRY byte 0.
+ * BLIST_ISROM is a quirk for devices that report wrong type but should
+ * be treated as (removable) CD-ROM. Override to TYPE_ROM as exception.
+ */
+ if (sdev->sdev_bflags & BLIST_ISROM) {
+ sdev->type = TYPE_ROM;
+ sdev->removable = 1;
+ } else {
+ sdev->type = inq_result[0] & 0x1f;
+ sdev->removable = (inq_result[1] & 0x80) >> 7;
+
+ /*
+ * Some devices may respond with wrong type for well-known
+ * logical units. Force well-known type to enumerate them
+ * correctly.
+ */
+ if (scsi_is_wlun(sdev->lun) && sdev->type != TYPE_WLUN) {
+ sdev_printk(KERN_WARNING, sdev,
+ "%s: correcting incorrect peripheral device type 0x%x for W-LUN 0x%16xhN\n",
+ __func__, sdev->type,
+ (unsigned int)sdev->lun);
+ sdev->type = TYPE_WLUN;
+ }
+ }
+
+ /*
+ * Set lockable to match removable. Devices with removable media
+ * can typically have their media locked/unlocked via the
+ * ALLOW_MEDIUM_REMOVAL command.
+ */
+ sdev->lockable = sdev->removable;
+
+ /* Update capability flags from INQUIRY byte 7 */
+ sdev->soft_reset = (inq_result[7] & 1) && ((inq_result[3] & 7) == 2);
+
+ /*
+ * Update protocol support flags.
+ * Only update ppr if we have enough INQUIRY data (>56 bytes) to check
+ * byte 56, or if scsi_level indicates SCSI-3+ support. If we don't have
+ * enough data, leave ppr unchanged to avoid incorrectly clearing it
+ * during rescan with short INQUIRY.
+ */
+ if (sdev->scsi_level >= SCSI_3 || inq_len > 56)
+ sdev->ppr = (sdev->scsi_level >= SCSI_3 ||
+ (inq_len > 56 && inq_result[56] & 0x04)) ? 1 : 0;
+ sdev->wdtr = !!(inq_result[7] & 0x60);
+ sdev->sdtr = !!(inq_result[7] & 0x10);
+
+ /*
+ * Update tagged queuing support from INQUIRY byte 7.
+ * BLIST_NOTQ is an exception to force tagged queuing off.
+ */
+ if (sdev->sdev_bflags & BLIST_NOTQ)
+ sdev->tagged_supported = 0;
+ else
+ sdev->tagged_supported = (sdev->scsi_level >= SCSI_2) &&
+ (inq_result[7] & 2);
+ sdev->simple_tags = sdev->tagged_supported;
+
+ mutex_unlock(&sdev->inquiry_mutex);
+
+ if (had_prior_inquiry) {
+ if (old_type != sdev->type) {
+ sdev_printk(KERN_NOTICE, sdev,
+ "device type changed from %d to %d\n",
+ old_type, sdev->type);
+ return SCSI_INQ_REPROBE_NEEDED;
+ }
+ if (old_periph_qual != sdev->inq_periph_qual) {
+ sdev_printk(KERN_NOTICE, sdev,
+ "peripheral qualifier changed from %d to %d\n",
+ old_periph_qual, sdev->inq_periph_qual);
+ return SCSI_INQ_REPROBE_NEEDED;
+ }
+ }
+
+ return SCSI_INQ_UNCHANGED;
+}
+
/**
* scsi_report_opcode - Find out if a given command is supported
* @sdev: scsi device to query
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index e6fd6bc30644..743babf1602c 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -408,6 +408,19 @@ void scsi_attach_vpd(struct scsi_device *sdev);
void scsi_cdl_check(struct scsi_device *sdev);
int scsi_cdl_enable(struct scsi_device *sdev, bool enable);
+/**
+ * enum scsi_inq_update_result - Return values for scsi_update_inquiry_data()
+ * @SCSI_INQ_UNCHANGED: INQUIRY data updated, no reprobe needed
+ * @SCSI_INQ_REPROBE_NEEDED: INQUIRY data updated, standard INQUIRY data changed
+ */
+enum scsi_inq_update_result {
+ SCSI_INQ_UNCHANGED = 0,
+ SCSI_INQ_REPROBE_NEEDED = 1,
+};
+
+int scsi_update_inquiry_data(struct scsi_device *sdev,
+ unsigned char *inq_result, size_t inq_len);
+
extern int __must_check scsi_device_get(struct scsi_device *);
extern void scsi_device_put(struct scsi_device *);
extern struct scsi_device *scsi_device_lookup(struct Scsi_Host *,
--
2.55.0
next prev parent reply other threads:[~2026-10-12 21:05 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-12 21:05 [PATCH v6 0/5] scsi: Refresh INQUIRY data and reprobe on rescan Brian Bunker
2026-10-12 21:05 ` [PATCH v6 1/5] scsi: core: Protect INQUIRY sysfs attributes with mutex Brian Bunker
2026-10-12 21:05 ` Brian Bunker [this message]
2026-10-12 21:27 ` [PATCH v6 2/5] scsi: core: Add scsi_update_inquiry_data() for updating INQUIRY data sashiko-bot
2026-10-13 10:02 ` Damien Le Moal
2026-10-12 21:05 ` [PATCH v6 3/5] scsi: core: Refactor scsi_add_lun() to use scsi_update_inquiry_data() Brian Bunker
2026-10-12 21:27 ` sashiko-bot
2026-10-12 21:05 ` [PATCH v6 4/5] scsi: core: Add device reprobe support to scsi_rescan_device() Brian Bunker
2026-10-12 21:27 ` sashiko-bot
2026-10-12 21:05 ` [PATCH v6 5/5] scsi: core: Handle reprobe for existing devices during SCSI scan Brian Bunker
2026-10-12 21:24 ` sashiko-bot
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=20261012210511.16061-3-brian@purestorage.com \
--to=brian@purestorage.com \
--cc=James.Bottomley@HansenPartnership.com \
--cc=bvanassche@acm.org \
--cc=hare@kernel.org \
--cc=hare@suse.de \
--cc=krishna.kant@purestorage.com \
--cc=linux-scsi@vger.kernel.org \
--cc=martin.petersen@oracle.com \
--cc=mkp@kernel.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.