mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
s390/dasd: add autoquiesce feature
Add the internal logic to check for autoquiesce triggers and handle them. Quiesce and resume are functions that tell Linux to stop/resume issuing I/Os to a specific DASD. The DASD driver allows a manual quiesce/resume via ioctl. Autoquiesce will define an amount of triggers that will lead to an automatic quiesce if a certain event occurs. There is no automatic resume. All events will be reported via DASD Extended Error Reporting (EER) if configured. Signed-off-by: Stefan Haberland <sth@linux.ibm.com> Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com> Reviewed-by: Halil Pasic <pasic@linux.ibm.com> Link: https://lore.kernel.org/r/20230405142017.2446986-3-sth@linux.ibm.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
861d53dbed
commit
1cee2975bb
@ -78,6 +78,7 @@ typedef struct dasd_information2_t {
|
||||
* 0x040: give access to raw eckd data
|
||||
* 0x080: enable discard support
|
||||
* 0x100: enable autodisable for IFCC errors (default)
|
||||
* 0x200: enable requeue of all requests on autoquiesce
|
||||
*/
|
||||
#define DASD_FEATURE_READONLY 0x001
|
||||
#define DASD_FEATURE_USEDIAG 0x002
|
||||
@ -88,6 +89,7 @@ typedef struct dasd_information2_t {
|
||||
#define DASD_FEATURE_USERAW 0x040
|
||||
#define DASD_FEATURE_DISCARD 0x080
|
||||
#define DASD_FEATURE_PATH_AUTODISABLE 0x100
|
||||
#define DASD_FEATURE_REQUEUEQUIESCE 0x200
|
||||
#define DASD_FEATURE_DEFAULT DASD_FEATURE_PATH_AUTODISABLE
|
||||
|
||||
#define DASD_PARTN_BITS 2
|
||||
|
@ -73,7 +73,8 @@ static void dasd_profile_init(struct dasd_profile *, struct dentry *);
|
||||
static void dasd_profile_exit(struct dasd_profile *);
|
||||
static void dasd_hosts_init(struct dentry *, struct dasd_device *);
|
||||
static void dasd_hosts_exit(struct dasd_device *);
|
||||
|
||||
static int dasd_handle_autoquiesce(struct dasd_device *, struct dasd_ccw_req *,
|
||||
unsigned int);
|
||||
/*
|
||||
* SECTION: Operations on the device structure.
|
||||
*/
|
||||
@ -2325,7 +2326,7 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible)
|
||||
/* Non-temporary stop condition will trigger fail fast */
|
||||
if (device->stopped & ~DASD_STOPPED_PENDING &&
|
||||
test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
|
||||
(!dasd_eer_enabled(device))) {
|
||||
!dasd_eer_enabled(device) && device->aq_mask == 0) {
|
||||
cqr->status = DASD_CQR_FAILED;
|
||||
cqr->intrc = -ENOLINK;
|
||||
continue;
|
||||
@ -2801,20 +2802,18 @@ restart:
|
||||
dasd_log_sense(cqr, &cqr->irb);
|
||||
}
|
||||
|
||||
/* First of all call extended error reporting. */
|
||||
if (dasd_eer_enabled(base) &&
|
||||
cqr->status == DASD_CQR_FAILED) {
|
||||
dasd_eer_write(base, cqr, DASD_EER_FATALERROR);
|
||||
|
||||
/* restart request */
|
||||
/*
|
||||
* First call extended error reporting and check for autoquiesce
|
||||
*/
|
||||
spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
|
||||
if (cqr->status == DASD_CQR_FAILED &&
|
||||
dasd_handle_autoquiesce(base, cqr, DASD_EER_FATALERROR)) {
|
||||
cqr->status = DASD_CQR_FILLED;
|
||||
cqr->retries = 255;
|
||||
spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
|
||||
dasd_device_set_stop_bits(base, DASD_STOPPED_QUIESCE);
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(base->cdev),
|
||||
flags);
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
|
||||
goto restart;
|
||||
}
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
|
||||
|
||||
/* Process finished ERP request. */
|
||||
if (cqr->refers) {
|
||||
@ -2856,7 +2855,7 @@ static void __dasd_block_start_head(struct dasd_block *block)
|
||||
/* Non-temporary stop condition will trigger fail fast */
|
||||
if (block->base->stopped & ~DASD_STOPPED_PENDING &&
|
||||
test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
|
||||
(!dasd_eer_enabled(block->base))) {
|
||||
!dasd_eer_enabled(block->base) && block->base->aq_mask == 0) {
|
||||
cqr->status = DASD_CQR_FAILED;
|
||||
cqr->intrc = -ENOLINK;
|
||||
dasd_schedule_block_bh(block);
|
||||
@ -3670,8 +3669,8 @@ int dasd_generic_last_path_gone(struct dasd_device *device)
|
||||
dev_warn(&device->cdev->dev, "No operational channel path is left "
|
||||
"for the device\n");
|
||||
DBF_DEV_EVENT(DBF_WARNING, device, "%s", "last path gone");
|
||||
/* First of all call extended error reporting. */
|
||||
dasd_eer_write(device, NULL, DASD_EER_NOPATH);
|
||||
/* First call extended error reporting and check for autoquiesce. */
|
||||
dasd_handle_autoquiesce(device, NULL, DASD_EER_NOPATH);
|
||||
|
||||
if (device->state < DASD_STATE_BASIC)
|
||||
return 0;
|
||||
@ -3803,7 +3802,8 @@ void dasd_generic_path_event(struct ccw_device *cdev, int *path_event)
|
||||
"No verified channel paths remain for the device\n");
|
||||
DBF_DEV_EVENT(DBF_WARNING, device,
|
||||
"%s", "last verified path gone");
|
||||
dasd_eer_write(device, NULL, DASD_EER_NOPATH);
|
||||
/* First call extended error reporting and check for autoquiesce. */
|
||||
dasd_handle_autoquiesce(device, NULL, DASD_EER_NOPATH);
|
||||
dasd_device_set_stop_bits(device,
|
||||
DASD_STOPPED_DC_WAIT);
|
||||
}
|
||||
@ -3825,7 +3825,8 @@ EXPORT_SYMBOL_GPL(dasd_generic_verify_path);
|
||||
void dasd_generic_space_exhaust(struct dasd_device *device,
|
||||
struct dasd_ccw_req *cqr)
|
||||
{
|
||||
dasd_eer_write(device, NULL, DASD_EER_NOSPC);
|
||||
/* First call extended error reporting and check for autoquiesce. */
|
||||
dasd_handle_autoquiesce(device, NULL, DASD_EER_NOSPC);
|
||||
|
||||
if (device->state < DASD_STATE_BASIC)
|
||||
return;
|
||||
@ -3958,6 +3959,31 @@ void dasd_schedule_requeue(struct dasd_device *device)
|
||||
}
|
||||
EXPORT_SYMBOL(dasd_schedule_requeue);
|
||||
|
||||
static int dasd_handle_autoquiesce(struct dasd_device *device,
|
||||
struct dasd_ccw_req *cqr,
|
||||
unsigned int reason)
|
||||
{
|
||||
/* in any case write eer message with reason */
|
||||
if (dasd_eer_enabled(device))
|
||||
dasd_eer_write(device, cqr, reason);
|
||||
|
||||
if (!test_bit(reason, &device->aq_mask))
|
||||
return 0;
|
||||
|
||||
/* notify eer about autoquiesce */
|
||||
if (dasd_eer_enabled(device))
|
||||
dasd_eer_write(device, NULL, DASD_EER_AUTOQUIESCE);
|
||||
|
||||
pr_info("%s: The DASD has been put in the quiesce state\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
dasd_device_set_stop_bits(device, DASD_STOPPED_QUIESCE);
|
||||
|
||||
if (device->features & DASD_FEATURE_REQUEUEQUIESCE)
|
||||
dasd_schedule_requeue(device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
|
||||
int rdc_buffer_size,
|
||||
int magic)
|
||||
|
@ -387,6 +387,7 @@ void dasd_eer_write(struct dasd_device *device, struct dasd_ccw_req *cqr,
|
||||
break;
|
||||
case DASD_EER_NOPATH:
|
||||
case DASD_EER_NOSPC:
|
||||
case DASD_EER_AUTOQUIESCE:
|
||||
dasd_eer_write_standard_trigger(device, NULL, id);
|
||||
break;
|
||||
case DASD_EER_STATECHANGE:
|
||||
|
@ -450,6 +450,7 @@ extern struct dasd_discipline *dasd_diag_discipline_pointer;
|
||||
#define DASD_EER_STATECHANGE 3
|
||||
#define DASD_EER_PPRCSUSPEND 4
|
||||
#define DASD_EER_NOSPC 5
|
||||
#define DASD_EER_AUTOQUIESCE 31
|
||||
|
||||
/* DASD path handling */
|
||||
|
||||
@ -627,6 +628,7 @@ struct dasd_device {
|
||||
struct dasd_format_entry format_entry;
|
||||
struct kset *paths_info;
|
||||
struct dasd_copy_relation *copy;
|
||||
unsigned long aq_mask;
|
||||
};
|
||||
|
||||
struct dasd_block {
|
||||
|
Loading…
Reference in New Issue
Block a user