For when no device handler is used, add ALUA support.
This will be equivalent to when native SCSI multipathing is used.
Essentially all the same handling is available as DH alua driver for
rescan, request prep, sense handling.
Signed-off-by: John Garry <john.g.garry@oracle.com>
---
drivers/scsi/scsi_alua.c | 93 +++++++++++++++++++++++++++++++++++++++
drivers/scsi/scsi_error.c | 7 +++
drivers/scsi/scsi_lib.c | 7 +++
drivers/scsi/scsi_scan.c | 2 +
drivers/scsi/scsi_sysfs.c | 4 +-
include/scsi/scsi_alua.h | 14 ++++++
6 files changed, 126 insertions(+), 1 deletion(-)
diff --git a/drivers/scsi/scsi_alua.c b/drivers/scsi/scsi_alua.c
index d3fcd887e5018..ee0229b1a9d12 100644
--- a/drivers/scsi/scsi_alua.c
+++ b/drivers/scsi/scsi_alua.c
@@ -562,6 +562,90 @@ int scsi_alua_stpg_run(struct scsi_device *sdev, bool optimize)
}
EXPORT_SYMBOL_GPL(scsi_alua_stpg_run);
+enum scsi_disposition scsi_alua_check_sense(struct scsi_device *sdev,
+ struct scsi_sense_hdr *sense_hdr)
+{
+ switch (sense_hdr->sense_key) {
+ case NOT_READY:
+ if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
+ /*
+ * LUN Not Accessible - ALUA state transition
+ */
+ scsi_alua_handle_state_transition(sdev);
+ return NEEDS_RETRY;
+ }
+ break;
+ case UNIT_ATTENTION:
+ if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
+ /*
+ * LUN Not Accessible - ALUA state transition
+ */
+ scsi_alua_handle_state_transition(sdev);
+ return NEEDS_RETRY;
+ }
+ if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) {
+ /*
+ * Power On, Reset, or Bus Device Reset.
+ * Might have obscured a state transition,
+ * so schedule a recheck.
+ */
+ scsi_device_alua_rescan(sdev);
+ return ADD_TO_MLQUEUE;
+ }
+ if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x04)
+ /*
+ * Device internal reset
+ */
+ return ADD_TO_MLQUEUE;
+ if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x01)
+ /*
+ * Mode Parameters Changed
+ */
+ return ADD_TO_MLQUEUE;
+ if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) {
+ /*
+ * ALUA state changed
+ */
+ scsi_device_alua_rescan(sdev);
+ return ADD_TO_MLQUEUE;
+ }
+ if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) {
+ /*
+ * Implicit ALUA state transition failed
+ */
+ scsi_device_alua_rescan(sdev);
+ return ADD_TO_MLQUEUE;
+ }
+ if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x03)
+ /*
+ * Inquiry data has changed
+ */
+ return ADD_TO_MLQUEUE;
+ if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x0e)
+ /*
+ * REPORTED_LUNS_DATA_HAS_CHANGED is reported
+ * when switching controllers on targets like
+ * Intel Multi-Flex. We can just retry.
+ */
+ return ADD_TO_MLQUEUE;
+ break;
+ }
+
+ return SCSI_RETURN_NOT_HANDLED;
+}
+
+static void alua_rtpg_work(struct work_struct *work)
+{
+ struct alua_data *alua =
+ container_of(work, struct alua_data, work.work);
+ int ret;
+
+ ret = scsi_alua_rtpg_run(alua->sdev);
+
+ if (ret == -EAGAIN)
+ queue_delayed_work(kalua_wq, &alua->work, alua->interval * HZ);
+}
+
int scsi_alua_sdev_init(struct scsi_device *sdev)
{
int rel_port, ret, tpgs;
@@ -591,6 +675,7 @@ int scsi_alua_sdev_init(struct scsi_device *sdev)
goto out_free_data;
}
+ INIT_DELAYED_WORK(&sdev->alua->work, alua_rtpg_work);
sdev->alua->sdev = sdev;
sdev->alua->tpgs = tpgs;
spin_lock_init(&sdev->alua->lock);
@@ -638,6 +723,14 @@ bool scsi_device_alua_implicit(struct scsi_device *sdev)
return sdev->alua->tpgs & TPGS_MODE_IMPLICIT;
}
+void scsi_device_alua_rescan(struct scsi_device *sdev)
+{
+ struct alua_data *alua = sdev->alua;
+
+ queue_delayed_work(kalua_wq, &alua->work,
+ msecs_to_jiffies(ALUA_RTPG_DELAY_MSECS));
+}
+
int scsi_alua_init(void)
{
kalua_wq = alloc_workqueue("kalua", WQ_MEM_RECLAIM | WQ_PERCPU, 0);
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 147127fb4db9c..a542e7a85a24d 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -29,6 +29,7 @@
#include <linux/jiffies.h>
#include <scsi/scsi.h>
+#include <scsi/scsi_alua.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_device.h>
@@ -578,6 +579,12 @@ enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd)
if (rc != SCSI_RETURN_NOT_HANDLED)
return rc;
/* handler does not care. Drop down to default handling */
+ } else if (scsi_device_alua_implicit(sdev)) {
+ enum scsi_disposition rc;
+
+ rc = scsi_alua_check_sense(sdev, &sshdr);
+ if (rc != SCSI_RETURN_NOT_HANDLED)
+ return rc;
}
if (scmd->cmnd[0] == TEST_UNIT_READY &&
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index d3a8cd4166f92..e5bcee555ea10 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -26,6 +26,7 @@
#include <linux/unaligned.h>
#include <scsi/scsi.h>
+#include <scsi/scsi_alua.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_device.h>
@@ -1719,6 +1720,12 @@ static blk_status_t scsi_prepare_cmd(struct request *req)
if (sdev->handler && sdev->handler->prep_fn) {
blk_status_t ret = sdev->handler->prep_fn(sdev, req);
+ if (ret != BLK_STS_OK)
+ return ret;
+ } else if (scsi_device_alua_implicit(sdev)) {
+ /* We should be able to make this common for ALUA DH as well */
+ blk_status_t ret = scsi_alua_prep_fn(sdev, req);
+
if (ret != BLK_STS_OK)
return ret;
}
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 3af64d1231445..73caf83bd1097 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -1744,6 +1744,8 @@ int scsi_rescan_device(struct scsi_device *sdev)
if (sdev->handler && sdev->handler->rescan)
sdev->handler->rescan(sdev);
+ else if (scsi_device_alua_implicit(sdev))
+ scsi_device_alua_rescan(sdev);
if (dev->driver && try_module_get(dev->driver->owner)) {
struct scsi_driver *drv = to_scsi_driver(dev->driver);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 6c4c3c22f6acf..71a9613898cfc 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -1152,7 +1152,7 @@ sdev_show_access_state(struct device *dev,
unsigned char access_state;
const char *access_state_name;
- if (!sdev->handler)
+ if (!sdev->handler && !scsi_device_alua_implicit(sdev))
return -EINVAL;
access_state = (sdev->access_state & SCSI_ACCESS_STATE_MASK);
@@ -1409,6 +1409,8 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
scsi_autopm_get_device(sdev);
scsi_dh_add_device(sdev);
+ if (!sdev->handler && scsi_device_alua_implicit(sdev))
+ scsi_device_alua_rescan(sdev);
error = device_add(&sdev->sdev_gendev);
if (error) {
diff --git a/include/scsi/scsi_alua.h b/include/scsi/scsi_alua.h
index 2d5db944f75b7..8e506d1d66cce 100644
--- a/include/scsi/scsi_alua.h
+++ b/include/scsi/scsi_alua.h
@@ -24,6 +24,7 @@ struct alua_data {
unsigned char transition_tmo;
unsigned long expiry;
unsigned long interval;
+ struct delayed_work work;
struct scsi_device *sdev;
spinlock_t lock;
};
@@ -35,11 +36,15 @@ void scsi_alua_handle_state_transition(struct scsi_device *sdev);
int scsi_alua_check_tpgs(struct scsi_device *sdev);
+enum scsi_disposition scsi_alua_check_sense(struct scsi_device *sdev,
+ struct scsi_sense_hdr *sense_hdr);
+
int scsi_alua_rtpg_run(struct scsi_device *sdev);
int scsi_alua_stpg_run(struct scsi_device *sdev, bool optimize);
blk_status_t scsi_alua_prep_fn(struct scsi_device *sdev, struct request *req);
+void scsi_device_alua_rescan(struct scsi_device *sdev);
bool scsi_device_alua_implicit(struct scsi_device *sdev);
int scsi_alua_init(void);
@@ -53,6 +58,12 @@ static inline int scsi_alua_check_tpgs(struct scsi_device *sdev)
{
return 0;
}
+static inline
+enum scsi_disposition scsi_alua_check_sense(struct scsi_device *sdev,
+ struct scsi_sense_hdr *sense_hdr)
+{
+ return SCSI_RETURN_NOT_HANDLED;
+}
static inline int scsi_alua_rtpg_run(struct scsi_device *sdev)
{
return 0;
@@ -66,6 +77,9 @@ blk_status_t scsi_alua_prep_fn(struct scsi_device *sdev, struct request *req)
{
return BLK_STS_OK;
}
+static inline void scsi_device_alua_rescan(struct scsi_device *sdev)
+{
+}
static inline bool scsi_device_alua_implicit(struct scsi_device *sdev)
{
return false;
--
2.43.5
On Tue, Mar 17, 2026 at 12:07:03PM +0000, John Garry wrote:
> For when no device handler is used, add ALUA support.
>
> This will be equivalent to when native SCSI multipathing is used.
>
> Essentially all the same handling is available as DH alua driver for
> rescan, request prep, sense handling.
>
> Signed-off-by: John Garry <john.g.garry@oracle.com>
> ---
> drivers/scsi/scsi_alua.c | 93 +++++++++++++++++++++++++++++++++++++++
> drivers/scsi/scsi_error.c | 7 +++
> drivers/scsi/scsi_lib.c | 7 +++
> drivers/scsi/scsi_scan.c | 2 +
> drivers/scsi/scsi_sysfs.c | 4 +-
> include/scsi/scsi_alua.h | 14 ++++++
> 6 files changed, 126 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/scsi/scsi_alua.c b/drivers/scsi/scsi_alua.c
> index d3fcd887e5018..ee0229b1a9d12 100644
> --- a/drivers/scsi/scsi_alua.c
> +++ b/drivers/scsi/scsi_alua.c
> @@ -562,6 +562,90 @@ int scsi_alua_stpg_run(struct scsi_device *sdev, bool optimize)
> }
> EXPORT_SYMBOL_GPL(scsi_alua_stpg_run);
>
> +enum scsi_disposition scsi_alua_check_sense(struct scsi_device *sdev,
> + struct scsi_sense_hdr *sense_hdr)
This seems like it should be shareable with scsi_dh_alua as well. In
might need to take a function to call for rescanning and have
alua_check_sense() be a wrapper around it, but since the force argument
to alua_check() is now always set to true in scsi_dh_alua, it's
unnecessary, so both it and scsi_device_alua_rescan() can have the
same arguments.
> +{
> + switch (sense_hdr->sense_key) {
> + case NOT_READY:
> + if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
> + /*
> + * LUN Not Accessible - ALUA state transition
> + */
> + scsi_alua_handle_state_transition(sdev);
> + return NEEDS_RETRY;
> + }
> + break;
> + case UNIT_ATTENTION:
> + if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
> + /*
> + * LUN Not Accessible - ALUA state transition
> + */
> + scsi_alua_handle_state_transition(sdev);
> + return NEEDS_RETRY;
> + }
> + if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) {
> + /*
> + * Power On, Reset, or Bus Device Reset.
> + * Might have obscured a state transition,
> + * so schedule a recheck.
> + */
> + scsi_device_alua_rescan(sdev);
> + return ADD_TO_MLQUEUE;
> + }
> + if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x04)
> + /*
> + * Device internal reset
> + */
> + return ADD_TO_MLQUEUE;
> + if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x01)
> + /*
> + * Mode Parameters Changed
> + */
> + return ADD_TO_MLQUEUE;
> + if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) {
> + /*
> + * ALUA state changed
> + */
> + scsi_device_alua_rescan(sdev);
> + return ADD_TO_MLQUEUE;
> + }
> + if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) {
> + /*
> + * Implicit ALUA state transition failed
> + */
> + scsi_device_alua_rescan(sdev);
> + return ADD_TO_MLQUEUE;
> + }
> + if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x03)
> + /*
> + * Inquiry data has changed
> + */
> + return ADD_TO_MLQUEUE;
> + if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x0e)
> + /*
> + * REPORTED_LUNS_DATA_HAS_CHANGED is reported
> + * when switching controllers on targets like
> + * Intel Multi-Flex. We can just retry.
> + */
> + return ADD_TO_MLQUEUE;
> + break;
> + }
> +
> + return SCSI_RETURN_NOT_HANDLED;
> +}
> +
> +static void alua_rtpg_work(struct work_struct *work)
> +{
> + struct alua_data *alua =
> + container_of(work, struct alua_data, work.work);
> + int ret;
> +
> + ret = scsi_alua_rtpg_run(alua->sdev);
> +
> + if (ret == -EAGAIN)
> + queue_delayed_work(kalua_wq, &alua->work, alua->interval * HZ);
> +}
> +
> int scsi_alua_sdev_init(struct scsi_device *sdev)
> {
> int rel_port, ret, tpgs;
> @@ -591,6 +675,7 @@ int scsi_alua_sdev_init(struct scsi_device *sdev)
> goto out_free_data;
> }
>
> + INIT_DELAYED_WORK(&sdev->alua->work, alua_rtpg_work);
> sdev->alua->sdev = sdev;
> sdev->alua->tpgs = tpgs;
> spin_lock_init(&sdev->alua->lock);
> @@ -638,6 +723,14 @@ bool scsi_device_alua_implicit(struct scsi_device *sdev)
> return sdev->alua->tpgs & TPGS_MODE_IMPLICIT;
> }
>
> +void scsi_device_alua_rescan(struct scsi_device *sdev)
> +{
> + struct alua_data *alua = sdev->alua;
> +
> + queue_delayed_work(kalua_wq, &alua->work,
> + msecs_to_jiffies(ALUA_RTPG_DELAY_MSECS));
This code doesn't support triggering a new rtpg while the current one is
running. I'll leave it to people with more scsi expertise to say how
important that is, but the scsi_dh_alua code now will always trigger a
new rtpg in this case (or at least it would, with the issues from patch
12 fixed).
-Ben
> +}
> +
> int scsi_alua_init(void)
> {
> kalua_wq = alloc_workqueue("kalua", WQ_MEM_RECLAIM | WQ_PERCPU, 0);
> diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
> index 147127fb4db9c..a542e7a85a24d 100644
> --- a/drivers/scsi/scsi_error.c
> +++ b/drivers/scsi/scsi_error.c
> @@ -29,6 +29,7 @@
> #include <linux/jiffies.h>
>
> #include <scsi/scsi.h>
> +#include <scsi/scsi_alua.h>
> #include <scsi/scsi_cmnd.h>
> #include <scsi/scsi_dbg.h>
> #include <scsi/scsi_device.h>
> @@ -578,6 +579,12 @@ enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd)
> if (rc != SCSI_RETURN_NOT_HANDLED)
> return rc;
> /* handler does not care. Drop down to default handling */
> + } else if (scsi_device_alua_implicit(sdev)) {
> + enum scsi_disposition rc;
> +
> + rc = scsi_alua_check_sense(sdev, &sshdr);
> + if (rc != SCSI_RETURN_NOT_HANDLED)
> + return rc;
> }
>
> if (scmd->cmnd[0] == TEST_UNIT_READY &&
> diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
> index d3a8cd4166f92..e5bcee555ea10 100644
> --- a/drivers/scsi/scsi_lib.c
> +++ b/drivers/scsi/scsi_lib.c
> @@ -26,6 +26,7 @@
> #include <linux/unaligned.h>
>
> #include <scsi/scsi.h>
> +#include <scsi/scsi_alua.h>
> #include <scsi/scsi_cmnd.h>
> #include <scsi/scsi_dbg.h>
> #include <scsi/scsi_device.h>
> @@ -1719,6 +1720,12 @@ static blk_status_t scsi_prepare_cmd(struct request *req)
> if (sdev->handler && sdev->handler->prep_fn) {
> blk_status_t ret = sdev->handler->prep_fn(sdev, req);
>
> + if (ret != BLK_STS_OK)
> + return ret;
> + } else if (scsi_device_alua_implicit(sdev)) {
> + /* We should be able to make this common for ALUA DH as well */
> + blk_status_t ret = scsi_alua_prep_fn(sdev, req);
> +
> if (ret != BLK_STS_OK)
> return ret;
> }
> diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
> index 3af64d1231445..73caf83bd1097 100644
> --- a/drivers/scsi/scsi_scan.c
> +++ b/drivers/scsi/scsi_scan.c
> @@ -1744,6 +1744,8 @@ int scsi_rescan_device(struct scsi_device *sdev)
>
> if (sdev->handler && sdev->handler->rescan)
> sdev->handler->rescan(sdev);
> + else if (scsi_device_alua_implicit(sdev))
> + scsi_device_alua_rescan(sdev);
>
> if (dev->driver && try_module_get(dev->driver->owner)) {
> struct scsi_driver *drv = to_scsi_driver(dev->driver);
> diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
> index 6c4c3c22f6acf..71a9613898cfc 100644
> --- a/drivers/scsi/scsi_sysfs.c
> +++ b/drivers/scsi/scsi_sysfs.c
> @@ -1152,7 +1152,7 @@ sdev_show_access_state(struct device *dev,
> unsigned char access_state;
> const char *access_state_name;
>
> - if (!sdev->handler)
> + if (!sdev->handler && !scsi_device_alua_implicit(sdev))
> return -EINVAL;
>
> access_state = (sdev->access_state & SCSI_ACCESS_STATE_MASK);
> @@ -1409,6 +1409,8 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
> scsi_autopm_get_device(sdev);
>
> scsi_dh_add_device(sdev);
> + if (!sdev->handler && scsi_device_alua_implicit(sdev))
> + scsi_device_alua_rescan(sdev);
>
> error = device_add(&sdev->sdev_gendev);
> if (error) {
> diff --git a/include/scsi/scsi_alua.h b/include/scsi/scsi_alua.h
> index 2d5db944f75b7..8e506d1d66cce 100644
> --- a/include/scsi/scsi_alua.h
> +++ b/include/scsi/scsi_alua.h
> @@ -24,6 +24,7 @@ struct alua_data {
> unsigned char transition_tmo;
> unsigned long expiry;
> unsigned long interval;
> + struct delayed_work work;
> struct scsi_device *sdev;
> spinlock_t lock;
> };
> @@ -35,11 +36,15 @@ void scsi_alua_handle_state_transition(struct scsi_device *sdev);
>
> int scsi_alua_check_tpgs(struct scsi_device *sdev);
>
> +enum scsi_disposition scsi_alua_check_sense(struct scsi_device *sdev,
> + struct scsi_sense_hdr *sense_hdr);
> +
> int scsi_alua_rtpg_run(struct scsi_device *sdev);
> int scsi_alua_stpg_run(struct scsi_device *sdev, bool optimize);
>
> blk_status_t scsi_alua_prep_fn(struct scsi_device *sdev, struct request *req);
>
> +void scsi_device_alua_rescan(struct scsi_device *sdev);
> bool scsi_device_alua_implicit(struct scsi_device *sdev);
>
> int scsi_alua_init(void);
> @@ -53,6 +58,12 @@ static inline int scsi_alua_check_tpgs(struct scsi_device *sdev)
> {
> return 0;
> }
> +static inline
> +enum scsi_disposition scsi_alua_check_sense(struct scsi_device *sdev,
> + struct scsi_sense_hdr *sense_hdr)
> +{
> + return SCSI_RETURN_NOT_HANDLED;
> +}
> static inline int scsi_alua_rtpg_run(struct scsi_device *sdev)
> {
> return 0;
> @@ -66,6 +77,9 @@ blk_status_t scsi_alua_prep_fn(struct scsi_device *sdev, struct request *req)
> {
> return BLK_STS_OK;
> }
> +static inline void scsi_device_alua_rescan(struct scsi_device *sdev)
> +{
> +}
> static inline bool scsi_device_alua_implicit(struct scsi_device *sdev)
> {
> return false;
> --
> 2.43.5
On 23/03/2026 01:58, Benjamin Marzinski wrote:
> On Tue, Mar 17, 2026 at 12:07:03PM +0000, John Garry wrote:
>> For when no device handler is used, add ALUA support.
>>
>> This will be equivalent to when native SCSI multipathing is used.
>>
>> Essentially all the same handling is available as DH alua driver for
>> rescan, request prep, sense handling.
>>
>> Signed-off-by: John Garry <john.g.garry@oracle.com>
>> ---
>> drivers/scsi/scsi_alua.c | 93 +++++++++++++++++++++++++++++++++++++++
>> drivers/scsi/scsi_error.c | 7 +++
>> drivers/scsi/scsi_lib.c | 7 +++
>> drivers/scsi/scsi_scan.c | 2 +
>> drivers/scsi/scsi_sysfs.c | 4 +-
>> include/scsi/scsi_alua.h | 14 ++++++
>> 6 files changed, 126 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/scsi/scsi_alua.c b/drivers/scsi/scsi_alua.c
>> index d3fcd887e5018..ee0229b1a9d12 100644
>> --- a/drivers/scsi/scsi_alua.c
>> +++ b/drivers/scsi/scsi_alua.c
>> @@ -562,6 +562,90 @@ int scsi_alua_stpg_run(struct scsi_device *sdev, bool optimize)
>> }
>> EXPORT_SYMBOL_GPL(scsi_alua_stpg_run);
>>
>> +enum scsi_disposition scsi_alua_check_sense(struct scsi_device *sdev,
>> + struct scsi_sense_hdr *sense_hdr)
>
> This seems like it should be shareable with scsi_dh_alua as well. In
> might need to take a function to call for rescanning and have
> alua_check_sense() be a wrapper around it, but since the force argument
> to alua_check() is now always set to true in scsi_dh_alua, it's
> unnecessary, so both it and scsi_device_alua_rescan() can have the
> same arguments.
Yeah, I tried it and I just thought that adding the rescan callback was
a bit messy. I can go with the single function if we think it's better.
>
>> +{
>> + switch (sense_hdr->sense_key) {
>> + case NOT_READY:
>> + if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
>> + /*
>> + * LUN Not Accessible - ALUA state transition
>> + */
>> + scsi_alua_handle_state_transition(sdev);
>> + return NEEDS_RETRY;
>> + }
>> + break;
>> + case UNIT_ATTENTION:
>> + if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
>> + /*
>> + * LUN Not Accessible - ALUA state transition
>> + */
>> + scsi_alua_handle_state_transition(sdev);
>> + return NEEDS_RETRY;
>> + }
>> + if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) {
>> + /*
>> + * Power On, Reset, or Bus Device Reset.
>> + * Might have obscured a state transition,
>> + * so schedule a recheck.
>> + */
>> + scsi_device_alua_rescan(sdev);
>> + return ADD_TO_MLQUEUE;
>> + }
>> + if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x04)
>> + /*
>> + * Device internal reset
>> + */
>> + return ADD_TO_MLQUEUE;
>> + if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x01)
>> + /*
>> + * Mode Parameters Changed
>> + */
>> + return ADD_TO_MLQUEUE;
>> + if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) {
>> + /*
>> + * ALUA state changed
>> + */
>> + scsi_device_alua_rescan(sdev);
>> + return ADD_TO_MLQUEUE;
>> + }
>> + if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) {
>> + /*
>> + * Implicit ALUA state transition failed
>> + */
>> + scsi_device_alua_rescan(sdev);
>> + return ADD_TO_MLQUEUE;
>> + }
>> + if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x03)
>> + /*
>> + * Inquiry data has changed
>> + */
>> + return ADD_TO_MLQUEUE;
>> + if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x0e)
>> + /*
>> + * REPORTED_LUNS_DATA_HAS_CHANGED is reported
>> + * when switching controllers on targets like
>> + * Intel Multi-Flex. We can just retry.
>> + */
>> + return ADD_TO_MLQUEUE;
>> + break;
>> + }
>> +
>> + return SCSI_RETURN_NOT_HANDLED;
>> +}
>> +
>> +static void alua_rtpg_work(struct work_struct *work)
>> +{
>> + struct alua_data *alua =
>> + container_of(work, struct alua_data, work.work);
>> + int ret;
>> +
>> + ret = scsi_alua_rtpg_run(alua->sdev);
>> +
>> + if (ret == -EAGAIN)
>> + queue_delayed_work(kalua_wq, &alua->work, alua->interval * HZ);
>> +}
>> +
>> int scsi_alua_sdev_init(struct scsi_device *sdev)
>> {
>> int rel_port, ret, tpgs;
>> @@ -591,6 +675,7 @@ int scsi_alua_sdev_init(struct scsi_device *sdev)
>> goto out_free_data;
>> }
>>
>> + INIT_DELAYED_WORK(&sdev->alua->work, alua_rtpg_work);
>> sdev->alua->sdev = sdev;
>> sdev->alua->tpgs = tpgs;
>> spin_lock_init(&sdev->alua->lock);
>> @@ -638,6 +723,14 @@ bool scsi_device_alua_implicit(struct scsi_device *sdev)
>> return sdev->alua->tpgs & TPGS_MODE_IMPLICIT;
>> }
>>
>> +void scsi_device_alua_rescan(struct scsi_device *sdev)
>> +{
>> + struct alua_data *alua = sdev->alua;
>> +
>> + queue_delayed_work(kalua_wq, &alua->work,
>> + msecs_to_jiffies(ALUA_RTPG_DELAY_MSECS));
>
> This code doesn't support triggering a new rtpg while the current one is
> running. I'll leave it to people with more scsi expertise to say how
> important that is, but the scsi_dh_alua code now will always trigger a
> new rtpg in this case (or at least it would, with the issues from patch
> 12 fixed).
>
If the work is running and we call queue_delayed_work() on the same
work_struct, then it is enqueued again. If the work is pending and we
call queue_delayed_work(), then it is not requeued (as it is already
queued).
Thanks,
John
On Mon, Mar 23, 2026 at 12:52:18PM +0000, John Garry wrote:
> On 23/03/2026 01:58, Benjamin Marzinski wrote:
> > On Tue, Mar 17, 2026 at 12:07:03PM +0000, John Garry wrote:
> > > For when no device handler is used, add ALUA support.
> > >
> > > This will be equivalent to when native SCSI multipathing is used.
> > >
> > > Essentially all the same handling is available as DH alua driver for
> > > rescan, request prep, sense handling.
> > >
> > > Signed-off-by: John Garry <john.g.garry@oracle.com>
> > > ---
> > > drivers/scsi/scsi_alua.c | 93 +++++++++++++++++++++++++++++++++++++++
> > > drivers/scsi/scsi_error.c | 7 +++
> > > drivers/scsi/scsi_lib.c | 7 +++
> > > drivers/scsi/scsi_scan.c | 2 +
> > > drivers/scsi/scsi_sysfs.c | 4 +-
> > > include/scsi/scsi_alua.h | 14 ++++++
> > > 6 files changed, 126 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/scsi/scsi_alua.c b/drivers/scsi/scsi_alua.c
> > > index d3fcd887e5018..ee0229b1a9d12 100644
> > > --- a/drivers/scsi/scsi_alua.c
> > > +++ b/drivers/scsi/scsi_alua.c
> > > @@ -562,6 +562,90 @@ int scsi_alua_stpg_run(struct scsi_device *sdev, bool optimize)
> > > }
> > > EXPORT_SYMBOL_GPL(scsi_alua_stpg_run);
> > > +enum scsi_disposition scsi_alua_check_sense(struct scsi_device *sdev,
> > > + struct scsi_sense_hdr *sense_hdr)
> >
> > This seems like it should be shareable with scsi_dh_alua as well. In
> > might need to take a function to call for rescanning and have
> > alua_check_sense() be a wrapper around it, but since the force argument
> > to alua_check() is now always set to true in scsi_dh_alua, it's
> > unnecessary, so both it and scsi_device_alua_rescan() can have the
> > same arguments.
>
> Yeah, I tried it and I just thought that adding the rescan callback was a
> bit messy. I can go with the single function if we think it's better.
I would defer to the opinion of an acutal SCSI maintainer (which I am
not) on this.
>
> >
> > > +{
> > > + switch (sense_hdr->sense_key) {
> > > + case NOT_READY:
> > > + if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
> > > + /*
> > > + * LUN Not Accessible - ALUA state transition
> > > + */
> > > + scsi_alua_handle_state_transition(sdev);
> > > + return NEEDS_RETRY;
> > > + }
> > > + break;
> > > + case UNIT_ATTENTION:
> > > + if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
> > > + /*
> > > + * LUN Not Accessible - ALUA state transition
> > > + */
> > > + scsi_alua_handle_state_transition(sdev);
> > > + return NEEDS_RETRY;
> > > + }
> > > + if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) {
> > > + /*
> > > + * Power On, Reset, or Bus Device Reset.
> > > + * Might have obscured a state transition,
> > > + * so schedule a recheck.
> > > + */
> > > + scsi_device_alua_rescan(sdev);
> > > + return ADD_TO_MLQUEUE;
> > > + }
> > > + if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x04)
> > > + /*
> > > + * Device internal reset
> > > + */
> > > + return ADD_TO_MLQUEUE;
> > > + if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x01)
> > > + /*
> > > + * Mode Parameters Changed
> > > + */
> > > + return ADD_TO_MLQUEUE;
> > > + if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) {
> > > + /*
> > > + * ALUA state changed
> > > + */
> > > + scsi_device_alua_rescan(sdev);
> > > + return ADD_TO_MLQUEUE;
> > > + }
> > > + if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) {
> > > + /*
> > > + * Implicit ALUA state transition failed
> > > + */
> > > + scsi_device_alua_rescan(sdev);
> > > + return ADD_TO_MLQUEUE;
> > > + }
> > > + if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x03)
> > > + /*
> > > + * Inquiry data has changed
> > > + */
> > > + return ADD_TO_MLQUEUE;
> > > + if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x0e)
> > > + /*
> > > + * REPORTED_LUNS_DATA_HAS_CHANGED is reported
> > > + * when switching controllers on targets like
> > > + * Intel Multi-Flex. We can just retry.
> > > + */
> > > + return ADD_TO_MLQUEUE;
> > > + break;
> > > + }
> > > +
> > > + return SCSI_RETURN_NOT_HANDLED;
> > > +}
> > > +
> > > +static void alua_rtpg_work(struct work_struct *work)
> > > +{
> > > + struct alua_data *alua =
> > > + container_of(work, struct alua_data, work.work);
> > > + int ret;
> > > +
> > > + ret = scsi_alua_rtpg_run(alua->sdev);
> > > +
> > > + if (ret == -EAGAIN)
> > > + queue_delayed_work(kalua_wq, &alua->work, alua->interval * HZ);
> > > +}
> > > +
> > > int scsi_alua_sdev_init(struct scsi_device *sdev)
> > > {
> > > int rel_port, ret, tpgs;
> > > @@ -591,6 +675,7 @@ int scsi_alua_sdev_init(struct scsi_device *sdev)
> > > goto out_free_data;
> > > }
> > > + INIT_DELAYED_WORK(&sdev->alua->work, alua_rtpg_work);
> > > sdev->alua->sdev = sdev;
> > > sdev->alua->tpgs = tpgs;
> > > spin_lock_init(&sdev->alua->lock);
> > > @@ -638,6 +723,14 @@ bool scsi_device_alua_implicit(struct scsi_device *sdev)
> > > return sdev->alua->tpgs & TPGS_MODE_IMPLICIT;
> > > }
> > > +void scsi_device_alua_rescan(struct scsi_device *sdev)
> > > +{
> > > + struct alua_data *alua = sdev->alua;
> > > +
> > > + queue_delayed_work(kalua_wq, &alua->work,
> > > + msecs_to_jiffies(ALUA_RTPG_DELAY_MSECS));
> >
> > This code doesn't support triggering a new rtpg while the current one is
> > running. I'll leave it to people with more scsi expertise to say how
> > important that is, but the scsi_dh_alua code now will always trigger a
> > new rtpg in this case (or at least it would, with the issues from patch
> > 12 fixed).
> >
>
> If the work is running and we call queue_delayed_work() on the same
> work_struct, then it is enqueued again. If the work is pending and we call
> queue_delayed_work(), then it is not requeued (as it is already queued).
Oops. You're correct.
-Ben
> Thanks,
> John
On 23/03/2026 17:29, Benjamin Marzinski wrote: >> Yeah, I tried it and I just thought that adding the rescan callback was a >> bit messy. I can go with the single function if we think it's better. > I would defer to the opinion of an acutal SCSI maintainer (which I am > not) on this. I'll check for a better way to factor out this code so that it does not need to be duplicated. Thanks, John
Hi John, kernel test robot noticed the following build errors: [auto build test ERROR on mkp-scsi/for-next] [also build test ERROR on jejb-scsi/for-next linus/master v7.0-rc4 next-20260318] [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/John-Garry/scsi-scsi_dh_alua-Delete-alua_port_group/20260318-105207 base: https://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git for-next patch link: https://lore.kernel.org/r/20260317120703.3702387-14-john.g.garry%40oracle.com patch subject: [PATCH 13/13] scsi: core: Add implicit ALUA support config: s390-randconfig-001-20260318 (https://download.01.org/0day-ci/archive/20260319/202603190739.QIFfPfdg-lkp@intel.com/config) compiler: s390-linux-gcc (GCC) 11.5.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260319/202603190739.QIFfPfdg-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/202603190739.QIFfPfdg-lkp@intel.com/ All errors (new ones prefixed by >>, old ones prefixed by <<): >> ERROR: modpost: "scsi_device_alua_rescan" [drivers/scsi/scsi_mod.ko] undefined! >> ERROR: modpost: "scsi_alua_check_sense" [drivers/scsi/scsi_mod.ko] undefined! ERROR: modpost: "scsi_exit_alua" [drivers/scsi/scsi_mod.ko] undefined! ERROR: modpost: "scsi_alua_init" [drivers/scsi/scsi_mod.ko] undefined! ERROR: modpost: "scsi_alua_sdev_exit" [drivers/scsi/scsi_mod.ko] undefined! ERROR: modpost: "scsi_alua_sdev_init" [drivers/scsi/scsi_mod.ko] undefined! >> ERROR: modpost: "scsi_device_alua_implicit" [drivers/scsi/scsi_mod.ko] undefined! -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
On 3/17/26 13:07, John Garry wrote:
> For when no device handler is used, add ALUA support.
>
> This will be equivalent to when native SCSI multipathing is used.
>
> Essentially all the same handling is available as DH alua driver for
> rescan, request prep, sense handling.
>
> Signed-off-by: John Garry <john.g.garry@oracle.com>
> ---
> drivers/scsi/scsi_alua.c | 93 +++++++++++++++++++++++++++++++++++++++
> drivers/scsi/scsi_error.c | 7 +++
> drivers/scsi/scsi_lib.c | 7 +++
> drivers/scsi/scsi_scan.c | 2 +
> drivers/scsi/scsi_sysfs.c | 4 +-
> include/scsi/scsi_alua.h | 14 ++++++
> 6 files changed, 126 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/scsi/scsi_alua.c b/drivers/scsi/scsi_alua.c
> index d3fcd887e5018..ee0229b1a9d12 100644
> --- a/drivers/scsi/scsi_alua.c
> +++ b/drivers/scsi/scsi_alua.c
> @@ -562,6 +562,90 @@ int scsi_alua_stpg_run(struct scsi_device *sdev, bool optimize)
> }
> EXPORT_SYMBOL_GPL(scsi_alua_stpg_run);
>
> +enum scsi_disposition scsi_alua_check_sense(struct scsi_device *sdev,
> + struct scsi_sense_hdr *sense_hdr)
> +{
> + switch (sense_hdr->sense_key) {
> + case NOT_READY:
> + if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
> + /*
> + * LUN Not Accessible - ALUA state transition
> + */
> + scsi_alua_handle_state_transition(sdev);
> + return NEEDS_RETRY;
> + }
> + break;
> + case UNIT_ATTENTION:
> + if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
> + /*
> + * LUN Not Accessible - ALUA state transition
> + */
> + scsi_alua_handle_state_transition(sdev);
> + return NEEDS_RETRY;
> + }
> + if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) {
> + /*
> + * Power On, Reset, or Bus Device Reset.
> + * Might have obscured a state transition,
> + * so schedule a recheck.
> + */
> + scsi_device_alua_rescan(sdev);
> + return ADD_TO_MLQUEUE;
> + }
> + if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x04)
> + /*
> + * Device internal reset
> + */
> + return ADD_TO_MLQUEUE;
> + if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x01)
> + /*
> + * Mode Parameters Changed
> + */
> + return ADD_TO_MLQUEUE;
> + if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) {
> + /*
> + * ALUA state changed
> + */
> + scsi_device_alua_rescan(sdev);
> + return ADD_TO_MLQUEUE;
> + }
> + if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) {
> + /*
> + * Implicit ALUA state transition failed
> + */
> + scsi_device_alua_rescan(sdev);
> + return ADD_TO_MLQUEUE;
> + }
> + if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x03)
> + /*
> + * Inquiry data has changed
> + */
> + return ADD_TO_MLQUEUE;
> + if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x0e)
> + /*
> + * REPORTED_LUNS_DATA_HAS_CHANGED is reported
> + * when switching controllers on targets like
> + * Intel Multi-Flex. We can just retry.
> + */
> + return ADD_TO_MLQUEUE;
> + break;
> + }
> +
> + return SCSI_RETURN_NOT_HANDLED;
> +}
> +
> +static void alua_rtpg_work(struct work_struct *work)
> +{
> + struct alua_data *alua =
> + container_of(work, struct alua_data, work.work);
> + int ret;
> +
> + ret = scsi_alua_rtpg_run(alua->sdev);
> +
> + if (ret == -EAGAIN)
> + queue_delayed_work(kalua_wq, &alua->work, alua->interval * HZ);
> +}
> +
> int scsi_alua_sdev_init(struct scsi_device *sdev)
> {
> int rel_port, ret, tpgs;
> @@ -591,6 +675,7 @@ int scsi_alua_sdev_init(struct scsi_device *sdev)
> goto out_free_data;
> }
>
> + INIT_DELAYED_WORK(&sdev->alua->work, alua_rtpg_work);
> sdev->alua->sdev = sdev;
> sdev->alua->tpgs = tpgs;
> spin_lock_init(&sdev->alua->lock);
> @@ -638,6 +723,14 @@ bool scsi_device_alua_implicit(struct scsi_device *sdev)
> return sdev->alua->tpgs & TPGS_MODE_IMPLICIT;
> }
>
> +void scsi_device_alua_rescan(struct scsi_device *sdev)
> +{
> + struct alua_data *alua = sdev->alua;
> +
> + queue_delayed_work(kalua_wq, &alua->work,
> + msecs_to_jiffies(ALUA_RTPG_DELAY_MSECS));
> +}
> +
> int scsi_alua_init(void)
> {
> kalua_wq = alloc_workqueue("kalua", WQ_MEM_RECLAIM | WQ_PERCPU, 0);
> diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
> index 147127fb4db9c..a542e7a85a24d 100644
> --- a/drivers/scsi/scsi_error.c
> +++ b/drivers/scsi/scsi_error.c
> @@ -29,6 +29,7 @@
> #include <linux/jiffies.h>
>
> #include <scsi/scsi.h>
> +#include <scsi/scsi_alua.h>
> #include <scsi/scsi_cmnd.h>
> #include <scsi/scsi_dbg.h>
> #include <scsi/scsi_device.h>
> @@ -578,6 +579,12 @@ enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd)
> if (rc != SCSI_RETURN_NOT_HANDLED)
> return rc;
> /* handler does not care. Drop down to default handling */
> + } else if (scsi_device_alua_implicit(sdev)) {
> + enum scsi_disposition rc;
> +
> + rc = scsi_alua_check_sense(sdev, &sshdr);
> + if (rc != SCSI_RETURN_NOT_HANDLED)
> + return rc;
> }
>
> if (scmd->cmnd[0] == TEST_UNIT_READY &&
> diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
> index d3a8cd4166f92..e5bcee555ea10 100644
> --- a/drivers/scsi/scsi_lib.c
> +++ b/drivers/scsi/scsi_lib.c
> @@ -26,6 +26,7 @@
> #include <linux/unaligned.h>
>
> #include <scsi/scsi.h>
> +#include <scsi/scsi_alua.h>
> #include <scsi/scsi_cmnd.h>
> #include <scsi/scsi_dbg.h>
> #include <scsi/scsi_device.h>
> @@ -1719,6 +1720,12 @@ static blk_status_t scsi_prepare_cmd(struct request *req)
> if (sdev->handler && sdev->handler->prep_fn) {
> blk_status_t ret = sdev->handler->prep_fn(sdev, req);
>
> + if (ret != BLK_STS_OK)
> + return ret;
> + } else if (scsi_device_alua_implicit(sdev)) {
> + /* We should be able to make this common for ALUA DH as well */
> + blk_status_t ret = scsi_alua_prep_fn(sdev, req);
> +
> if (ret != BLK_STS_OK)
> return ret;
> }
> diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
> index 3af64d1231445..73caf83bd1097 100644
> --- a/drivers/scsi/scsi_scan.c
> +++ b/drivers/scsi/scsi_scan.c
> @@ -1744,6 +1744,8 @@ int scsi_rescan_device(struct scsi_device *sdev)
>
> if (sdev->handler && sdev->handler->rescan)
> sdev->handler->rescan(sdev);
> + else if (scsi_device_alua_implicit(sdev))
> + scsi_device_alua_rescan(sdev);
>
> if (dev->driver && try_module_get(dev->driver->owner)) {
> struct scsi_driver *drv = to_scsi_driver(dev->driver);
> diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
> index 6c4c3c22f6acf..71a9613898cfc 100644
> --- a/drivers/scsi/scsi_sysfs.c
> +++ b/drivers/scsi/scsi_sysfs.c
> @@ -1152,7 +1152,7 @@ sdev_show_access_state(struct device *dev,
> unsigned char access_state;
> const char *access_state_name;
>
> - if (!sdev->handler)
> + if (!sdev->handler && !scsi_device_alua_implicit(sdev))
> return -EINVAL;
>
> access_state = (sdev->access_state & SCSI_ACCESS_STATE_MASK);
> @@ -1409,6 +1409,8 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
> scsi_autopm_get_device(sdev);
>
> scsi_dh_add_device(sdev);
> + if (!sdev->handler && scsi_device_alua_implicit(sdev))
> + scsi_device_alua_rescan(sdev);
>
> error = device_add(&sdev->sdev_gendev);
> if (error) {
> diff --git a/include/scsi/scsi_alua.h b/include/scsi/scsi_alua.h
> index 2d5db944f75b7..8e506d1d66cce 100644
> --- a/include/scsi/scsi_alua.h
> +++ b/include/scsi/scsi_alua.h
> @@ -24,6 +24,7 @@ struct alua_data {
> unsigned char transition_tmo;
> unsigned long expiry;
> unsigned long interval;
> + struct delayed_work work;
> struct scsi_device *sdev;
> spinlock_t lock;
> };
> @@ -35,11 +36,15 @@ void scsi_alua_handle_state_transition(struct scsi_device *sdev);
>
> int scsi_alua_check_tpgs(struct scsi_device *sdev);
>
> +enum scsi_disposition scsi_alua_check_sense(struct scsi_device *sdev,
> + struct scsi_sense_hdr *sense_hdr);
> +
> int scsi_alua_rtpg_run(struct scsi_device *sdev);
> int scsi_alua_stpg_run(struct scsi_device *sdev, bool optimize);
>
> blk_status_t scsi_alua_prep_fn(struct scsi_device *sdev, struct request *req);
>
> +void scsi_device_alua_rescan(struct scsi_device *sdev);
> bool scsi_device_alua_implicit(struct scsi_device *sdev);
>
> int scsi_alua_init(void);
> @@ -53,6 +58,12 @@ static inline int scsi_alua_check_tpgs(struct scsi_device *sdev)
> {
> return 0;
> }
> +static inline
> +enum scsi_disposition scsi_alua_check_sense(struct scsi_device *sdev,
> + struct scsi_sense_hdr *sense_hdr)
> +{
> + return SCSI_RETURN_NOT_HANDLED;
> +}
> static inline int scsi_alua_rtpg_run(struct scsi_device *sdev)
> {
> return 0;
> @@ -66,6 +77,9 @@ blk_status_t scsi_alua_prep_fn(struct scsi_device *sdev, struct request *req)
> {
> return BLK_STS_OK;
> }
> +static inline void scsi_device_alua_rescan(struct scsi_device *sdev)
> +{
> +}
> static inline bool scsi_device_alua_implicit(struct scsi_device *sdev)
> {
> return false;
... and this justifies what I mentioned with the previous two patches.
Please fold the patch for scsi_device_alua_implicit() into this, and
open-code the prep_fn such that we know what's going on.
The ALUA state machine might be challenging, though.
The scsi_dh_alua driver had this as a workqueue, as it was the only way
how we could execute several calls consecutively.
I'm not utterly convinced that we need have the very same functionality
in the scsi core, but for simplicity let's keep it.
But: we only should keep the 'retry RTPG' logic in the scsi core;
sending STPG should be delegated to scsi_dh_alua.
So you need to adjust scsi_dh_alua for that, too, and cannot just
lift the existing functions into the scsi core.
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
© 2016 - 2026 Red Hat, Inc.