mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 03:27:44 -04:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Martin Schwidefsky: "The big one is support for fake NUMA, splitting a really large machine in more manageable piece improves performance in some cases, e.g. for a KVM host. The FICON Link Incident handling has been improved, this helps the operator to identify degraded or non-operational FICON connections. The save and restore of floating point and vector registers has been overhauled to allow the future use of vector registers in the kernel. A few small enhancement, magic sys-requests for the vt220 console via SCLP, some more assembler code has been converted to C, the PCI error handling is improved. And the usual cleanup and bug fixing" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (59 commits) s390/jump_label: Use %*ph to print small buffers s390/sclp_vt220: support magic sysrequests s390/ctrlchar: improve handling of magic sysrequests s390/numa: remove superfluous ARCH_WANT defines s390/3270: redraw screen on unsolicited device end s390/dcssblk: correct out of bounds array indexes s390/mm: simplify page table alloc/free code s390/pci: move debug messages to debugfs s390/nmi: initialize control register 0 earlier s390/zcrypt: use msleep() instead of mdelay() s390/hmcdrv: fix interrupt registration s390/setup: fix novx parameter s390/uaccess: remove uaccess_primary kernel parameter s390: remove unneeded sizeof(void *) comparisons s390/facilities: remove transactional-execution bits s390/numa: re-add DIE sched_domain_topology_level s390/dasd: enhance CUIR scope detection s390/dasd: fix failing path verification s390/vdso: emit a GNU hash s390/numa: make core to node mapping data dynamic ...
This commit is contained in:
commit
9c6a019c6e
94 changed files with 3696 additions and 1368 deletions
|
|
@ -58,7 +58,7 @@ static struct alias_server *_find_server(struct dasd_uid *uid)
|
|||
&& !strncmp(pos->uid.serial, uid->serial,
|
||||
sizeof(uid->serial)))
|
||||
return pos;
|
||||
};
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ static struct alias_lcu *_find_lcu(struct alias_server *server,
|
|||
list_for_each_entry(pos, &server->lculist, lcu) {
|
||||
if (pos->uid.ssid == uid->ssid)
|
||||
return pos;
|
||||
};
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -97,7 +97,7 @@ static struct alias_pav_group *_find_group(struct alias_lcu *lcu,
|
|||
if (pos->uid.base_unit_addr == search_unit_addr &&
|
||||
!strncmp(pos->uid.vduit, uid->vduit, sizeof(uid->vduit)))
|
||||
return pos;
|
||||
};
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1036,7 +1036,7 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
|
|||
{
|
||||
void *conf_data;
|
||||
int conf_len, conf_data_saved;
|
||||
int rc, path_err;
|
||||
int rc, path_err, pos;
|
||||
__u8 lpm, opm;
|
||||
struct dasd_eckd_private *private, path_private;
|
||||
struct dasd_path *path_data;
|
||||
|
|
@ -1068,6 +1068,17 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
|
|||
path_data->opm |= lpm;
|
||||
continue; /* no error */
|
||||
}
|
||||
/* translate path mask to position in mask */
|
||||
pos = 8 - ffs(lpm);
|
||||
kfree(private->path_conf_data[pos]);
|
||||
if ((__u8 *)private->path_conf_data[pos] ==
|
||||
private->conf_data) {
|
||||
private->conf_data = NULL;
|
||||
private->conf_len = 0;
|
||||
conf_data_saved = 0;
|
||||
}
|
||||
private->path_conf_data[pos] =
|
||||
(struct dasd_conf_data *) conf_data;
|
||||
/* save first valid configuration data */
|
||||
if (!conf_data_saved) {
|
||||
kfree(private->conf_data);
|
||||
|
|
@ -1095,7 +1106,6 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
|
|||
kfree(conf_data);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dasd_eckd_compare_path_uid(
|
||||
device, &path_private)) {
|
||||
uid = &path_private.uid;
|
||||
|
|
@ -1157,9 +1167,6 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
|
|||
path_data->cablepm &= ~lpm;
|
||||
path_data->hpfpm &= ~lpm;
|
||||
path_data->cuirpm &= ~lpm;
|
||||
|
||||
if (conf_data != private->conf_data)
|
||||
kfree(conf_data);
|
||||
}
|
||||
|
||||
return path_err;
|
||||
|
|
@ -1259,7 +1266,11 @@ static void do_path_verification_work(struct work_struct *work)
|
|||
schedule_work(work);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check if path verification already running and delay if so */
|
||||
if (test_and_set_bit(DASD_FLAG_PATH_VERIFY, &device->flags)) {
|
||||
schedule_work(work);
|
||||
return;
|
||||
}
|
||||
opm = 0;
|
||||
npm = 0;
|
||||
ppm = 0;
|
||||
|
|
@ -1402,7 +1413,7 @@ static void do_path_verification_work(struct work_struct *work)
|
|||
device->path_data.hpfpm |= hpfpm;
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
|
||||
}
|
||||
|
||||
clear_bit(DASD_FLAG_PATH_VERIFY, &device->flags);
|
||||
dasd_put_device(device);
|
||||
if (data->isglobal)
|
||||
mutex_unlock(&dasd_path_verification_mutex);
|
||||
|
|
@ -1810,6 +1821,7 @@ out_err1:
|
|||
static void dasd_eckd_uncheck_device(struct dasd_device *device)
|
||||
{
|
||||
struct dasd_eckd_private *private;
|
||||
int i;
|
||||
|
||||
private = (struct dasd_eckd_private *) device->private;
|
||||
dasd_alias_disconnect_device_from_lcu(device);
|
||||
|
|
@ -1818,6 +1830,15 @@ static void dasd_eckd_uncheck_device(struct dasd_device *device)
|
|||
private->vdsneq = NULL;
|
||||
private->gneq = NULL;
|
||||
private->conf_len = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
kfree(private->path_conf_data[i]);
|
||||
if ((__u8 *)private->path_conf_data[i] ==
|
||||
private->conf_data) {
|
||||
private->conf_data = NULL;
|
||||
private->conf_len = 0;
|
||||
}
|
||||
private->path_conf_data[i] = NULL;
|
||||
}
|
||||
kfree(private->conf_data);
|
||||
private->conf_data = NULL;
|
||||
}
|
||||
|
|
@ -3968,7 +3989,7 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp)
|
|||
rc = -EFAULT;
|
||||
if (copy_from_user(&usrparm, argp, sizeof(usrparm)))
|
||||
goto out;
|
||||
if (is_compat_task() || sizeof(long) == 4) {
|
||||
if (is_compat_task()) {
|
||||
/* Make sure pointers are sane even on 31 bit. */
|
||||
rc = -EINVAL;
|
||||
if ((usrparm.psf_data >> 32) != 0)
|
||||
|
|
@ -4525,12 +4546,13 @@ static int dasd_eckd_read_message_buffer(struct dasd_device *device,
|
|||
cqr->startdev = device;
|
||||
cqr->memdev = device;
|
||||
cqr->block = NULL;
|
||||
cqr->retries = 256;
|
||||
cqr->expires = 10 * HZ;
|
||||
|
||||
/* we need to check for messages on exactly this path */
|
||||
set_bit(DASD_CQR_VERIFY_PATH, &cqr->flags);
|
||||
cqr->lpm = lpum;
|
||||
/* dasd_sleep_on_immediatly does not do complex error
|
||||
* recovery so clear erp flag and set retry counter to
|
||||
* do basic erp */
|
||||
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
|
||||
cqr->retries = 256;
|
||||
|
||||
/* Prepare for Read Subsystem Data */
|
||||
prssdp = (struct dasd_psf_prssd_data *) cqr->data;
|
||||
|
|
@ -4605,10 +4627,10 @@ dasd_eckd_psf_cuir_response(struct dasd_device *device, int response,
|
|||
psf_cuir->message_id = message_id;
|
||||
psf_cuir->cssid = sch_id.cssid;
|
||||
psf_cuir->ssid = sch_id.ssid;
|
||||
|
||||
ccw = cqr->cpaddr;
|
||||
ccw->cmd_code = DASD_ECKD_CCW_PSF;
|
||||
ccw->cda = (__u32)(addr_t)psf_cuir;
|
||||
ccw->flags = CCW_FLAG_SLI;
|
||||
ccw->count = sizeof(struct dasd_psf_cuir_response);
|
||||
|
||||
cqr->startdev = device;
|
||||
|
|
@ -4618,6 +4640,7 @@ dasd_eckd_psf_cuir_response(struct dasd_device *device, int response,
|
|||
cqr->expires = 10*HZ;
|
||||
cqr->buildclk = get_tod_clock();
|
||||
cqr->status = DASD_CQR_FILLED;
|
||||
set_bit(DASD_CQR_VERIFY_PATH, &cqr->flags);
|
||||
|
||||
rc = dasd_sleep_on(cqr);
|
||||
|
||||
|
|
@ -4625,118 +4648,252 @@ dasd_eckd_psf_cuir_response(struct dasd_device *device, int response,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int dasd_eckd_cuir_change_state(struct dasd_device *device, __u8 lpum)
|
||||
/*
|
||||
* return configuration data that is referenced by record selector
|
||||
* if a record selector is specified or per default return the
|
||||
* conf_data pointer for the path specified by lpum
|
||||
*/
|
||||
static struct dasd_conf_data *dasd_eckd_get_ref_conf(struct dasd_device *device,
|
||||
__u8 lpum,
|
||||
struct dasd_cuir_message *cuir)
|
||||
{
|
||||
unsigned long flags;
|
||||
__u8 tbcpm;
|
||||
struct dasd_eckd_private *private;
|
||||
struct dasd_conf_data *conf_data;
|
||||
int path, pos;
|
||||
|
||||
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
|
||||
tbcpm = device->path_data.opm & ~lpum;
|
||||
if (tbcpm) {
|
||||
device->path_data.opm = tbcpm;
|
||||
device->path_data.cuirpm |= lpum;
|
||||
private = (struct dasd_eckd_private *) device->private;
|
||||
if (cuir->record_selector == 0)
|
||||
goto out;
|
||||
for (path = 0x80, pos = 0; path; path >>= 1, pos++) {
|
||||
conf_data = private->path_conf_data[pos];
|
||||
if (conf_data->gneq.record_selector ==
|
||||
cuir->record_selector)
|
||||
return conf_data;
|
||||
}
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
|
||||
return tbcpm ? 0 : PSF_CUIR_LAST_PATH;
|
||||
out:
|
||||
return private->path_conf_data[8 - ffs(lpum)];
|
||||
}
|
||||
|
||||
/*
|
||||
* walk through all devices and quiesce them
|
||||
* if it is the last path return error
|
||||
* This function determines the scope of a reconfiguration request by
|
||||
* analysing the path and device selection data provided in the CUIR request.
|
||||
* Returns a path mask containing CUIR affected paths for the give device.
|
||||
*
|
||||
* If the CUIR request does not contain the required information return the
|
||||
* path mask of the path the attention message for the CUIR request was reveived
|
||||
* on.
|
||||
*/
|
||||
static int dasd_eckd_cuir_scope(struct dasd_device *device, __u8 lpum,
|
||||
struct dasd_cuir_message *cuir)
|
||||
{
|
||||
struct dasd_conf_data *ref_conf_data;
|
||||
unsigned long bitmask = 0, mask = 0;
|
||||
struct dasd_eckd_private *private;
|
||||
struct dasd_conf_data *conf_data;
|
||||
unsigned int pos, path;
|
||||
char *ref_gneq, *gneq;
|
||||
char *ref_ned, *ned;
|
||||
int tbcpm = 0;
|
||||
|
||||
/* if CUIR request does not specify the scope use the path
|
||||
the attention message was presented on */
|
||||
if (!cuir->ned_map ||
|
||||
!(cuir->neq_map[0] | cuir->neq_map[1] | cuir->neq_map[2]))
|
||||
return lpum;
|
||||
|
||||
private = (struct dasd_eckd_private *) device->private;
|
||||
/* get reference conf data */
|
||||
ref_conf_data = dasd_eckd_get_ref_conf(device, lpum, cuir);
|
||||
/* reference ned is determined by ned_map field */
|
||||
pos = 8 - ffs(cuir->ned_map);
|
||||
ref_ned = (char *)&ref_conf_data->neds[pos];
|
||||
ref_gneq = (char *)&ref_conf_data->gneq;
|
||||
/* transfer 24 bit neq_map to mask */
|
||||
mask = cuir->neq_map[2];
|
||||
mask |= cuir->neq_map[1] << 8;
|
||||
mask |= cuir->neq_map[0] << 16;
|
||||
|
||||
for (path = 0x80; path; path >>= 1) {
|
||||
/* initialise data per path */
|
||||
bitmask = mask;
|
||||
pos = 8 - ffs(path);
|
||||
conf_data = private->path_conf_data[pos];
|
||||
pos = 8 - ffs(cuir->ned_map);
|
||||
ned = (char *) &conf_data->neds[pos];
|
||||
/* compare reference ned and per path ned */
|
||||
if (memcmp(ref_ned, ned, sizeof(*ned)) != 0)
|
||||
continue;
|
||||
gneq = (char *)&conf_data->gneq;
|
||||
/* compare reference gneq and per_path gneq under
|
||||
24 bit mask where mask bit 0 equals byte 7 of
|
||||
the gneq and mask bit 24 equals byte 31 */
|
||||
while (bitmask) {
|
||||
pos = ffs(bitmask) - 1;
|
||||
if (memcmp(&ref_gneq[31 - pos], &gneq[31 - pos], 1)
|
||||
!= 0)
|
||||
break;
|
||||
clear_bit(pos, &bitmask);
|
||||
}
|
||||
if (bitmask)
|
||||
continue;
|
||||
/* device and path match the reference values
|
||||
add path to CUIR scope */
|
||||
tbcpm |= path;
|
||||
}
|
||||
return tbcpm;
|
||||
}
|
||||
|
||||
static void dasd_eckd_cuir_notify_user(struct dasd_device *device,
|
||||
unsigned long paths,
|
||||
struct subchannel_id sch_id, int action)
|
||||
{
|
||||
struct channel_path_desc *desc;
|
||||
int pos;
|
||||
|
||||
while (paths) {
|
||||
/* get position of bit in mask */
|
||||
pos = ffs(paths) - 1;
|
||||
/* get channel path descriptor from this position */
|
||||
desc = ccw_device_get_chp_desc(device->cdev, 7 - pos);
|
||||
if (action == CUIR_QUIESCE)
|
||||
pr_warn("Service on the storage server caused path "
|
||||
"%x.%02x to go offline", sch_id.cssid,
|
||||
desc ? desc->chpid : 0);
|
||||
else if (action == CUIR_RESUME)
|
||||
pr_info("Path %x.%02x is back online after service "
|
||||
"on the storage server", sch_id.cssid,
|
||||
desc ? desc->chpid : 0);
|
||||
kfree(desc);
|
||||
clear_bit(pos, &paths);
|
||||
}
|
||||
}
|
||||
|
||||
static int dasd_eckd_cuir_remove_path(struct dasd_device *device, __u8 lpum,
|
||||
struct dasd_cuir_message *cuir)
|
||||
{
|
||||
unsigned long tbcpm;
|
||||
|
||||
tbcpm = dasd_eckd_cuir_scope(device, lpum, cuir);
|
||||
/* nothing to do if path is not in use */
|
||||
if (!(device->path_data.opm & tbcpm))
|
||||
return 0;
|
||||
if (!(device->path_data.opm & ~tbcpm)) {
|
||||
/* no path would be left if the CUIR action is taken
|
||||
return error */
|
||||
return -EINVAL;
|
||||
}
|
||||
/* remove device from operational path mask */
|
||||
device->path_data.opm &= ~tbcpm;
|
||||
device->path_data.cuirpm |= tbcpm;
|
||||
return tbcpm;
|
||||
}
|
||||
|
||||
/*
|
||||
* walk through all devices and build a path mask to quiesce them
|
||||
* return an error if the last path to a device would be removed
|
||||
*
|
||||
* if only part of the devices are quiesced and an error
|
||||
* occurs no onlining necessary, the storage server will
|
||||
* notify the already set offline devices again
|
||||
*/
|
||||
static int dasd_eckd_cuir_quiesce(struct dasd_device *device, __u8 lpum,
|
||||
struct channel_path_desc *desc,
|
||||
struct subchannel_id sch_id)
|
||||
struct subchannel_id sch_id,
|
||||
struct dasd_cuir_message *cuir)
|
||||
{
|
||||
struct alias_pav_group *pavgroup, *tempgroup;
|
||||
struct dasd_eckd_private *private;
|
||||
struct dasd_device *dev, *n;
|
||||
int rc;
|
||||
unsigned long paths = 0;
|
||||
unsigned long flags;
|
||||
int tbcpm;
|
||||
|
||||
private = (struct dasd_eckd_private *) device->private;
|
||||
rc = 0;
|
||||
|
||||
/* active devices */
|
||||
list_for_each_entry_safe(dev, n,
|
||||
&private->lcu->active_devices,
|
||||
list_for_each_entry_safe(dev, n, &private->lcu->active_devices,
|
||||
alias_list) {
|
||||
rc = dasd_eckd_cuir_change_state(dev, lpum);
|
||||
if (rc)
|
||||
goto out;
|
||||
spin_lock_irqsave(get_ccwdev_lock(dev->cdev), flags);
|
||||
tbcpm = dasd_eckd_cuir_remove_path(dev, lpum, cuir);
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(dev->cdev), flags);
|
||||
if (tbcpm < 0)
|
||||
goto out_err;
|
||||
paths |= tbcpm;
|
||||
}
|
||||
|
||||
/* inactive devices */
|
||||
list_for_each_entry_safe(dev, n,
|
||||
&private->lcu->inactive_devices,
|
||||
list_for_each_entry_safe(dev, n, &private->lcu->inactive_devices,
|
||||
alias_list) {
|
||||
rc = dasd_eckd_cuir_change_state(dev, lpum);
|
||||
if (rc)
|
||||
goto out;
|
||||
spin_lock_irqsave(get_ccwdev_lock(dev->cdev), flags);
|
||||
tbcpm = dasd_eckd_cuir_remove_path(dev, lpum, cuir);
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(dev->cdev), flags);
|
||||
if (tbcpm < 0)
|
||||
goto out_err;
|
||||
paths |= tbcpm;
|
||||
}
|
||||
|
||||
/* devices in PAV groups */
|
||||
list_for_each_entry_safe(pavgroup, tempgroup,
|
||||
&private->lcu->grouplist, group) {
|
||||
list_for_each_entry_safe(dev, n, &pavgroup->baselist,
|
||||
alias_list) {
|
||||
rc = dasd_eckd_cuir_change_state(dev, lpum);
|
||||
if (rc)
|
||||
goto out;
|
||||
spin_lock_irqsave(get_ccwdev_lock(dev->cdev), flags);
|
||||
tbcpm = dasd_eckd_cuir_remove_path(dev, lpum, cuir);
|
||||
spin_unlock_irqrestore(
|
||||
get_ccwdev_lock(dev->cdev), flags);
|
||||
if (tbcpm < 0)
|
||||
goto out_err;
|
||||
paths |= tbcpm;
|
||||
}
|
||||
list_for_each_entry_safe(dev, n, &pavgroup->aliaslist,
|
||||
alias_list) {
|
||||
rc = dasd_eckd_cuir_change_state(dev, lpum);
|
||||
if (rc)
|
||||
goto out;
|
||||
spin_lock_irqsave(get_ccwdev_lock(dev->cdev), flags);
|
||||
tbcpm = dasd_eckd_cuir_remove_path(dev, lpum, cuir);
|
||||
spin_unlock_irqrestore(
|
||||
get_ccwdev_lock(dev->cdev), flags);
|
||||
if (tbcpm < 0)
|
||||
goto out_err;
|
||||
paths |= tbcpm;
|
||||
}
|
||||
}
|
||||
|
||||
pr_warn("Service on the storage server caused path %x.%02x to go offline",
|
||||
sch_id.cssid, desc ? desc->chpid : 0);
|
||||
rc = PSF_CUIR_COMPLETED;
|
||||
out:
|
||||
return rc;
|
||||
/* notify user about all paths affected by CUIR action */
|
||||
dasd_eckd_cuir_notify_user(device, paths, sch_id, CUIR_QUIESCE);
|
||||
return 0;
|
||||
out_err:
|
||||
return tbcpm;
|
||||
}
|
||||
|
||||
static int dasd_eckd_cuir_resume(struct dasd_device *device, __u8 lpum,
|
||||
struct channel_path_desc *desc,
|
||||
struct subchannel_id sch_id)
|
||||
struct subchannel_id sch_id,
|
||||
struct dasd_cuir_message *cuir)
|
||||
{
|
||||
struct alias_pav_group *pavgroup, *tempgroup;
|
||||
struct dasd_eckd_private *private;
|
||||
struct dasd_device *dev, *n;
|
||||
unsigned long paths = 0;
|
||||
int tbcpm;
|
||||
|
||||
pr_info("Path %x.%02x is back online after service on the storage server",
|
||||
sch_id.cssid, desc ? desc->chpid : 0);
|
||||
private = (struct dasd_eckd_private *) device->private;
|
||||
|
||||
/*
|
||||
* the path may have been added through a generic path event before
|
||||
* only trigger path verification if the path is not already in use
|
||||
*/
|
||||
|
||||
list_for_each_entry_safe(dev, n,
|
||||
&private->lcu->active_devices,
|
||||
alias_list) {
|
||||
if (!(dev->path_data.opm & lpum)) {
|
||||
dev->path_data.tbvpm |= lpum;
|
||||
tbcpm = dasd_eckd_cuir_scope(dev, lpum, cuir);
|
||||
paths |= tbcpm;
|
||||
if (!(dev->path_data.opm & tbcpm)) {
|
||||
dev->path_data.tbvpm |= tbcpm;
|
||||
dasd_schedule_device_bh(dev);
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(dev, n,
|
||||
&private->lcu->inactive_devices,
|
||||
alias_list) {
|
||||
if (!(dev->path_data.opm & lpum)) {
|
||||
dev->path_data.tbvpm |= lpum;
|
||||
tbcpm = dasd_eckd_cuir_scope(dev, lpum, cuir);
|
||||
paths |= tbcpm;
|
||||
if (!(dev->path_data.opm & tbcpm)) {
|
||||
dev->path_data.tbvpm |= tbcpm;
|
||||
dasd_schedule_device_bh(dev);
|
||||
}
|
||||
}
|
||||
|
||||
/* devices in PAV groups */
|
||||
list_for_each_entry_safe(pavgroup, tempgroup,
|
||||
&private->lcu->grouplist,
|
||||
|
|
@ -4744,21 +4901,27 @@ static int dasd_eckd_cuir_resume(struct dasd_device *device, __u8 lpum,
|
|||
list_for_each_entry_safe(dev, n,
|
||||
&pavgroup->baselist,
|
||||
alias_list) {
|
||||
if (!(dev->path_data.opm & lpum)) {
|
||||
dev->path_data.tbvpm |= lpum;
|
||||
tbcpm = dasd_eckd_cuir_scope(dev, lpum, cuir);
|
||||
paths |= tbcpm;
|
||||
if (!(dev->path_data.opm & tbcpm)) {
|
||||
dev->path_data.tbvpm |= tbcpm;
|
||||
dasd_schedule_device_bh(dev);
|
||||
}
|
||||
}
|
||||
list_for_each_entry_safe(dev, n,
|
||||
&pavgroup->aliaslist,
|
||||
alias_list) {
|
||||
if (!(dev->path_data.opm & lpum)) {
|
||||
dev->path_data.tbvpm |= lpum;
|
||||
tbcpm = dasd_eckd_cuir_scope(dev, lpum, cuir);
|
||||
paths |= tbcpm;
|
||||
if (!(dev->path_data.opm & tbcpm)) {
|
||||
dev->path_data.tbvpm |= tbcpm;
|
||||
dasd_schedule_device_bh(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
return PSF_CUIR_COMPLETED;
|
||||
/* notify user about all paths affected by CUIR action */
|
||||
dasd_eckd_cuir_notify_user(device, paths, sch_id, CUIR_RESUME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dasd_eckd_handle_cuir(struct dasd_device *device, void *messages,
|
||||
|
|
@ -4768,8 +4931,12 @@ static void dasd_eckd_handle_cuir(struct dasd_device *device, void *messages,
|
|||
struct channel_path_desc *desc;
|
||||
struct subchannel_id sch_id;
|
||||
int pos, response;
|
||||
ccw_device_get_schid(device->cdev, &sch_id);
|
||||
|
||||
DBF_DEV_EVENT(DBF_WARNING, device,
|
||||
"CUIR request: %016llx %016llx %016llx %08x",
|
||||
((u64 *)cuir)[0], ((u64 *)cuir)[1], ((u64 *)cuir)[2],
|
||||
((u32 *)cuir)[3]);
|
||||
ccw_device_get_schid(device->cdev, &sch_id);
|
||||
/* get position of path in mask */
|
||||
pos = 8 - ffs(lpum);
|
||||
/* get channel path descriptor from this position */
|
||||
|
|
@ -4777,18 +4944,26 @@ static void dasd_eckd_handle_cuir(struct dasd_device *device, void *messages,
|
|||
|
||||
if (cuir->code == CUIR_QUIESCE) {
|
||||
/* quiesce */
|
||||
response = dasd_eckd_cuir_quiesce(device, lpum, desc, sch_id);
|
||||
if (dasd_eckd_cuir_quiesce(device, lpum, sch_id, cuir))
|
||||
response = PSF_CUIR_LAST_PATH;
|
||||
else
|
||||
response = PSF_CUIR_COMPLETED;
|
||||
} else if (cuir->code == CUIR_RESUME) {
|
||||
/* resume */
|
||||
response = dasd_eckd_cuir_resume(device, lpum, desc, sch_id);
|
||||
dasd_eckd_cuir_resume(device, lpum, sch_id, cuir);
|
||||
response = PSF_CUIR_COMPLETED;
|
||||
} else
|
||||
response = PSF_CUIR_NOT_SUPPORTED;
|
||||
|
||||
dasd_eckd_psf_cuir_response(device, response, cuir->message_id,
|
||||
desc, sch_id);
|
||||
|
||||
dasd_eckd_psf_cuir_response(device, response,
|
||||
cuir->message_id, desc, sch_id);
|
||||
DBF_DEV_EVENT(DBF_WARNING, device,
|
||||
"CUIR response: %d on message ID %08x", response,
|
||||
cuir->message_id);
|
||||
/* free descriptor copy */
|
||||
kfree(desc);
|
||||
/* to make sure there is no attention left schedule work again */
|
||||
device->discipline->check_attention(device, lpum);
|
||||
}
|
||||
|
||||
static void dasd_eckd_check_attention_work(struct work_struct *work)
|
||||
|
|
@ -4800,22 +4975,18 @@ static void dasd_eckd_check_attention_work(struct work_struct *work)
|
|||
|
||||
data = container_of(work, struct check_attention_work_data, worker);
|
||||
device = data->device;
|
||||
|
||||
messages = kzalloc(sizeof(*messages), GFP_KERNEL);
|
||||
if (!messages) {
|
||||
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
|
||||
"Could not allocate attention message buffer");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = dasd_eckd_read_message_buffer(device, messages, data->lpum);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (messages->length == ATTENTION_LENGTH_CUIR &&
|
||||
messages->format == ATTENTION_FORMAT_CUIR)
|
||||
dasd_eckd_handle_cuir(device, messages, data->lpum);
|
||||
|
||||
out:
|
||||
dasd_put_device(device);
|
||||
kfree(messages);
|
||||
|
|
|
|||
|
|
@ -355,7 +355,8 @@ struct dasd_gneq {
|
|||
__u8 identifier:2;
|
||||
__u8 reserved:6;
|
||||
} __attribute__ ((packed)) flags;
|
||||
__u8 reserved[5];
|
||||
__u8 record_selector;
|
||||
__u8 reserved[4];
|
||||
struct {
|
||||
__u8 value:2;
|
||||
__u8 number:6;
|
||||
|
|
@ -492,10 +493,18 @@ struct alias_pav_group {
|
|||
struct dasd_device *next;
|
||||
};
|
||||
|
||||
struct dasd_conf_data {
|
||||
struct dasd_ned neds[5];
|
||||
u8 reserved[64];
|
||||
struct dasd_gneq gneq;
|
||||
} __packed;
|
||||
|
||||
struct dasd_eckd_private {
|
||||
struct dasd_eckd_characteristics rdc_data;
|
||||
u8 *conf_data;
|
||||
int conf_len;
|
||||
/* per path configuration data */
|
||||
struct dasd_conf_data *path_conf_data[8];
|
||||
/* pointers to specific parts in the conf_data */
|
||||
struct dasd_ned *ned;
|
||||
struct dasd_sneq *sneq;
|
||||
|
|
|
|||
|
|
@ -534,6 +534,7 @@ struct dasd_attention_data {
|
|||
#define DASD_FLAG_SAFE_OFFLINE 10 /* safe offline processing requested*/
|
||||
#define DASD_FLAG_SAFE_OFFLINE_RUNNING 11 /* safe offline running */
|
||||
#define DASD_FLAG_ABORTALL 12 /* Abort all noretry requests */
|
||||
#define DASD_FLAG_PATH_VERIFY 13 /* Path verification worker running */
|
||||
|
||||
#define DASD_SLEEPON_START_TAG ((void *) 1)
|
||||
#define DASD_SLEEPON_END_TAG ((void *) 2)
|
||||
|
|
|
|||
|
|
@ -548,10 +548,10 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
|
|||
*/
|
||||
num_of_segments = 0;
|
||||
for (i = 0; (i < count && (buf[i] != '\0') && (buf[i] != '\n')); i++) {
|
||||
for (j = i; (buf[j] != ':') &&
|
||||
for (j = i; j < count &&
|
||||
(buf[j] != ':') &&
|
||||
(buf[j] != '\0') &&
|
||||
(buf[j] != '\n') &&
|
||||
j < count; j++) {
|
||||
(buf[j] != '\n'); j++) {
|
||||
local_buf[j-i] = toupper(buf[j]);
|
||||
}
|
||||
local_buf[j-i] = '\0';
|
||||
|
|
@ -723,7 +723,7 @@ dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const ch
|
|||
/*
|
||||
* parse input
|
||||
*/
|
||||
for (i = 0; ((*(buf+i)!='\0') && (*(buf+i)!='\n') && i < count); i++) {
|
||||
for (i = 0; (i < count && (*(buf+i)!='\0') && (*(buf+i)!='\n')); i++) {
|
||||
local_buf[i] = toupper(buf[i]);
|
||||
}
|
||||
local_buf[i] = '\0';
|
||||
|
|
@ -904,10 +904,10 @@ dcssblk_check_params(void)
|
|||
|
||||
for (i = 0; (i < DCSSBLK_PARM_LEN) && (dcssblk_segments[i] != '\0');
|
||||
i++) {
|
||||
for (j = i; (dcssblk_segments[j] != ',') &&
|
||||
for (j = i; (j < DCSSBLK_PARM_LEN) &&
|
||||
(dcssblk_segments[j] != ',') &&
|
||||
(dcssblk_segments[j] != '\0') &&
|
||||
(dcssblk_segments[j] != '(') &&
|
||||
(j < DCSSBLK_PARM_LEN); j++)
|
||||
(dcssblk_segments[j] != '('); j++)
|
||||
{
|
||||
buf[j-i] = dcssblk_segments[j];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -413,6 +413,10 @@ con3270_irq(struct con3270 *cp, struct raw3270_request *rq, struct irb *irb)
|
|||
else
|
||||
/* Normal end. Copy residual count. */
|
||||
rq->rescnt = irb->scsw.cmd.count;
|
||||
} else if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) {
|
||||
/* Interrupt without an outstanding request -> update all */
|
||||
cp->update_flags = CON_UPDATE_ALL;
|
||||
con3270_set_timer(cp, 1);
|
||||
}
|
||||
return RAW3270_IO_DONE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,15 +14,21 @@
|
|||
#include "ctrlchar.h"
|
||||
|
||||
#ifdef CONFIG_MAGIC_SYSRQ
|
||||
static int ctrlchar_sysrq_key;
|
||||
static struct sysrq_work ctrlchar_sysrq;
|
||||
|
||||
static void
|
||||
ctrlchar_handle_sysrq(struct work_struct *work)
|
||||
{
|
||||
handle_sysrq(ctrlchar_sysrq_key);
|
||||
struct sysrq_work *sysrq = container_of(work, struct sysrq_work, work);
|
||||
|
||||
handle_sysrq(sysrq->key);
|
||||
}
|
||||
|
||||
static DECLARE_WORK(ctrlchar_work, ctrlchar_handle_sysrq);
|
||||
void schedule_sysrq_work(struct sysrq_work *sw)
|
||||
{
|
||||
INIT_WORK(&sw->work, ctrlchar_handle_sysrq);
|
||||
schedule_work(&sw->work);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -51,8 +57,8 @@ ctrlchar_handle(const unsigned char *buf, int len, struct tty_struct *tty)
|
|||
#ifdef CONFIG_MAGIC_SYSRQ
|
||||
/* racy */
|
||||
if (len == 3 && buf[1] == '-') {
|
||||
ctrlchar_sysrq_key = buf[2];
|
||||
schedule_work(&ctrlchar_work);
|
||||
ctrlchar_sysrq.key = buf[2];
|
||||
schedule_sysrq_work(&ctrlchar_sysrq);
|
||||
return CTRLCHAR_SYSRQ;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
*/
|
||||
|
||||
#include <linux/tty.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
extern unsigned int
|
||||
ctrlchar_handle(const unsigned char *buf, int len, struct tty_struct *tty);
|
||||
|
|
@ -17,3 +19,13 @@ ctrlchar_handle(const unsigned char *buf, int len, struct tty_struct *tty);
|
|||
#define CTRLCHAR_SYSRQ (3 << 8)
|
||||
|
||||
#define CTRLCHAR_MASK (~0xffu)
|
||||
|
||||
|
||||
#ifdef CONFIG_MAGIC_SYSRQ
|
||||
struct sysrq_work {
|
||||
int key;
|
||||
struct work_struct work;
|
||||
};
|
||||
|
||||
void schedule_sysrq_work(struct sysrq_work *sw);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ int diag_ftp_startup(void)
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
ctl_set_bit(0, 63 - 22);
|
||||
irq_subclass_register(IRQ_SUBCLASS_SERVICE_SIGNAL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -232,6 +232,6 @@ int diag_ftp_startup(void)
|
|||
*/
|
||||
void diag_ftp_shutdown(void)
|
||||
{
|
||||
ctl_clear_bit(0, 63 - 22);
|
||||
irq_subclass_unregister(IRQ_SUBCLASS_SERVICE_SIGNAL);
|
||||
unregister_external_irq(EXT_IRQ_CP_SERVICE, diag_ftp_handler);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ static void dcss_mkname(char *ascii_name, char *ebcdic_name)
|
|||
if (ascii_name[i] == '\0')
|
||||
break;
|
||||
ebcdic_name[i] = toupper(ascii_name[i]);
|
||||
};
|
||||
}
|
||||
for (; i < 8; i++)
|
||||
ebcdic_name[i] = ' ';
|
||||
ASCEBC(ebcdic_name, 8);
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ static DECLARE_COMPLETION(sclp_request_queue_flushed);
|
|||
/* Number of console pages to allocate, used by sclp_con.c and sclp_vt220.c */
|
||||
int sclp_console_pages = SCLP_CONSOLE_PAGES;
|
||||
/* Flag to indicate if buffer pages are dropped on buffer full condition */
|
||||
int sclp_console_drop = 0;
|
||||
int sclp_console_drop = 1;
|
||||
/* Number of times the console dropped buffer pages */
|
||||
unsigned long sclp_console_full;
|
||||
|
||||
|
|
@ -79,8 +79,8 @@ static int __init sclp_setup_console_drop(char *str)
|
|||
int drop, rc;
|
||||
|
||||
rc = kstrtoint(str, 0, &drop);
|
||||
if (!rc && drop)
|
||||
sclp_console_drop = 1;
|
||||
if (!rc)
|
||||
sclp_console_drop = drop;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <asm/setup.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/sclp.h>
|
||||
#include <asm/numa.h>
|
||||
|
||||
#include "sclp.h"
|
||||
|
||||
|
|
@ -388,11 +389,11 @@ static struct notifier_block sclp_mem_nb = {
|
|||
};
|
||||
|
||||
static void __init align_to_block_size(unsigned long long *start,
|
||||
unsigned long long *size)
|
||||
unsigned long long *size,
|
||||
unsigned long long alignment)
|
||||
{
|
||||
unsigned long long start_align, size_align, alignment;
|
||||
unsigned long long start_align, size_align;
|
||||
|
||||
alignment = memory_block_size_bytes();
|
||||
start_align = roundup(*start, alignment);
|
||||
size_align = rounddown(*start + *size, alignment) - start_align;
|
||||
|
||||
|
|
@ -404,8 +405,8 @@ static void __init align_to_block_size(unsigned long long *start,
|
|||
|
||||
static void __init add_memory_merged(u16 rn)
|
||||
{
|
||||
unsigned long long start, size, addr, block_size;
|
||||
static u16 first_rn, num;
|
||||
unsigned long long start, size;
|
||||
|
||||
if (rn && first_rn && (first_rn + num == rn)) {
|
||||
num++;
|
||||
|
|
@ -423,9 +424,12 @@ static void __init add_memory_merged(u16 rn)
|
|||
goto skip_add;
|
||||
if (memory_end_set && (start + size > memory_end))
|
||||
size = memory_end - start;
|
||||
align_to_block_size(&start, &size);
|
||||
if (size)
|
||||
add_memory(0, start, size);
|
||||
block_size = memory_block_size_bytes();
|
||||
align_to_block_size(&start, &size, block_size);
|
||||
if (!size)
|
||||
goto skip_add;
|
||||
for (addr = start; addr < start + size; addr += block_size)
|
||||
add_memory(numa_pfn_to_nid(PFN_DOWN(addr)), addr, block_size);
|
||||
skip_add:
|
||||
first_rn = rn;
|
||||
num = 1;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/wait.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_driver.h>
|
||||
#include <linux/tty_flip.h>
|
||||
|
|
@ -27,6 +28,7 @@
|
|||
|
||||
#include <asm/uaccess.h>
|
||||
#include "sclp.h"
|
||||
#include "ctrlchar.h"
|
||||
|
||||
#define SCLP_VT220_MAJOR TTY_MAJOR
|
||||
#define SCLP_VT220_MINOR 65
|
||||
|
|
@ -477,6 +479,53 @@ sclp_vt220_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
|||
#define SCLP_VT220_SESSION_STARTED 0x80
|
||||
#define SCLP_VT220_SESSION_DATA 0x00
|
||||
|
||||
#ifdef CONFIG_MAGIC_SYSRQ
|
||||
|
||||
static int sysrq_pressed;
|
||||
static struct sysrq_work sysrq;
|
||||
|
||||
static void sclp_vt220_reset_session(void)
|
||||
{
|
||||
sysrq_pressed = 0;
|
||||
}
|
||||
|
||||
static void sclp_vt220_handle_input(const char *buffer, unsigned int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
/* Handle magic sys request */
|
||||
if (buffer[i] == ('O' ^ 0100)) { /* CTRL-O */
|
||||
/*
|
||||
* If pressed again, reset sysrq_pressed
|
||||
* and flip CTRL-O character
|
||||
*/
|
||||
sysrq_pressed = !sysrq_pressed;
|
||||
if (sysrq_pressed)
|
||||
continue;
|
||||
} else if (sysrq_pressed) {
|
||||
sysrq.key = buffer[i];
|
||||
schedule_sysrq_work(&sysrq);
|
||||
sysrq_pressed = 0;
|
||||
continue;
|
||||
}
|
||||
tty_insert_flip_char(&sclp_vt220_port, buffer[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void sclp_vt220_reset_session(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void sclp_vt220_handle_input(const char *buffer, unsigned int count)
|
||||
{
|
||||
tty_insert_flip_string(&sclp_vt220_port, buffer, count);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Called by the SCLP to report incoming event buffers.
|
||||
*/
|
||||
|
|
@ -492,12 +541,13 @@ sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
|
|||
switch (*buffer) {
|
||||
case SCLP_VT220_SESSION_ENDED:
|
||||
case SCLP_VT220_SESSION_STARTED:
|
||||
sclp_vt220_reset_session();
|
||||
break;
|
||||
case SCLP_VT220_SESSION_DATA:
|
||||
/* Send input to line discipline */
|
||||
buffer++;
|
||||
count--;
|
||||
tty_insert_flip_string(&sclp_vt220_port, buffer, count);
|
||||
sclp_vt220_handle_input(buffer, count);
|
||||
tty_flip_buffer_push(&sclp_vt220_port);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -659,6 +659,10 @@ tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb)
|
|||
else
|
||||
/* Normal end. Copy residual count. */
|
||||
rq->rescnt = irb->scsw.cmd.count;
|
||||
} else if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) {
|
||||
/* Interrupt without an outstanding request -> update all */
|
||||
tp->update_flags = TTY_UPDATE_ALL;
|
||||
tty3270_set_timer(tp, 1);
|
||||
}
|
||||
return RAW3270_IO_DONE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include <asm/chsc.h>
|
||||
#include <asm/crw.h>
|
||||
#include <asm/isc.h>
|
||||
#include <asm/ebcdic.h>
|
||||
|
||||
#include "css.h"
|
||||
#include "cio.h"
|
||||
|
|
@ -272,36 +273,6 @@ static void s390_process_res_acc(struct chp_link *link)
|
|||
css_schedule_reprobe();
|
||||
}
|
||||
|
||||
static int
|
||||
__get_chpid_from_lir(void *data)
|
||||
{
|
||||
struct lir {
|
||||
u8 iq;
|
||||
u8 ic;
|
||||
u16 sci;
|
||||
/* incident-node descriptor */
|
||||
u32 indesc[28];
|
||||
/* attached-node descriptor */
|
||||
u32 andesc[28];
|
||||
/* incident-specific information */
|
||||
u32 isinfo[28];
|
||||
} __attribute__ ((packed)) *lir;
|
||||
|
||||
lir = data;
|
||||
if (!(lir->iq&0x80))
|
||||
/* NULL link incident record */
|
||||
return -EINVAL;
|
||||
if (!(lir->indesc[0]&0xc0000000))
|
||||
/* node descriptor not valid */
|
||||
return -EINVAL;
|
||||
if (!(lir->indesc[0]&0x10000000))
|
||||
/* don't handle device-type nodes - FIXME */
|
||||
return -EINVAL;
|
||||
/* Byte 3 contains the chpid. Could also be CTCA, but we don't care */
|
||||
|
||||
return (u16) (lir->indesc[0]&0x000000ff);
|
||||
}
|
||||
|
||||
struct chsc_sei_nt0_area {
|
||||
u8 flags;
|
||||
u8 vf; /* validity flags */
|
||||
|
|
@ -341,22 +312,132 @@ struct chsc_sei {
|
|||
} u;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Node Descriptor as defined in SA22-7204, "Common I/O-Device Commands"
|
||||
*/
|
||||
|
||||
#define ND_VALIDITY_VALID 0
|
||||
#define ND_VALIDITY_OUTDATED 1
|
||||
#define ND_VALIDITY_INVALID 2
|
||||
|
||||
struct node_descriptor {
|
||||
/* Flags. */
|
||||
union {
|
||||
struct {
|
||||
u32 validity:3;
|
||||
u32 reserved:5;
|
||||
} __packed;
|
||||
u8 byte0;
|
||||
} __packed;
|
||||
|
||||
/* Node parameters. */
|
||||
u32 params:24;
|
||||
|
||||
/* Node ID. */
|
||||
char type[6];
|
||||
char model[3];
|
||||
char manufacturer[3];
|
||||
char plant[2];
|
||||
char seq[12];
|
||||
u16 tag;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Link Incident Record as defined in SA22-7202, "ESCON I/O Interface"
|
||||
*/
|
||||
|
||||
#define LIR_IQ_CLASS_INFO 0
|
||||
#define LIR_IQ_CLASS_DEGRADED 1
|
||||
#define LIR_IQ_CLASS_NOT_OPERATIONAL 2
|
||||
|
||||
struct lir {
|
||||
struct {
|
||||
u32 null:1;
|
||||
u32 reserved:3;
|
||||
u32 class:2;
|
||||
u32 reserved2:2;
|
||||
} __packed iq;
|
||||
u32 ic:8;
|
||||
u32 reserved:16;
|
||||
struct node_descriptor incident_node;
|
||||
struct node_descriptor attached_node;
|
||||
u8 reserved2[32];
|
||||
} __packed;
|
||||
|
||||
#define PARAMS_LEN 10 /* PARAMS=xx,xxxxxx */
|
||||
#define NODEID_LEN 35 /* NODEID=tttttt/mdl,mmm.ppssssssssssss,xxxx */
|
||||
|
||||
/* Copy EBCIDC text, convert to ASCII and optionally add delimiter. */
|
||||
static char *store_ebcdic(char *dest, const char *src, unsigned long len,
|
||||
char delim)
|
||||
{
|
||||
memcpy(dest, src, len);
|
||||
EBCASC(dest, len);
|
||||
|
||||
if (delim)
|
||||
dest[len++] = delim;
|
||||
|
||||
return dest + len;
|
||||
}
|
||||
|
||||
/* Format node ID and parameters for output in LIR log message. */
|
||||
static void format_node_data(char *params, char *id, struct node_descriptor *nd)
|
||||
{
|
||||
memset(params, 0, PARAMS_LEN);
|
||||
memset(id, 0, NODEID_LEN);
|
||||
|
||||
if (nd->validity != ND_VALIDITY_VALID) {
|
||||
strncpy(params, "n/a", PARAMS_LEN - 1);
|
||||
strncpy(id, "n/a", NODEID_LEN - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* PARAMS=xx,xxxxxx */
|
||||
snprintf(params, PARAMS_LEN, "%02x,%06x", nd->byte0, nd->params);
|
||||
/* NODEID=tttttt/mdl,mmm.ppssssssssssss,xxxx */
|
||||
id = store_ebcdic(id, nd->type, sizeof(nd->type), '/');
|
||||
id = store_ebcdic(id, nd->model, sizeof(nd->model), ',');
|
||||
id = store_ebcdic(id, nd->manufacturer, sizeof(nd->manufacturer), '.');
|
||||
id = store_ebcdic(id, nd->plant, sizeof(nd->plant), 0);
|
||||
id = store_ebcdic(id, nd->seq, sizeof(nd->seq), ',');
|
||||
sprintf(id, "%04X", nd->tag);
|
||||
}
|
||||
|
||||
static void chsc_process_sei_link_incident(struct chsc_sei_nt0_area *sei_area)
|
||||
{
|
||||
struct chp_id chpid;
|
||||
int id;
|
||||
struct lir *lir = (struct lir *) &sei_area->ccdf;
|
||||
char iuparams[PARAMS_LEN], iunodeid[NODEID_LEN], auparams[PARAMS_LEN],
|
||||
aunodeid[NODEID_LEN];
|
||||
|
||||
CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x)\n",
|
||||
sei_area->rs, sei_area->rsid);
|
||||
if (sei_area->rs != 4)
|
||||
CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x, iq=%02x)\n",
|
||||
sei_area->rs, sei_area->rsid, sei_area->ccdf[0]);
|
||||
|
||||
/* Ignore NULL Link Incident Records. */
|
||||
if (lir->iq.null)
|
||||
return;
|
||||
id = __get_chpid_from_lir(sei_area->ccdf);
|
||||
if (id < 0)
|
||||
CIO_CRW_EVENT(4, "chsc: link incident - invalid LIR\n");
|
||||
else {
|
||||
chp_id_init(&chpid);
|
||||
chpid.id = id;
|
||||
chsc_chp_offline(chpid);
|
||||
|
||||
/* Inform user that a link requires maintenance actions because it has
|
||||
* become degraded or not operational. Note that this log message is
|
||||
* the primary intention behind a Link Incident Record. */
|
||||
|
||||
format_node_data(iuparams, iunodeid, &lir->incident_node);
|
||||
format_node_data(auparams, aunodeid, &lir->attached_node);
|
||||
|
||||
switch (lir->iq.class) {
|
||||
case LIR_IQ_CLASS_DEGRADED:
|
||||
pr_warn("Link degraded: RS=%02x RSID=%04x IC=%02x "
|
||||
"IUPARAMS=%s IUNODEID=%s AUPARAMS=%s AUNODEID=%s\n",
|
||||
sei_area->rs, sei_area->rsid, lir->ic, iuparams,
|
||||
iunodeid, auparams, aunodeid);
|
||||
break;
|
||||
case LIR_IQ_CLASS_NOT_OPERATIONAL:
|
||||
pr_err("Link stopped: RS=%02x RSID=%04x IC=%02x "
|
||||
"IUPARAMS=%s IUNODEID=%s AUPARAMS=%s AUNODEID=%s\n",
|
||||
sei_area->rs, sei_area->rsid, lir->ic, iuparams,
|
||||
iunodeid, auparams, aunodeid);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -540,7 +540,7 @@ int ccw_device_stlck(struct ccw_device *cdev)
|
|||
if (rc)
|
||||
goto out_unlock;
|
||||
/* Perform operation. */
|
||||
cdev->private->state = DEV_STATE_STEAL_LOCK,
|
||||
cdev->private->state = DEV_STATE_STEAL_LOCK;
|
||||
ccw_device_stlck_start(cdev, &data, &buffer[0], &buffer[32]);
|
||||
spin_unlock_irq(sch->lock);
|
||||
/* Wait for operation to finish. */
|
||||
|
|
|
|||
|
|
@ -336,7 +336,6 @@ static int eadm_subchannel_sch_event(struct subchannel *sch, int process)
|
|||
{
|
||||
struct eadm_private *private;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(sch->lock, flags);
|
||||
if (!device_is_registered(&sch->dev))
|
||||
|
|
@ -356,7 +355,7 @@ static int eadm_subchannel_sch_event(struct subchannel *sch, int process)
|
|||
out_unlock:
|
||||
spin_unlock_irqrestore(sch->lock, flags);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct css_device_id eadm_subchannel_ids[] = {
|
||||
|
|
|
|||
|
|
@ -1372,7 +1372,7 @@ static int ap_probe_device_type(struct ap_device *ap_dev)
|
|||
|
||||
/* Wait for the test message to complete. */
|
||||
for (i = 0; i < 6; i++) {
|
||||
mdelay(300);
|
||||
msleep(300);
|
||||
status = __ap_recv(ap_dev->qid, &psmid, reply, 4096);
|
||||
if (status.response_code == AP_RESPONSE_NORMAL &&
|
||||
psmid == 0x0102030405060708ULL)
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ static int zcrypt_pcixcc_mcl(struct ap_device *ap_dev)
|
|||
|
||||
/* Wait for the test message to complete. */
|
||||
for (i = 0; i < 6; i++) {
|
||||
mdelay(300);
|
||||
msleep(300);
|
||||
rc = ap_recv(ap_dev->qid, &psmid, reply, 4096);
|
||||
if (rc == 0 && psmid == 0x0102030405060708ULL)
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -390,10 +390,8 @@ static int qeth_l2_vlan_rx_kill_vid(struct net_device *dev,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int qeth_l2_stop_card(struct qeth_card *card, int recovery_mode)
|
||||
static void qeth_l2_stop_card(struct qeth_card *card, int recovery_mode)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
QETH_DBF_TEXT(SETUP , 2, "stopcard");
|
||||
QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
|
||||
|
||||
|
|
@ -427,7 +425,6 @@ static int qeth_l2_stop_card(struct qeth_card *card, int recovery_mode)
|
|||
qeth_clear_cmd_buffers(&card->read);
|
||||
qeth_clear_cmd_buffers(&card->write);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int qeth_l2_process_inbound_buffer(struct qeth_card *card,
|
||||
|
|
|
|||
|
|
@ -2158,10 +2158,8 @@ static struct qeth_card *qeth_l3_get_card_from_dev(struct net_device *dev)
|
|||
return card ;
|
||||
}
|
||||
|
||||
static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode)
|
||||
static void qeth_l3_stop_card(struct qeth_card *card, int recovery_mode)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
QETH_DBF_TEXT(SETUP, 2, "stopcard");
|
||||
QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
|
||||
|
||||
|
|
@ -2196,7 +2194,6 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode)
|
|||
qeth_clear_cmd_buffers(&card->read);
|
||||
qeth_clear_cmd_buffers(&card->write);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req)
|
|||
break;
|
||||
case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE:
|
||||
zfcp_fsf_link_down_info_eval(req, NULL);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
|
||||
|
|
|
|||
Loading…
Reference in a new issue