* [PATCH] scsi: core: add re-probe logic into SCSI rescan @ 2025-11-13 20:18 Brian Bunker 2025-11-14 9:48 ` kernel test robot 2025-11-27 14:53 ` Hannes Reinecke 0 siblings, 2 replies; 3+ messages in thread From: Brian Bunker @ 2025-11-13 20:18 UTC (permalink / raw) To: linux-scsi; +Cc: Brian Bunker, Krishna Kant SCSI rescanning will skip updating inquiry data if a device has already been created. This means that if a target changes the inquiry data of a device whether or not a unit attention is posted that will not ever be changed on a device. This is a particular problem for handling the ALUA unavailable state which requires setting the peripheral qualifier on a LUN. This toggling of that value makes it impossible without this functionality to properly handle that state. Additionally this fixes the updating of inquiry data when a unit attention of inquiry data has changed is returned from the target. Acked-by: Krishna Kant <krishna.kant@purestorage.com> Signed-off-by: Brian Bunker <brian@purestorage.com> --- drivers/scsi/scsi.c | 120 ++++++++++++++++++ drivers/scsi/scsi_scan.c | 246 +++++++++++++++++++++++++------------ include/scsi/scsi_device.h | 2 + 3 files changed, 292 insertions(+), 76 deletions(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 9a0f467264b3..c03ba25793f8 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -544,6 +544,126 @@ 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 an existing SCSI device. This is used 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_NOT_LOCKABLE, BLIST_NOTQ) are respected + * when updating device properties. + * + * Returns: + * 0 on success + * 1 if device type or peripheral qualifier changed (caller should call device_reprobe()) + * -ENOMEM on allocation failure + */ +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; + + /* Allocate new inquiry buffer */ + new_inquiry = kmemdup(inq_result, max_t(size_t, inq_len, 36), + GFP_KERNEL); + if (!new_inquiry) + return -ENOMEM; + + /* Update inquiry data under mutex protection */ + mutex_lock(&sdev->inquiry_mutex); + + /* Save old values to detect changes that require reprobe */ + old_type = sdev->type; + old_periph_qual = sdev->inq_periph_qual; + + kfree(sdev->inquiry); + sdev->inquiry = new_inquiry; + sdev->vendor = (char *)(sdev->inquiry + 8); + sdev->model = (char *)(sdev->inquiry + 16); + sdev->rev = (char *)(sdev->inquiry + 32); + sdev->inq_periph_qual = (inq_result[0] >> 5) & 7; + + /* + * Update device type and removable media flag from INQUIRY bytes 0-1. + * This is the single source of truth for setting these fields from + * INQUIRY data, used by both initial probe (scsi_add_lun) and reprobe + * (scsi_rescan_device, scsi_probe_and_add_lun). + */ + if (!(sdev->sdev_bflags & BLIST_ISROM)) { + 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; + } + + /* lockable defaults to removable, unless blacklist overrides */ + sdev->lockable = sdev->removable; + if (sdev->sdev_bflags & BLIST_NOT_LOCKABLE) + sdev->lockable = 0; + } + + /* Update capability flags from INQUIRY byte 7 */ + sdev->soft_reset = ((inq_result[7] & 1) && ((inq_result[3] & 7) == 2)) ? 1 : 0; + + /* Update protocol support flags */ + sdev->ppr = (sdev->scsi_level >= SCSI_3 || + (inq_len > 56 && inq_result[56] & 0x04)) ? 1 : 0; + sdev->wdtr = (inq_result[7] & 0x60) ? 1 : 0; + sdev->sdtr = (inq_result[7] & 0x10) ? 1 : 0; + + /* Update tagged queuing support */ + sdev->tagged_supported = ((sdev->scsi_level >= SCSI_2) && + (inq_result[7] & 2) && + !(sdev->sdev_bflags & BLIST_NOTQ)) ? 1 : 0; + sdev->simple_tags = sdev->tagged_supported; + + mutex_unlock(&sdev->inquiry_mutex); + + /* + * If device type or peripheral qualifier changed, return a special + * code to indicate that caller should trigger device_reprobe() to + * re-match with appropriate upper-layer driver. + * + * - Type changes require different drivers (sd vs sr vs st, etc.) + * - PQ changes affect scsi_bus_match() which only matches PQ == 0 + * + * Note: We check this AFTER updating all fields and releasing the + * mutex, so all INQUIRY-derived data is current regardless of whether + * reprobe is needed. + */ + if (old_type != sdev->type || old_periph_qual != sdev->inq_periph_qual) { + if (old_type != sdev->type) + sdev_printk(KERN_NOTICE, sdev, + "device type changed from %d to %d\n", + old_type, sdev->type); + 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 1; /* Type or PQ changed - caller should reprobe */ + } + + return 0; +} +EXPORT_SYMBOL(scsi_update_inquiry_data); + /** * scsi_report_opcode - Find out if a given command is supported * @sdev: scsi device to query diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 3c6e089e80c3..7f79b96ec992 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -898,19 +898,27 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, * these strings are invalid, but often they contain plausible data * nonetheless. It doesn't matter if the device sent < 36 bytes * total, since scsi_probe_lun() initializes inq_result with 0s. + * + * Set sdev_bflags before calling scsi_update_inquiry_data() so it + * can use the correct blacklist flags (especially BLIST_ISROM). */ - sdev->inquiry = kmemdup(inq_result, - max_t(size_t, sdev->inquiry_len, 36), - GFP_KERNEL); - if (sdev->inquiry == NULL) - return SCSI_SCAN_NO_RESPONSE; + sdev->sdev_bflags = *bflags; - sdev->vendor = (char *) (sdev->inquiry + 8); - sdev->model = (char *) (sdev->inquiry + 16); - sdev->rev = (char *) (sdev->inquiry + 32); + if (!sdev->inquiry) { + int ret = scsi_update_inquiry_data(sdev, inq_result, + sdev->inquiry_len); + if (ret < 0) { + return SCSI_SCAN_NO_RESPONSE; + } + /* Type or PQ change during initial setup is unexpected but not fatal */ + if (ret > 0) { + sdev_printk(KERN_NOTICE, sdev, + "device type or PQ changed during initial setup\n"); + } + } - sdev->is_ata = strncmp(sdev->vendor, "ATA ", 8) == 0; - if (sdev->is_ata) { + if (strncmp(sdev->vendor, "ATA ", 8) == 0) { + sdev->is_ata = 1; /* * sata emulation layer device. This is a hack to work around * the SATL power management specifications which state that @@ -920,26 +928,12 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, sdev->allow_restart = 1; } - if (*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; - } - - } + /* + * scsi_update_inquiry_data() has already set type, removable, lockable, + * inq_periph_qual, soft_reset, ppr, wdtr, sdtr, tagged_supported, and + * simple_tags from INQUIRY data. Handle special cases that need the + * raw inq_result or additional logic. + */ if (sdev->type == TYPE_RBC || sdev->type == TYPE_ROM) { /* RBC and MMC devices can return SCSI-3 compliance and yet @@ -950,46 +944,12 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, *bflags |= BLIST_NOREPORTLUN; } - /* - * For a peripheral qualifier (PQ) value of 1 (001b), the SCSI - * spec says: The device server is capable of supporting the - * specified peripheral device type on this logical unit. However, - * the physical device is not currently connected to this logical - * unit. - * - * The above is vague, as it implies that we could treat 001 and - * 011 the same. Stay compatible with previous code, and create a - * scsi_device for a PQ of 1 - * - * Don't set the device offline here; rather let the upper - * level drivers eval the PQ to decide whether they should - * attach. So remove ((inq_result[0] >> 5) & 7) == 1 check. - */ - - sdev->inq_periph_qual = (inq_result[0] >> 5) & 7; - sdev->lockable = sdev->removable; - sdev->soft_reset = (inq_result[7] & 1) && ((inq_result[3] & 7) == 2); - - if (sdev->scsi_level >= SCSI_3 || - (sdev->inquiry_len > 56 && inq_result[56] & 0x04)) - sdev->ppr = 1; - if (inq_result[7] & 0x60) - sdev->wdtr = 1; - if (inq_result[7] & 0x10) - sdev->sdtr = 1; - sdev_printk(KERN_NOTICE, sdev, "%s %.8s %.16s %.4s PQ: %d " "ANSI: %d%s\n", scsi_device_type(sdev->type), sdev->vendor, sdev->model, sdev->rev, sdev->inq_periph_qual, inq_result[2] & 0x07, (inq_result[3] & 0x0f) == 1 ? " CCS" : ""); - if ((sdev->scsi_level >= SCSI_2) && (inq_result[7] & 2) && - !(*bflags & BLIST_NOTQ)) { - sdev->tagged_supported = 1; - sdev->simple_tags = 1; - } - /* * Some devices (Texel CD ROM drives) have handshaking problems * when used with the Seagate controllers. borken is initialized @@ -1184,6 +1144,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, blist_flags_t bflags; int res = SCSI_SCAN_NO_RESPONSE, result_len = 256; struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + bool is_reprobe = false; /* * The rescan flag is used as an optimization, the first scan of a @@ -1191,7 +1152,19 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, */ sdev = scsi_device_lookup_by_target(starget, lun); if (sdev) { - if (rescan != SCSI_SCAN_INITIAL || !scsi_device_created(sdev)) { + if (rescan == SCSI_SCAN_INITIAL && !scsi_device_created(sdev)) { + /* + * During initial scan, if device is already fully initialized + * (not in CREATED state), skip reprobing. This is an optimization + * to avoid redundant probing during boot when the same LUN is + * discovered multiple times (e.g., via REPORT_LUNS and then + * sequential scan). + * + * Note: We don't check PQ here because sdev->inq_periph_qual + * is the cached value. If the target changed PQ, we won't detect + * it without sending INQUIRY. However, during initial boot scan, + * we assume devices don't change state, so this optimization is safe. + */ SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev, "scsi scan: device exists on %s\n", dev_name(&sdev->sdev_gendev))); @@ -1206,11 +1179,24 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, sdev->model); return SCSI_SCAN_LUN_PRESENT; } - scsi_device_put(sdev); - } else + /* + * For rescan operations or devices still being created, + * always reprobe to detect peripheral qualifier or device type + * changes: + * - PQ 0 -> non-zero: detach upper layer drivers (scsi_bus_match fails) + * - PQ non-zero -> 0: attach upper layer drivers (scsi_bus_match succeeds) + * - Type change: re-match with correct driver (sd vs sr vs st, etc.) + */ + SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev, + "scsi scan: device exists (type %d, PQ %d), reprobing\n", + sdev->type, sdev->inq_periph_qual)); + is_reprobe = true; + /* Continue with existing device - keep the reference */ + } else { sdev = scsi_alloc_sdev(starget, lun, hostdata); - if (!sdev) - goto out; + if (!sdev) + goto out; + } result = kmalloc(result_len, GFP_KERNEL); if (!result) @@ -1219,6 +1205,54 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, if (scsi_probe_lun(sdev, result, result_len, &bflags)) goto out_free_result; + /* + * For reprobe scenarios, update the inquiry data with fresh + * INQUIRY results. The device already exists in sysfs, so we + * don't call scsi_add_lun() which would try to add it again. + */ + if (is_reprobe) { + int update_ret = scsi_update_inquiry_data(sdev, result, result_len); + if (update_ret < 0) { + sdev_printk(KERN_WARNING, sdev, + "scsi scan: failed to update inquiry data\n"); + res = SCSI_SCAN_NO_RESPONSE; + goto out_free_result; + } + SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev, + "scsi scan: updated inquiry data (type %d, PQ %d)\n", + sdev->type, sdev->inq_periph_qual)); + + /* Update VPD pages with fresh data */ + if (sdev->scsi_level >= SCSI_3) + scsi_attach_vpd(sdev); + + if (bflagsp) + *bflagsp = bflags; + + /* + * Trigger device reprobe if type or PQ changed. + * scsi_update_inquiry_data() returns 1 when either changes. + * + * The scsi_bus_match() function only matches devices with + * PQ == 0, so PQ changes cause driver attach/detach. + * + * Device type changes require reprobe to match the correct + * upper-layer driver (e.g., sd for TYPE_DISK, sr for TYPE_ROM). + */ + if (update_ret > 0) { + SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev, + "scsi scan: type or PQ changed, reprobing for drivers\n")); + res = device_reprobe(&sdev->sdev_gendev); + if (res < 0) + sdev_printk(KERN_WARNING, sdev, + "scsi scan: device reprobe failed: %d\n", res); + } + + /* Device already exists, just return success */ + res = SCSI_SCAN_LUN_PRESENT; + goto out_free_result; + } + if (bflagsp) *bflagsp = bflags; /* @@ -1705,6 +1739,10 @@ EXPORT_SYMBOL(scsi_resume_device); int scsi_rescan_device(struct scsi_device *sdev) { struct device *dev = &sdev->sdev_gendev; + unsigned char *inq_result; + blist_flags_t bflags; + int result_len = 256; + int inquiry_ret = 0; int ret = 0; device_lock(dev); @@ -1721,19 +1759,75 @@ int scsi_rescan_device(struct scsi_device *sdev) goto unlock; } + /* + * Rescan standard INQUIRY data to detect changes in device + * properties (vendor, model, rev, peripheral qualifier, device type, etc.) + */ + inq_result = kmalloc(result_len, GFP_KERNEL); + if (inq_result) { + if (scsi_probe_lun(sdev, inq_result, result_len, + &bflags) == 0) { + /* Successfully got fresh INQUIRY data */ + inquiry_ret = scsi_update_inquiry_data(sdev, inq_result, + sdev->inquiry_len); + if (inquiry_ret < 0) { + sdev_printk(KERN_WARNING, sdev, + "scsi rescan: failed to update inquiry data\n"); + } else { + SCSI_LOG_SCAN_BUS(3, + sdev_printk(KERN_INFO, sdev, + "scsi rescan: updated inquiry data, PQ %d\n", + sdev->inq_periph_qual)); + } + } + kfree(inq_result); + } + scsi_attach_vpd(sdev); scsi_cdl_check(sdev); - if (sdev->handler && sdev->handler->rescan) - sdev->handler->rescan(sdev); + /* + * If peripheral qualifier or device type changed, reprobe to update + * driver attachment. scsi_update_inquiry_data() returns 1 when either + * changes. + * + * The scsi_bus_match() function only matches devices with PQ == 0, + * so PQ changes cause driver attach/detach. + * + * Device type changes require reprobe to match the correct upper-layer + * driver (e.g., sd for TYPE_DISK, sr for TYPE_ROM). + */ + if (inquiry_ret > 0) { + int reprobe_ret; - if (dev->driver && try_module_get(dev->driver->owner)) { - struct scsi_driver *drv = to_scsi_driver(dev->driver); + SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev, + "scsi rescan: type or PQ changed, reprobing\n")); - if (drv->rescan) - drv->rescan(dev); - module_put(dev->driver->owner); + device_unlock(dev); + reprobe_ret = device_reprobe(dev); + device_lock(dev); + + if (reprobe_ret < 0) { + sdev_printk(KERN_WARNING, sdev, + "scsi rescan: device reprobe failed: %d\n", reprobe_ret); + } + } else if (inquiry_ret == 0) { + /* + * PQ and type unchanged, just call driver's rescan + * function to update device properties (capacity, etc.) + */ + if (sdev->handler && sdev->handler->rescan) + sdev->handler->rescan(sdev); + + if (dev->driver && try_module_get(dev->driver->owner)) { + struct scsi_driver *drv = to_scsi_driver(dev->driver); + + if (drv->rescan) + drv->rescan(dev); + module_put(dev->driver->owner); + } } + /* If inquiry_ret < 0, INQUIRY failed - skip both reprobe and rescan */ unlock: device_unlock(dev); diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 993008cdea65..831b16422f5c 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -400,6 +400,8 @@ extern int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh); 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); +int scsi_update_inquiry_data(struct scsi_device *sdev, + unsigned char *inq_result, size_t inq_len); extern struct scsi_device *scsi_device_from_queue(struct request_queue *q); extern int __must_check scsi_device_get(struct scsi_device *); -- 2.51.0 ^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] scsi: core: add re-probe logic into SCSI rescan 2025-11-13 20:18 [PATCH] scsi: core: add re-probe logic into SCSI rescan Brian Bunker @ 2025-11-14 9:48 ` kernel test robot 2025-11-27 14:53 ` Hannes Reinecke 1 sibling, 0 replies; 3+ messages in thread From: kernel test robot @ 2025-11-14 9:48 UTC (permalink / raw) To: Brian Bunker, linux-scsi; +Cc: oe-kbuild-all, Brian Bunker, Krishna Kant Hi Brian, kernel test robot noticed the following build errors: [auto build test ERROR on jejb-scsi/for-next] [also build test ERROR on mkp-scsi/for-next linus/master v6.18-rc5 next-20251114] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Brian-Bunker/scsi-core-add-re-probe-logic-into-SCSI-rescan/20251114-042028 base: https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git for-next patch link: https://lore.kernel.org/r/20251113201819.76650-1-brian%40purestorage.com patch subject: [PATCH] scsi: core: add re-probe logic into SCSI rescan config: nios2-randconfig-r071-20251114 (https://download.01.org/0day-ci/archive/20251114/202511141703.pqiMI34x-lkp@intel.com/config) compiler: nios2-linux-gcc (GCC) 11.5.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251114/202511141703.pqiMI34x-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202511141703.pqiMI34x-lkp@intel.com/ All errors (new ones prefixed by >>): drivers/scsi/scsi.c: In function 'scsi_update_inquiry_data': >> drivers/scsi/scsi.c:600:35: error: 'BLIST_ISROM' undeclared (first use in this function) 600 | if (!(sdev->sdev_bflags & BLIST_ISROM)) { | ^~~~~~~~~~~ drivers/scsi/scsi.c:600:35: note: each undeclared identifier is reported only once for each function it appears in >> drivers/scsi/scsi.c:618:41: error: 'BLIST_NOT_LOCKABLE' undeclared (first use in this function) 618 | if (sdev->sdev_bflags & BLIST_NOT_LOCKABLE) | ^~~~~~~~~~~~~~~~~~ >> drivers/scsi/scsi.c:634:57: error: 'BLIST_NOTQ' undeclared (first use in this function) 634 | !(sdev->sdev_bflags & BLIST_NOTQ)) ? 1 : 0; | ^~~~~~~~~~ vim +/BLIST_ISROM +600 drivers/scsi/scsi.c 546 547 /** 548 * scsi_update_inquiry_data - Update standard INQUIRY data for a SCSI device 549 * @sdev: The device to update 550 * @inq_result: Buffer containing new INQUIRY data 551 * @inq_len: Length of inquiry data 552 * 553 * Updates the standard INQUIRY data (vendor, model, rev, peripheral qualifier, 554 * device type, removable media flag) and capability flags derived from INQUIRY 555 * data for an existing SCSI device. This is used when reprobing a device to get 556 * fresh INQUIRY information. The old inquiry buffer is freed and replaced with 557 * the new data under the protection of inquiry_mutex. 558 * 559 * Blacklist flags (BLIST_ISROM, BLIST_NOT_LOCKABLE, BLIST_NOTQ) are respected 560 * when updating device properties. 561 * 562 * Returns: 563 * 0 on success 564 * 1 if device type or peripheral qualifier changed (caller should call device_reprobe()) 565 * -ENOMEM on allocation failure 566 */ 567 int scsi_update_inquiry_data(struct scsi_device *sdev, 568 unsigned char *inq_result, size_t inq_len) 569 { 570 unsigned char *new_inquiry; 571 unsigned char old_type; 572 unsigned char old_periph_qual; 573 574 /* Allocate new inquiry buffer */ 575 new_inquiry = kmemdup(inq_result, max_t(size_t, inq_len, 36), 576 GFP_KERNEL); 577 if (!new_inquiry) 578 return -ENOMEM; 579 580 /* Update inquiry data under mutex protection */ 581 mutex_lock(&sdev->inquiry_mutex); 582 583 /* Save old values to detect changes that require reprobe */ 584 old_type = sdev->type; 585 old_periph_qual = sdev->inq_periph_qual; 586 587 kfree(sdev->inquiry); 588 sdev->inquiry = new_inquiry; 589 sdev->vendor = (char *)(sdev->inquiry + 8); 590 sdev->model = (char *)(sdev->inquiry + 16); 591 sdev->rev = (char *)(sdev->inquiry + 32); 592 sdev->inq_periph_qual = (inq_result[0] >> 5) & 7; 593 594 /* 595 * Update device type and removable media flag from INQUIRY bytes 0-1. 596 * This is the single source of truth for setting these fields from 597 * INQUIRY data, used by both initial probe (scsi_add_lun) and reprobe 598 * (scsi_rescan_device, scsi_probe_and_add_lun). 599 */ > 600 if (!(sdev->sdev_bflags & BLIST_ISROM)) { 601 sdev->type = inq_result[0] & 0x1f; 602 sdev->removable = (inq_result[1] & 0x80) >> 7; 603 604 /* 605 * some devices may respond with wrong type for 606 * well-known logical units. Force well-known type 607 * to enumerate them correctly. 608 */ 609 if (scsi_is_wlun(sdev->lun) && sdev->type != TYPE_WLUN) { 610 sdev_printk(KERN_WARNING, sdev, 611 "%s: correcting incorrect peripheral device type 0x%x for W-LUN 0x%16xhN\n", 612 __func__, sdev->type, (unsigned int)sdev->lun); 613 sdev->type = TYPE_WLUN; 614 } 615 616 /* lockable defaults to removable, unless blacklist overrides */ 617 sdev->lockable = sdev->removable; > 618 if (sdev->sdev_bflags & BLIST_NOT_LOCKABLE) 619 sdev->lockable = 0; 620 } 621 622 /* Update capability flags from INQUIRY byte 7 */ 623 sdev->soft_reset = ((inq_result[7] & 1) && ((inq_result[3] & 7) == 2)) ? 1 : 0; 624 625 /* Update protocol support flags */ 626 sdev->ppr = (sdev->scsi_level >= SCSI_3 || 627 (inq_len > 56 && inq_result[56] & 0x04)) ? 1 : 0; 628 sdev->wdtr = (inq_result[7] & 0x60) ? 1 : 0; 629 sdev->sdtr = (inq_result[7] & 0x10) ? 1 : 0; 630 631 /* Update tagged queuing support */ 632 sdev->tagged_supported = ((sdev->scsi_level >= SCSI_2) && 633 (inq_result[7] & 2) && > 634 !(sdev->sdev_bflags & BLIST_NOTQ)) ? 1 : 0; 635 sdev->simple_tags = sdev->tagged_supported; 636 637 mutex_unlock(&sdev->inquiry_mutex); 638 639 /* 640 * If device type or peripheral qualifier changed, return a special 641 * code to indicate that caller should trigger device_reprobe() to 642 * re-match with appropriate upper-layer driver. 643 * 644 * - Type changes require different drivers (sd vs sr vs st, etc.) 645 * - PQ changes affect scsi_bus_match() which only matches PQ == 0 646 * 647 * Note: We check this AFTER updating all fields and releasing the 648 * mutex, so all INQUIRY-derived data is current regardless of whether 649 * reprobe is needed. 650 */ 651 if (old_type != sdev->type || old_periph_qual != sdev->inq_periph_qual) { 652 if (old_type != sdev->type) 653 sdev_printk(KERN_NOTICE, sdev, 654 "device type changed from %d to %d\n", 655 old_type, sdev->type); 656 if (old_periph_qual != sdev->inq_periph_qual) 657 sdev_printk(KERN_NOTICE, sdev, 658 "peripheral qualifier changed from %d to %d\n", 659 old_periph_qual, sdev->inq_periph_qual); 660 return 1; /* Type or PQ changed - caller should reprobe */ 661 } 662 663 return 0; 664 } 665 EXPORT_SYMBOL(scsi_update_inquiry_data); 666 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] scsi: core: add re-probe logic into SCSI rescan 2025-11-13 20:18 [PATCH] scsi: core: add re-probe logic into SCSI rescan Brian Bunker 2025-11-14 9:48 ` kernel test robot @ 2025-11-27 14:53 ` Hannes Reinecke 1 sibling, 0 replies; 3+ messages in thread From: Hannes Reinecke @ 2025-11-27 14:53 UTC (permalink / raw) To: Brian Bunker, linux-scsi; +Cc: Krishna Kant On 11/13/25 21:18, Brian Bunker wrote: > SCSI rescanning will skip updating inquiry data if a device > has already been created. This means that if a target changes the > inquiry data of a device whether or not a unit attention is posted > that will not ever be changed on a device. > > This is a particular problem for handling the ALUA unavailable state > which requires setting the peripheral qualifier on a LUN. This > toggling of that value makes it impossible without this functionality > to properly handle that state. > > Additionally this fixes the updating of inquiry data when a unit > attention of inquiry data has changed is returned from the target. > In general this is not a bad idea; we're doing a similar thing for the VPD pages already, so it seems to be okay in general. But some comments further below: > Acked-by: Krishna Kant <krishna.kant@purestorage.com> > Signed-off-by: Brian Bunker <brian@purestorage.com> > --- > drivers/scsi/scsi.c | 120 ++++++++++++++++++ > drivers/scsi/scsi_scan.c | 246 +++++++++++++++++++++++++------------ > include/scsi/scsi_device.h | 2 + > 3 files changed, 292 insertions(+), 76 deletions(-) > > diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c > index 9a0f467264b3..c03ba25793f8 100644 > --- a/drivers/scsi/scsi.c > +++ b/drivers/scsi/scsi.c > @@ -544,6 +544,126 @@ 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 an existing SCSI device. This is used 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_NOT_LOCKABLE, BLIST_NOTQ) are respected > + * when updating device properties. > + * > + * Returns: > + * 0 on success > + * 1 if device type or peripheral qualifier changed (caller should call device_reprobe()) > + * -ENOMEM on allocation failure > + */ > +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; > + > + /* Allocate new inquiry buffer */ > + new_inquiry = kmemdup(inq_result, max_t(size_t, inq_len, 36), > + GFP_KERNEL); > + if (!new_inquiry) > + return -ENOMEM; > + > + /* Update inquiry data under mutex protection */ > + mutex_lock(&sdev->inquiry_mutex); > + > + /* Save old values to detect changes that require reprobe */ > + old_type = sdev->type; > + old_periph_qual = sdev->inq_periph_qual; > + > + kfree(sdev->inquiry); > + sdev->inquiry = new_inquiry; > + sdev->vendor = (char *)(sdev->inquiry + 8); > + sdev->model = (char *)(sdev->inquiry + 16); > + sdev->rev = (char *)(sdev->inquiry + 32); > + sdev->inq_periph_qual = (inq_result[0] >> 5) & 7; I really hate these. Can't we replace them with accessor functions and drop the pointers? > + > + /* > + * Update device type and removable media flag from INQUIRY bytes 0-1. > + * This is the single source of truth for setting these fields from > + * INQUIRY data, used by both initial probe (scsi_add_lun) and reprobe > + * (scsi_rescan_device, scsi_probe_and_add_lun). > + */ > + if (!(sdev->sdev_bflags & BLIST_ISROM)) { > + sdev->type = inq_result[0] & 0x1f; > + sdev->removable = (inq_result[1] & 0x80) >> 7; Similar here. We should use accessor functions and drop the structure entries. > + > + /* > + * 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; And the accessors can take this into account, too. > + } > + > + /* lockable defaults to removable, unless blacklist overrides */ > + sdev->lockable = sdev->removable; > + if (sdev->sdev_bflags & BLIST_NOT_LOCKABLE) > + sdev->lockable = 0; > + } > + > + /* Update capability flags from INQUIRY byte 7 */ > + sdev->soft_reset = ((inq_result[7] & 1) && ((inq_result[3] & 7) == 2)) ? 1 : 0; > + > + /* Update protocol support flags */ > + sdev->ppr = (sdev->scsi_level >= SCSI_3 || > + (inq_len > 56 && inq_result[56] & 0x04)) ? 1 : 0; > + sdev->wdtr = (inq_result[7] & 0x60) ? 1 : 0; > + sdev->sdtr = (inq_result[7] & 0x10) ? 1 : 0; > + > + /* Update tagged queuing support */ > + sdev->tagged_supported = ((sdev->scsi_level >= SCSI_2) && > + (inq_result[7] & 2) && > + !(sdev->sdev_bflags & BLIST_NOTQ)) ? 1 : 0; > + sdev->simple_tags = sdev->tagged_supported; > + > + mutex_unlock(&sdev->inquiry_mutex); > + And we even have an inquiry mutex, so we can hide the entire inquiry string update behind the mutex. Clearly we'll need to modify the sysfs attribute function to take the mutex, too, but that should be okay as it's not the hot path anyway. > + /* > + * If device type or peripheral qualifier changed, return a special > + * code to indicate that caller should trigger device_reprobe() to > + * re-match with appropriate upper-layer driver. > + * > + * - Type changes require different drivers (sd vs sr vs st, etc.) > + * - PQ changes affect scsi_bus_match() which only matches PQ == 0 > + * > + * Note: We check this AFTER updating all fields and releasing the > + * mutex, so all INQUIRY-derived data is current regardless of whether > + * reprobe is needed. > + */ > + if (old_type != sdev->type || old_periph_qual != sdev->inq_periph_qual) { > + if (old_type != sdev->type) > + sdev_printk(KERN_NOTICE, sdev, > + "device type changed from %d to %d\n", > + old_type, sdev->type); > + 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 1; /* Type or PQ changed - caller should reprobe */ > + } > + > + return 0; > +} > +EXPORT_SYMBOL(scsi_update_inquiry_data); > + > /** > * scsi_report_opcode - Find out if a given command is supported > * @sdev: scsi device to query > diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c > index 3c6e089e80c3..7f79b96ec992 100644 > --- a/drivers/scsi/scsi_scan.c > +++ b/drivers/scsi/scsi_scan.c > @@ -898,19 +898,27 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, > * these strings are invalid, but often they contain plausible data > * nonetheless. It doesn't matter if the device sent < 36 bytes > * total, since scsi_probe_lun() initializes inq_result with 0s. > + * > + * Set sdev_bflags before calling scsi_update_inquiry_data() so it > + * can use the correct blacklist flags (especially BLIST_ISROM). > */ > - sdev->inquiry = kmemdup(inq_result, > - max_t(size_t, sdev->inquiry_len, 36), > - GFP_KERNEL); > - if (sdev->inquiry == NULL) > - return SCSI_SCAN_NO_RESPONSE; > + sdev->sdev_bflags = *bflags; > > - sdev->vendor = (char *) (sdev->inquiry + 8); > - sdev->model = (char *) (sdev->inquiry + 16); > - sdev->rev = (char *) (sdev->inquiry + 32); > + if (!sdev->inquiry) { > + int ret = scsi_update_inquiry_data(sdev, inq_result, > + sdev->inquiry_len); > + if (ret < 0) { > + return SCSI_SCAN_NO_RESPONSE; > + } > + /* Type or PQ change during initial setup is unexpected but not fatal */ > + if (ret > 0) { > + sdev_printk(KERN_NOTICE, sdev, > + "device type or PQ changed during initial setup\n"); > + } > + } > > - sdev->is_ata = strncmp(sdev->vendor, "ATA ", 8) == 0; > - if (sdev->is_ata) { > + if (strncmp(sdev->vendor, "ATA ", 8) == 0) { > + sdev->is_ata = 1; That is a bit weird conceptually, as the conditional above checks for 'sdev->inquiry', so I would have expected a check for that within the condition. At least some sanity check the that inquiry string really is set. Or something. > /* > * sata emulation layer device. This is a hack to work around > * the SATL power management specifications which state that > @@ -920,26 +928,12 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, > sdev->allow_restart = 1; > } > > - if (*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; > - } > - > - } > + /* > + * scsi_update_inquiry_data() has already set type, removable, lockable, > + * inq_periph_qual, soft_reset, ppr, wdtr, sdtr, tagged_supported, and > + * simple_tags from INQUIRY data. Handle special cases that need the > + * raw inq_result or additional logic. > + */ > > if (sdev->type == TYPE_RBC || sdev->type == TYPE_ROM) { > /* RBC and MMC devices can return SCSI-3 compliance and yet > @@ -950,46 +944,12 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, > *bflags |= BLIST_NOREPORTLUN; > } > > - /* > - * For a peripheral qualifier (PQ) value of 1 (001b), the SCSI > - * spec says: The device server is capable of supporting the > - * specified peripheral device type on this logical unit. However, > - * the physical device is not currently connected to this logical > - * unit. > - * > - * The above is vague, as it implies that we could treat 001 and > - * 011 the same. Stay compatible with previous code, and create a > - * scsi_device for a PQ of 1 > - * > - * Don't set the device offline here; rather let the upper > - * level drivers eval the PQ to decide whether they should > - * attach. So remove ((inq_result[0] >> 5) & 7) == 1 check. > - */ > - > - sdev->inq_periph_qual = (inq_result[0] >> 5) & 7; > - sdev->lockable = sdev->removable; > - sdev->soft_reset = (inq_result[7] & 1) && ((inq_result[3] & 7) == 2); > - > - if (sdev->scsi_level >= SCSI_3 || > - (sdev->inquiry_len > 56 && inq_result[56] & 0x04)) > - sdev->ppr = 1; > - if (inq_result[7] & 0x60) > - sdev->wdtr = 1; > - if (inq_result[7] & 0x10) > - sdev->sdtr = 1; > - > sdev_printk(KERN_NOTICE, sdev, "%s %.8s %.16s %.4s PQ: %d " > "ANSI: %d%s\n", scsi_device_type(sdev->type), > sdev->vendor, sdev->model, sdev->rev, > sdev->inq_periph_qual, inq_result[2] & 0x07, > (inq_result[3] & 0x0f) == 1 ? " CCS" : ""); > > - if ((sdev->scsi_level >= SCSI_2) && (inq_result[7] & 2) && > - !(*bflags & BLIST_NOTQ)) { > - sdev->tagged_supported = 1; > - sdev->simple_tags = 1; > - } > - > /* > * Some devices (Texel CD ROM drives) have handshaking problems > * when used with the Seagate controllers. borken is initialized > @@ -1184,6 +1144,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, > blist_flags_t bflags; > int res = SCSI_SCAN_NO_RESPONSE, result_len = 256; > struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); > + bool is_reprobe = false; > > /* > * The rescan flag is used as an optimization, the first scan of a > @@ -1191,7 +1152,19 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, > */ > sdev = scsi_device_lookup_by_target(starget, lun); > if (sdev) { > - if (rescan != SCSI_SCAN_INITIAL || !scsi_device_created(sdev)) { > + if (rescan == SCSI_SCAN_INITIAL && !scsi_device_created(sdev)) { > + /* > + * During initial scan, if device is already fully initialized > + * (not in CREATED state), skip reprobing. This is an optimization > + * to avoid redundant probing during boot when the same LUN is > + * discovered multiple times (e.g., via REPORT_LUNS and then > + * sequential scan). > + * > + * Note: We don't check PQ here because sdev->inq_periph_qual > + * is the cached value. If the target changed PQ, we won't detect > + * it without sending INQUIRY. However, during initial boot scan, > + * we assume devices don't change state, so this optimization is safe. > + */ > SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev, > "scsi scan: device exists on %s\n", > dev_name(&sdev->sdev_gendev))); > @@ -1206,11 +1179,24 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, > sdev->model); > return SCSI_SCAN_LUN_PRESENT; > } > - scsi_device_put(sdev); > - } else > + /* > + * For rescan operations or devices still being created, > + * always reprobe to detect peripheral qualifier or device type > + * changes: > + * - PQ 0 -> non-zero: detach upper layer drivers (scsi_bus_match fails) > + * - PQ non-zero -> 0: attach upper layer drivers (scsi_bus_match succeeds) > + * - Type change: re-match with correct driver (sd vs sr vs st, etc.) > + */ > + SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev, > + "scsi scan: device exists (type %d, PQ %d), reprobing\n", > + sdev->type, sdev->inq_periph_qual)); > + is_reprobe = true; > + /* Continue with existing device - keep the reference */ > + } else { > sdev = scsi_alloc_sdev(starget, lun, hostdata); > - if (!sdev) > - goto out; > + if (!sdev) > + goto out; > + } > > result = kmalloc(result_len, GFP_KERNEL); > if (!result) > @@ -1219,6 +1205,54 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, > if (scsi_probe_lun(sdev, result, result_len, &bflags)) > goto out_free_result; > > + /* > + * For reprobe scenarios, update the inquiry data with fresh > + * INQUIRY results. The device already exists in sysfs, so we > + * don't call scsi_add_lun() which would try to add it again. > + */ > + if (is_reprobe) { > + int update_ret = scsi_update_inquiry_data(sdev, result, result_len); > + if (update_ret < 0) { > + sdev_printk(KERN_WARNING, sdev, > + "scsi scan: failed to update inquiry data\n"); > + res = SCSI_SCAN_NO_RESPONSE; > + goto out_free_result; > + } > + SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev, > + "scsi scan: updated inquiry data (type %d, PQ %d)\n", > + sdev->type, sdev->inq_periph_qual)); > + > + /* Update VPD pages with fresh data */ > + if (sdev->scsi_level >= SCSI_3) > + scsi_attach_vpd(sdev); > + > + if (bflagsp) > + *bflagsp = bflags; > + > + /* > + * Trigger device reprobe if type or PQ changed. > + * scsi_update_inquiry_data() returns 1 when either changes. > + * > + * The scsi_bus_match() function only matches devices with > + * PQ == 0, so PQ changes cause driver attach/detach. > + * > + * Device type changes require reprobe to match the correct > + * upper-layer driver (e.g., sd for TYPE_DISK, sr for TYPE_ROM). > + */ > + if (update_ret > 0) { > + SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev, > + "scsi scan: type or PQ changed, reprobing for drivers\n")); > + res = device_reprobe(&sdev->sdev_gendev); > + if (res < 0) > + sdev_printk(KERN_WARNING, sdev, > + "scsi scan: device reprobe failed: %d\n", res); > + } > + > + /* Device already exists, just return success */ > + res = SCSI_SCAN_LUN_PRESENT; > + goto out_free_result; > + } > + > if (bflagsp) > *bflagsp = bflags; > /* > @@ -1705,6 +1739,10 @@ EXPORT_SYMBOL(scsi_resume_device); > int scsi_rescan_device(struct scsi_device *sdev) > { > struct device *dev = &sdev->sdev_gendev; > + unsigned char *inq_result; > + blist_flags_t bflags; > + int result_len = 256; > + int inquiry_ret = 0; > int ret = 0; > > device_lock(dev); > @@ -1721,19 +1759,75 @@ int scsi_rescan_device(struct scsi_device *sdev) > goto unlock; > } > > + /* > + * Rescan standard INQUIRY data to detect changes in device > + * properties (vendor, model, rev, peripheral qualifier, device type, etc.) > + */ > + inq_result = kmalloc(result_len, GFP_KERNEL); > + if (inq_result) { > + if (scsi_probe_lun(sdev, inq_result, result_len, > + &bflags) == 0) { > + /* Successfully got fresh INQUIRY data */ > + inquiry_ret = scsi_update_inquiry_data(sdev, inq_result, > + sdev->inquiry_len); > + if (inquiry_ret < 0) { > + sdev_printk(KERN_WARNING, sdev, > + "scsi rescan: failed to update inquiry data\n"); > + } else { > + SCSI_LOG_SCAN_BUS(3, > + sdev_printk(KERN_INFO, sdev, > + "scsi rescan: updated inquiry data, PQ %d\n", > + sdev->inq_periph_qual)); > + } > + } > + kfree(inq_result); > + } > + > scsi_attach_vpd(sdev); > scsi_cdl_check(sdev); > > - if (sdev->handler && sdev->handler->rescan) > - sdev->handler->rescan(sdev); > + /* > + * If peripheral qualifier or device type changed, reprobe to update > + * driver attachment. scsi_update_inquiry_data() returns 1 when either > + * changes. > + * > + * The scsi_bus_match() function only matches devices with PQ == 0, > + * so PQ changes cause driver attach/detach. > + * > + * Device type changes require reprobe to match the correct upper-layer > + * driver (e.g., sd for TYPE_DISK, sr for TYPE_ROM). > + */ > + if (inquiry_ret > 0) { > + int reprobe_ret; > > - if (dev->driver && try_module_get(dev->driver->owner)) { > - struct scsi_driver *drv = to_scsi_driver(dev->driver); > + SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev, > + "scsi rescan: type or PQ changed, reprobing\n")); > > - if (drv->rescan) > - drv->rescan(dev); > - module_put(dev->driver->owner); > + device_unlock(dev); > + reprobe_ret = device_reprobe(dev); > + device_lock(dev); > + > + if (reprobe_ret < 0) { > + sdev_printk(KERN_WARNING, sdev, > + "scsi rescan: device reprobe failed: %d\n", reprobe_ret); > + } > + } else if (inquiry_ret == 0) { > + /* > + * PQ and type unchanged, just call driver's rescan > + * function to update device properties (capacity, etc.) > + */ > + if (sdev->handler && sdev->handler->rescan) > + sdev->handler->rescan(sdev); > + > + if (dev->driver && try_module_get(dev->driver->owner)) { > + struct scsi_driver *drv = to_scsi_driver(dev->driver); > + > + if (drv->rescan) > + drv->rescan(dev); > + module_put(dev->driver->owner); > + } > } > + /* If inquiry_ret < 0, INQUIRY failed - skip both reprobe and rescan */ > > unlock: > device_unlock(dev); > diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h > index 993008cdea65..831b16422f5c 100644 > --- a/include/scsi/scsi_device.h > +++ b/include/scsi/scsi_device.h > @@ -400,6 +400,8 @@ extern int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh); > 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); > +int scsi_update_inquiry_data(struct scsi_device *sdev, > + unsigned char *inq_result, size_t inq_len); > > extern struct scsi_device *scsi_device_from_queue(struct request_queue *q); > extern int __must_check scsi_device_get(struct scsi_device *); Cheers, Hannes -- Dr. Hannes Reinecke Kernel Storage Architect hare@suse.de +49 911 74053 688 SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-11-27 14:53 UTC | newest] Thread overview: 3+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-11-13 20:18 [PATCH] scsi: core: add re-probe logic into SCSI rescan Brian Bunker 2025-11-14 9:48 ` kernel test robot 2025-11-27 14:53 ` Hannes Reinecke
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox