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:
Linus Torvalds 2015-08-31 15:11:53 -07:00
commit 9c6a019c6e
94 changed files with 3696 additions and 1368 deletions

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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)

View file

@ -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];
}

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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. */

View file

@ -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[] = {

View file

@ -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)

View file

@ -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;

View file

@ -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,

View file

@ -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;
}
/*

View file

@ -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)