Commit 883120eb authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
  [S390] dasd: revalidate server for new pathgroup
  [S390] dasd: revert LCU optimization
  [S390] cleanup entry point definition
parents f07d4a76 f1633031
...@@ -88,7 +88,6 @@ KBUILD_CFLAGS += -pipe -fno-strength-reduce -Wno-sign-compare ...@@ -88,7 +88,6 @@ KBUILD_CFLAGS += -pipe -fno-strength-reduce -Wno-sign-compare
KBUILD_AFLAGS += $(aflags-y) KBUILD_AFLAGS += $(aflags-y)
OBJCOPYFLAGS := -O binary OBJCOPYFLAGS := -O binary
LDFLAGS_vmlinux := -e start
head-y := arch/s390/kernel/head.o head-y := arch/s390/kernel/head.o
head-y += arch/s390/kernel/$(if $(CONFIG_64BIT),head64.o,head31.o) head-y += arch/s390/kernel/$(if $(CONFIG_64BIT),head64.o,head31.o)
......
...@@ -9,12 +9,12 @@ ...@@ -9,12 +9,12 @@
#ifndef CONFIG_64BIT #ifndef CONFIG_64BIT
OUTPUT_FORMAT("elf32-s390", "elf32-s390", "elf32-s390") OUTPUT_FORMAT("elf32-s390", "elf32-s390", "elf32-s390")
OUTPUT_ARCH(s390) OUTPUT_ARCH(s390)
ENTRY(_start) ENTRY(startup)
jiffies = jiffies_64 + 4; jiffies = jiffies_64 + 4;
#else #else
OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390") OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390")
OUTPUT_ARCH(s390:64-bit) OUTPUT_ARCH(s390:64-bit)
ENTRY(_start) ENTRY(startup)
jiffies = jiffies_64; jiffies = jiffies_64;
#endif #endif
......
...@@ -3261,6 +3261,12 @@ void dasd_generic_path_event(struct ccw_device *cdev, int *path_event) ...@@ -3261,6 +3261,12 @@ void dasd_generic_path_event(struct ccw_device *cdev, int *path_event)
device->path_data.tbvpm |= eventlpm; device->path_data.tbvpm |= eventlpm;
dasd_schedule_device_bh(device); dasd_schedule_device_bh(device);
} }
if (path_event[chp] & PE_PATHGROUP_ESTABLISHED) {
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
"Pathgroup re-established\n");
if (device->discipline->kick_validate)
device->discipline->kick_validate(device);
}
} }
dasd_put_device(device); dasd_put_device(device);
} }
......
...@@ -189,14 +189,12 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device) ...@@ -189,14 +189,12 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
unsigned long flags; unsigned long flags;
struct alias_server *server, *newserver; struct alias_server *server, *newserver;
struct alias_lcu *lcu, *newlcu; struct alias_lcu *lcu, *newlcu;
int is_lcu_known;
struct dasd_uid uid; struct dasd_uid uid;
private = (struct dasd_eckd_private *) device->private; private = (struct dasd_eckd_private *) device->private;
device->discipline->get_uid(device, &uid); device->discipline->get_uid(device, &uid);
spin_lock_irqsave(&aliastree.lock, flags); spin_lock_irqsave(&aliastree.lock, flags);
is_lcu_known = 1;
server = _find_server(&uid); server = _find_server(&uid);
if (!server) { if (!server) {
spin_unlock_irqrestore(&aliastree.lock, flags); spin_unlock_irqrestore(&aliastree.lock, flags);
...@@ -208,7 +206,6 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device) ...@@ -208,7 +206,6 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
if (!server) { if (!server) {
list_add(&newserver->server, &aliastree.serverlist); list_add(&newserver->server, &aliastree.serverlist);
server = newserver; server = newserver;
is_lcu_known = 0;
} else { } else {
/* someone was faster */ /* someone was faster */
_free_server(newserver); _free_server(newserver);
...@@ -226,12 +223,10 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device) ...@@ -226,12 +223,10 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
if (!lcu) { if (!lcu) {
list_add(&newlcu->lcu, &server->lculist); list_add(&newlcu->lcu, &server->lculist);
lcu = newlcu; lcu = newlcu;
is_lcu_known = 0;
} else { } else {
/* someone was faster */ /* someone was faster */
_free_lcu(newlcu); _free_lcu(newlcu);
} }
is_lcu_known = 0;
} }
spin_lock(&lcu->lock); spin_lock(&lcu->lock);
list_add(&device->alias_list, &lcu->inactive_devices); list_add(&device->alias_list, &lcu->inactive_devices);
...@@ -239,64 +234,7 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device) ...@@ -239,64 +234,7 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
spin_unlock(&lcu->lock); spin_unlock(&lcu->lock);
spin_unlock_irqrestore(&aliastree.lock, flags); spin_unlock_irqrestore(&aliastree.lock, flags);
return is_lcu_known; return 0;
}
/*
* The first device to be registered on an LCU will have to do
* some additional setup steps to configure that LCU on the
* storage server. All further devices should wait with their
* initialization until the first device is done.
* To synchronize this work, the first device will call
* dasd_alias_lcu_setup_complete when it is done, and all
* other devices will wait for it with dasd_alias_wait_for_lcu_setup.
*/
void dasd_alias_lcu_setup_complete(struct dasd_device *device)
{
unsigned long flags;
struct alias_server *server;
struct alias_lcu *lcu;
struct dasd_uid uid;
device->discipline->get_uid(device, &uid);
lcu = NULL;
spin_lock_irqsave(&aliastree.lock, flags);
server = _find_server(&uid);
if (server)
lcu = _find_lcu(server, &uid);
spin_unlock_irqrestore(&aliastree.lock, flags);
if (!lcu) {
DBF_EVENT_DEVID(DBF_ERR, device->cdev,
"could not find lcu for %04x %02x",
uid.ssid, uid.real_unit_addr);
WARN_ON(1);
return;
}
complete_all(&lcu->lcu_setup);
}
void dasd_alias_wait_for_lcu_setup(struct dasd_device *device)
{
unsigned long flags;
struct alias_server *server;
struct alias_lcu *lcu;
struct dasd_uid uid;
device->discipline->get_uid(device, &uid);
lcu = NULL;
spin_lock_irqsave(&aliastree.lock, flags);
server = _find_server(&uid);
if (server)
lcu = _find_lcu(server, &uid);
spin_unlock_irqrestore(&aliastree.lock, flags);
if (!lcu) {
DBF_EVENT_DEVID(DBF_ERR, device->cdev,
"could not find lcu for %04x %02x",
uid.ssid, uid.real_unit_addr);
WARN_ON(1);
return;
}
wait_for_completion(&lcu->lcu_setup);
} }
/* /*
......
...@@ -1534,6 +1534,10 @@ static void dasd_eckd_validate_server(struct dasd_device *device) ...@@ -1534,6 +1534,10 @@ static void dasd_eckd_validate_server(struct dasd_device *device)
struct dasd_eckd_private *private; struct dasd_eckd_private *private;
int enable_pav; int enable_pav;
private = (struct dasd_eckd_private *) device->private;
if (private->uid.type == UA_BASE_PAV_ALIAS ||
private->uid.type == UA_HYPER_PAV_ALIAS)
return;
if (dasd_nopav || MACHINE_IS_VM) if (dasd_nopav || MACHINE_IS_VM)
enable_pav = 0; enable_pav = 0;
else else
...@@ -1542,11 +1546,28 @@ static void dasd_eckd_validate_server(struct dasd_device *device) ...@@ -1542,11 +1546,28 @@ static void dasd_eckd_validate_server(struct dasd_device *device)
/* may be requested feature is not available on server, /* may be requested feature is not available on server,
* therefore just report error and go ahead */ * therefore just report error and go ahead */
private = (struct dasd_eckd_private *) device->private;
DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "PSF-SSC for SSID %04x " DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "PSF-SSC for SSID %04x "
"returned rc=%d", private->uid.ssid, rc); "returned rc=%d", private->uid.ssid, rc);
} }
/*
* worker to do a validate server in case of a lost pathgroup
*/
static void dasd_eckd_do_validate_server(struct work_struct *work)
{
struct dasd_device *device = container_of(work, struct dasd_device,
kick_validate);
dasd_eckd_validate_server(device);
dasd_put_device(device);
}
static void dasd_eckd_kick_validate_server(struct dasd_device *device)
{
dasd_get_device(device);
/* queue call to do_validate_server to the kernel event daemon. */
schedule_work(&device->kick_validate);
}
static u32 get_fcx_max_data(struct dasd_device *device) static u32 get_fcx_max_data(struct dasd_device *device)
{ {
#if defined(CONFIG_64BIT) #if defined(CONFIG_64BIT)
...@@ -1588,10 +1609,13 @@ dasd_eckd_check_characteristics(struct dasd_device *device) ...@@ -1588,10 +1609,13 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
struct dasd_eckd_private *private; struct dasd_eckd_private *private;
struct dasd_block *block; struct dasd_block *block;
struct dasd_uid temp_uid; struct dasd_uid temp_uid;
int is_known, rc, i; int rc, i;
int readonly; int readonly;
unsigned long value; unsigned long value;
/* setup work queue for validate server*/
INIT_WORK(&device->kick_validate, dasd_eckd_do_validate_server);
if (!ccw_device_is_pathgroup(device->cdev)) { if (!ccw_device_is_pathgroup(device->cdev)) {
dev_warn(&device->cdev->dev, dev_warn(&device->cdev->dev,
"A channel path group could not be established\n"); "A channel path group could not be established\n");
...@@ -1651,22 +1675,12 @@ dasd_eckd_check_characteristics(struct dasd_device *device) ...@@ -1651,22 +1675,12 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
block->base = device; block->base = device;
} }
/* register lcu with alias handling, enable PAV if this is a new lcu */ /* register lcu with alias handling, enable PAV */
is_known = dasd_alias_make_device_known_to_lcu(device); rc = dasd_alias_make_device_known_to_lcu(device);
if (is_known < 0) { if (rc)
rc = is_known;
goto out_err2; goto out_err2;
}
/*
* dasd_eckd_validate_server is done on the first device that
* is found for an LCU. All later other devices have to wait
* for it, so they will read the correct feature codes.
*/
if (!is_known) {
dasd_eckd_validate_server(device); dasd_eckd_validate_server(device);
dasd_alias_lcu_setup_complete(device);
} else
dasd_alias_wait_for_lcu_setup(device);
/* device may report different configuration data after LCU setup */ /* device may report different configuration data after LCU setup */
rc = dasd_eckd_read_conf(device); rc = dasd_eckd_read_conf(device);
...@@ -4098,7 +4112,7 @@ static int dasd_eckd_restore_device(struct dasd_device *device) ...@@ -4098,7 +4112,7 @@ static int dasd_eckd_restore_device(struct dasd_device *device)
{ {
struct dasd_eckd_private *private; struct dasd_eckd_private *private;
struct dasd_eckd_characteristics temp_rdc_data; struct dasd_eckd_characteristics temp_rdc_data;
int is_known, rc; int rc;
struct dasd_uid temp_uid; struct dasd_uid temp_uid;
unsigned long flags; unsigned long flags;
...@@ -4121,14 +4135,10 @@ static int dasd_eckd_restore_device(struct dasd_device *device) ...@@ -4121,14 +4135,10 @@ static int dasd_eckd_restore_device(struct dasd_device *device)
goto out_err; goto out_err;
/* register lcu with alias handling, enable PAV if this is a new lcu */ /* register lcu with alias handling, enable PAV if this is a new lcu */
is_known = dasd_alias_make_device_known_to_lcu(device); rc = dasd_alias_make_device_known_to_lcu(device);
if (is_known < 0) if (rc)
return is_known; return rc;
if (!is_known) {
dasd_eckd_validate_server(device); dasd_eckd_validate_server(device);
dasd_alias_lcu_setup_complete(device);
} else
dasd_alias_wait_for_lcu_setup(device);
/* RE-Read Configuration Data */ /* RE-Read Configuration Data */
rc = dasd_eckd_read_conf(device); rc = dasd_eckd_read_conf(device);
...@@ -4270,6 +4280,7 @@ static struct dasd_discipline dasd_eckd_discipline = { ...@@ -4270,6 +4280,7 @@ static struct dasd_discipline dasd_eckd_discipline = {
.restore = dasd_eckd_restore_device, .restore = dasd_eckd_restore_device,
.reload = dasd_eckd_reload_device, .reload = dasd_eckd_reload_device,
.get_uid = dasd_eckd_get_uid, .get_uid = dasd_eckd_get_uid,
.kick_validate = dasd_eckd_kick_validate_server,
}; };
static int __init static int __init
......
...@@ -355,6 +355,7 @@ struct dasd_discipline { ...@@ -355,6 +355,7 @@ struct dasd_discipline {
int (*reload) (struct dasd_device *); int (*reload) (struct dasd_device *);
int (*get_uid) (struct dasd_device *, struct dasd_uid *); int (*get_uid) (struct dasd_device *, struct dasd_uid *);
void (*kick_validate) (struct dasd_device *);
}; };
extern struct dasd_discipline *dasd_diag_discipline_pointer; extern struct dasd_discipline *dasd_diag_discipline_pointer;
...@@ -455,6 +456,7 @@ struct dasd_device { ...@@ -455,6 +456,7 @@ struct dasd_device {
struct work_struct kick_work; struct work_struct kick_work;
struct work_struct restore_device; struct work_struct restore_device;
struct work_struct reload_device; struct work_struct reload_device;
struct work_struct kick_validate;
struct timer_list timer; struct timer_list timer;
debug_info_t *debug_area; debug_info_t *debug_area;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment