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: (31 commits)
  [S390] disassembler: mark exception causing instructions
  [S390] Enable exception traces by default
  [S390] return address of compat signals
  [S390] sysctl: get rid of dead declaration
  [S390] dasd: fix fixpoint divide exception in define_extent
  [S390] dasd: add sanity check to detect path connection error
  [S390] qdio: fix kernel panic for zfcp 31-bit
  [S390] Add s390x description to Documentation/kdump/kdump.txt
  [S390] Add VMCOREINFO_SYMBOL(high_memory) to vmcoreinfo
  [S390] dasd: fix expiration handling for recovery requests
  [S390] outstanding interrupts vs. smp_send_stop
  [S390] ipc: call generic sys_ipc demultiplexer
  [S390] zcrypt: Fix error return codes.
  [S390] zcrypt: Rework length parameter checking.
  [S390] cleanup trap handling
  [S390] Remove Kerntypes leftovers
  [S390] topology: increase poll frequency if change is anticipated
  [S390] entry[64].S improvements
  [S390] make arch/s390 subdirectories depend on config option
  [S390] kvm: move cmf host id constant out of lowcore
  ...

Fix up conflicts in arch/s390/kernel/{smp.c,topology.c} due to the
sysdev removal clashing with "topology: get rid of ifdefs" which moved
some of that code around.
This commit is contained in:
Linus Torvalds 2012-01-09 08:11:13 -08:00
commit 72f318897e
49 changed files with 1986 additions and 2019 deletions

View file

@ -1718,7 +1718,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
erp->startdev = device;
erp->memdev = device;
erp->magic = default_erp->magic;
erp->expires = 0;
erp->expires = default_erp->expires;
erp->retries = 256;
erp->buildclk = get_clock();
erp->status = DASD_CQR_FILLED;
@ -2363,7 +2363,7 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr)
erp->memdev = device;
erp->block = cqr->block;
erp->magic = cqr->magic;
erp->expires = 0;
erp->expires = cqr->expires;
erp->retries = 256;
erp->buildclk = get_clock();
erp->status = DASD_CQR_FILLED;

View file

@ -705,6 +705,16 @@ struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *base_device)
if (lcu->pav == NO_PAV ||
lcu->flags & (NEED_UAC_UPDATE | UPDATE_PENDING))
return NULL;
if (unlikely(!(private->features.feature[8] & 0x01))) {
/*
* PAV enabled but prefix not, very unlikely
* seems to be a lost pathgroup
* use base device to do IO
*/
DBF_DEV_EVENT(DBF_ERR, base_device, "%s",
"Prefix not enabled with PAV enabled\n");
return NULL;
}
spin_lock_irqsave(&lcu->lock, flags);
alias_device = group->next;

View file

@ -752,24 +752,13 @@ dasd_eckd_cdl_reclen(int recid)
return sizes_trk0[recid];
return LABEL_SIZE;
}
/*
* Generate device unique id that specifies the physical device.
*/
static int dasd_eckd_generate_uid(struct dasd_device *device)
/* create unique id from private structure. */
static void create_uid(struct dasd_eckd_private *private)
{
struct dasd_eckd_private *private;
struct dasd_uid *uid;
int count;
unsigned long flags;
struct dasd_uid *uid;
private = (struct dasd_eckd_private *) device->private;
if (!private)
return -ENODEV;
if (!private->ned || !private->gneq)
return -ENODEV;
uid = &private->uid;
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
memset(uid, 0, sizeof(struct dasd_uid));
memcpy(uid->vendor, private->ned->HDA_manufacturer,
sizeof(uid->vendor) - 1);
@ -792,6 +781,23 @@ static int dasd_eckd_generate_uid(struct dasd_device *device)
private->vdsneq->uit[count]);
}
}
}
/*
* Generate device unique id that specifies the physical device.
*/
static int dasd_eckd_generate_uid(struct dasd_device *device)
{
struct dasd_eckd_private *private;
unsigned long flags;
private = (struct dasd_eckd_private *) device->private;
if (!private)
return -ENODEV;
if (!private->ned || !private->gneq)
return -ENODEV;
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
create_uid(private);
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
return 0;
}
@ -811,6 +817,21 @@ static int dasd_eckd_get_uid(struct dasd_device *device, struct dasd_uid *uid)
return -EINVAL;
}
/*
* compare device UID with data of a given dasd_eckd_private structure
* return 0 for match
*/
static int dasd_eckd_compare_path_uid(struct dasd_device *device,
struct dasd_eckd_private *private)
{
struct dasd_uid device_uid;
create_uid(private);
dasd_eckd_get_uid(device, &device_uid);
return memcmp(&device_uid, &private->uid, sizeof(struct dasd_uid));
}
static void dasd_eckd_fill_rcd_cqr(struct dasd_device *device,
struct dasd_ccw_req *cqr,
__u8 *rcd_buffer,
@ -1005,59 +1026,120 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
int conf_len, conf_data_saved;
int rc;
__u8 lpm, opm;
struct dasd_eckd_private *private;
struct dasd_eckd_private *private, path_private;
struct dasd_path *path_data;
struct dasd_uid *uid;
char print_path_uid[60], print_device_uid[60];
private = (struct dasd_eckd_private *) device->private;
path_data = &device->path_data;
opm = ccw_device_get_path_mask(device->cdev);
lpm = 0x80;
conf_data_saved = 0;
/* get configuration data per operational path */
for (lpm = 0x80; lpm; lpm>>= 1) {
if (lpm & opm) {
rc = dasd_eckd_read_conf_lpm(device, &conf_data,
&conf_len, lpm);
if (rc && rc != -EOPNOTSUPP) { /* -EOPNOTSUPP is ok */
DBF_EVENT_DEVID(DBF_WARNING, device->cdev,
"Read configuration data returned "
"error %d", rc);
return rc;
}
if (conf_data == NULL) {
DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
"No configuration data "
"retrieved");
/* no further analysis possible */
path_data->opm |= lpm;
continue; /* no error */
}
/* save first valid configuration data */
if (!conf_data_saved) {
kfree(private->conf_data);
private->conf_data = conf_data;
private->conf_len = conf_len;
if (dasd_eckd_identify_conf_parts(private)) {
private->conf_data = NULL;
private->conf_len = 0;
kfree(conf_data);
continue;
}
conf_data_saved++;
}
switch (dasd_eckd_path_access(conf_data, conf_len)) {
case 0x02:
path_data->npm |= lpm;
break;
case 0x03:
path_data->ppm |= lpm;
break;
}
path_data->opm |= lpm;
if (conf_data != private->conf_data)
kfree(conf_data);
if (!(lpm & opm))
continue;
rc = dasd_eckd_read_conf_lpm(device, &conf_data,
&conf_len, lpm);
if (rc && rc != -EOPNOTSUPP) { /* -EOPNOTSUPP is ok */
DBF_EVENT_DEVID(DBF_WARNING, device->cdev,
"Read configuration data returned "
"error %d", rc);
return rc;
}
if (conf_data == NULL) {
DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
"No configuration data "
"retrieved");
/* no further analysis possible */
path_data->opm |= lpm;
continue; /* no error */
}
/* save first valid configuration data */
if (!conf_data_saved) {
kfree(private->conf_data);
private->conf_data = conf_data;
private->conf_len = conf_len;
if (dasd_eckd_identify_conf_parts(private)) {
private->conf_data = NULL;
private->conf_len = 0;
kfree(conf_data);
continue;
}
/*
* build device UID that other path data
* can be compared to it
*/
dasd_eckd_generate_uid(device);
conf_data_saved++;
} else {
path_private.conf_data = conf_data;
path_private.conf_len = DASD_ECKD_RCD_DATA_SIZE;
if (dasd_eckd_identify_conf_parts(
&path_private)) {
path_private.conf_data = NULL;
path_private.conf_len = 0;
kfree(conf_data);
continue;
}
if (dasd_eckd_compare_path_uid(
device, &path_private)) {
uid = &path_private.uid;
if (strlen(uid->vduit) > 0)
snprintf(print_path_uid,
sizeof(print_path_uid),
"%s.%s.%04x.%02x.%s",
uid->vendor, uid->serial,
uid->ssid, uid->real_unit_addr,
uid->vduit);
else
snprintf(print_path_uid,
sizeof(print_path_uid),
"%s.%s.%04x.%02x",
uid->vendor, uid->serial,
uid->ssid,
uid->real_unit_addr);
uid = &private->uid;
if (strlen(uid->vduit) > 0)
snprintf(print_device_uid,
sizeof(print_device_uid),
"%s.%s.%04x.%02x.%s",
uid->vendor, uid->serial,
uid->ssid, uid->real_unit_addr,
uid->vduit);
else
snprintf(print_device_uid,
sizeof(print_device_uid),
"%s.%s.%04x.%02x",
uid->vendor, uid->serial,
uid->ssid,
uid->real_unit_addr);
dev_err(&device->cdev->dev,
"Not all channel paths lead to "
"the same device, path %02X leads to "
"device %s instead of %s\n", lpm,
print_path_uid, print_device_uid);
return -EINVAL;
}
path_private.conf_data = NULL;
path_private.conf_len = 0;
}
switch (dasd_eckd_path_access(conf_data, conf_len)) {
case 0x02:
path_data->npm |= lpm;
break;
case 0x03:
path_data->ppm |= lpm;
break;
}
path_data->opm |= lpm;
if (conf_data != private->conf_data)
kfree(conf_data);
}
return 0;
}
@ -1090,12 +1172,61 @@ static int verify_fcx_max_data(struct dasd_device *device, __u8 lpm)
return 0;
}
static int rebuild_device_uid(struct dasd_device *device,
struct path_verification_work_data *data)
{
struct dasd_eckd_private *private;
struct dasd_path *path_data;
__u8 lpm, opm;
int rc;
rc = -ENODEV;
private = (struct dasd_eckd_private *) device->private;
path_data = &device->path_data;
opm = device->path_data.opm;
for (lpm = 0x80; lpm; lpm >>= 1) {
if (!(lpm & opm))
continue;
memset(&data->rcd_buffer, 0, sizeof(data->rcd_buffer));
memset(&data->cqr, 0, sizeof(data->cqr));
data->cqr.cpaddr = &data->ccw;
rc = dasd_eckd_read_conf_immediately(device, &data->cqr,
data->rcd_buffer,
lpm);
if (rc) {
if (rc == -EOPNOTSUPP) /* -EOPNOTSUPP is ok */
continue;
DBF_EVENT_DEVID(DBF_WARNING, device->cdev,
"Read configuration data "
"returned error %d", rc);
break;
}
memcpy(private->conf_data, data->rcd_buffer,
DASD_ECKD_RCD_DATA_SIZE);
if (dasd_eckd_identify_conf_parts(private)) {
rc = -ENODEV;
} else /* first valid path is enough */
break;
}
if (!rc)
rc = dasd_eckd_generate_uid(device);
return rc;
}
static void do_path_verification_work(struct work_struct *work)
{
struct path_verification_work_data *data;
struct dasd_device *device;
struct dasd_eckd_private path_private;
struct dasd_uid *uid;
__u8 path_rcd_buf[DASD_ECKD_RCD_DATA_SIZE];
__u8 lpm, opm, npm, ppm, epm;
unsigned long flags;
char print_uid[60];
int rc;
data = container_of(work, struct path_verification_work_data, worker);
@ -1112,64 +1243,129 @@ static void do_path_verification_work(struct work_struct *work)
ppm = 0;
epm = 0;
for (lpm = 0x80; lpm; lpm >>= 1) {
if (lpm & data->tbvpm) {
memset(data->rcd_buffer, 0, sizeof(data->rcd_buffer));
memset(&data->cqr, 0, sizeof(data->cqr));
data->cqr.cpaddr = &data->ccw;
rc = dasd_eckd_read_conf_immediately(device, &data->cqr,
data->rcd_buffer,
lpm);
if (!rc) {
switch (dasd_eckd_path_access(data->rcd_buffer,
DASD_ECKD_RCD_DATA_SIZE)) {
case 0x02:
npm |= lpm;
break;
case 0x03:
ppm |= lpm;
break;
}
opm |= lpm;
} else if (rc == -EOPNOTSUPP) {
DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
"path verification: No configuration "
"data retrieved");
opm |= lpm;
} else if (rc == -EAGAIN) {
DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
if (!(lpm & data->tbvpm))
continue;
memset(&data->rcd_buffer, 0, sizeof(data->rcd_buffer));
memset(&data->cqr, 0, sizeof(data->cqr));
data->cqr.cpaddr = &data->ccw;
rc = dasd_eckd_read_conf_immediately(device, &data->cqr,
data->rcd_buffer,
lpm);
if (!rc) {
switch (dasd_eckd_path_access(data->rcd_buffer,
DASD_ECKD_RCD_DATA_SIZE)
) {
case 0x02:
npm |= lpm;
break;
case 0x03:
ppm |= lpm;
break;
}
opm |= lpm;
} else if (rc == -EOPNOTSUPP) {
DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
"path verification: No configuration "
"data retrieved");
opm |= lpm;
} else if (rc == -EAGAIN) {
DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
"path verification: device is stopped,"
" try again later");
epm |= lpm;
} else {
dev_warn(&device->cdev->dev,
"Reading device feature codes failed "
"(rc=%d) for new path %x\n", rc, lpm);
continue;
}
if (verify_fcx_max_data(device, lpm)) {
epm |= lpm;
} else {
dev_warn(&device->cdev->dev,
"Reading device feature codes failed "
"(rc=%d) for new path %x\n", rc, lpm);
continue;
}
if (verify_fcx_max_data(device, lpm)) {
opm &= ~lpm;
npm &= ~lpm;
ppm &= ~lpm;
continue;
}
/*
* save conf_data for comparison after
* rebuild_device_uid may have changed
* the original data
*/
memcpy(&path_rcd_buf, data->rcd_buffer,
DASD_ECKD_RCD_DATA_SIZE);
path_private.conf_data = (void *) &path_rcd_buf;
path_private.conf_len = DASD_ECKD_RCD_DATA_SIZE;
if (dasd_eckd_identify_conf_parts(&path_private)) {
path_private.conf_data = NULL;
path_private.conf_len = 0;
continue;
}
/*
* compare path UID with device UID only if at least
* one valid path is left
* in other case the device UID may have changed and
* the first working path UID will be used as device UID
*/
if (device->path_data.opm &&
dasd_eckd_compare_path_uid(device, &path_private)) {
/*
* the comparison was not successful
* rebuild the device UID with at least one
* known path in case a z/VM hyperswap command
* has changed the device
*
* after this compare again
*
* if either the rebuild or the recompare fails
* the path can not be used
*/
if (rebuild_device_uid(device, data) ||
dasd_eckd_compare_path_uid(
device, &path_private)) {
uid = &path_private.uid;
if (strlen(uid->vduit) > 0)
snprintf(print_uid, sizeof(print_uid),
"%s.%s.%04x.%02x.%s",
uid->vendor, uid->serial,
uid->ssid, uid->real_unit_addr,
uid->vduit);
else
snprintf(print_uid, sizeof(print_uid),
"%s.%s.%04x.%02x",
uid->vendor, uid->serial,
uid->ssid,
uid->real_unit_addr);
dev_err(&device->cdev->dev,
"The newly added channel path %02X "
"will not be used because it leads "
"to a different device %s\n",
lpm, print_uid);
opm &= ~lpm;
npm &= ~lpm;
ppm &= ~lpm;
continue;
}
}
/*
* There is a small chance that a path is lost again between
* above path verification and the following modification of
* the device opm mask. We could avoid that race here by using
* yet another path mask, but we rather deal with this unlikely
* situation in dasd_start_IO.
*/
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
if (!device->path_data.opm && opm) {
device->path_data.opm = opm;
dasd_generic_path_operational(device);
} else
device->path_data.opm |= opm;
device->path_data.npm |= npm;
device->path_data.ppm |= ppm;
device->path_data.tbvpm |= epm;
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
}
/*
* There is a small chance that a path is lost again between
* above path verification and the following modification of
* the device opm mask. We could avoid that race here by using
* yet another path mask, but we rather deal with this unlikely
* situation in dasd_start_IO.
*/
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
if (!device->path_data.opm && opm) {
device->path_data.opm = opm;
dasd_generic_path_operational(device);
} else
device->path_data.opm |= opm;
device->path_data.npm |= npm;
device->path_data.ppm |= ppm;
device->path_data.tbvpm |= epm;
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
dasd_put_device(device);
if (data->isglobal)
@ -1441,11 +1637,6 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
device->default_expires = value;
}
/* Generate device unique id */
rc = dasd_eckd_generate_uid(device);
if (rc)
goto out_err1;
dasd_eckd_get_uid(device, &temp_uid);
if (temp_uid.type == UA_BASE_DEVICE) {
block = dasd_alloc_block();
@ -2206,7 +2397,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
sizeof(struct PFX_eckd_data));
} else {
if (define_extent(ccw++, cqr->data, first_trk,
last_trk, cmd, startdev) == -EAGAIN) {
last_trk, cmd, basedev) == -EAGAIN) {
/* Clock not in sync and XRC is enabled.
* Try again later.
*/

View file

@ -22,12 +22,9 @@
static struct kmem_cache *qdio_q_cache;
static struct kmem_cache *qdio_aob_cache;
struct qaob *qdio_allocate_aob()
struct qaob *qdio_allocate_aob(void)
{
struct qaob *aob;
aob = kmem_cache_zalloc(qdio_aob_cache, GFP_ATOMIC);
return aob;
return kmem_cache_zalloc(qdio_aob_cache, GFP_ATOMIC);
}
EXPORT_SYMBOL_GPL(qdio_allocate_aob);
@ -180,7 +177,8 @@ static void setup_queues(struct qdio_irq *irq_ptr,
setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i);
q->is_input_q = 1;
q->u.in.queue_start_poll = qdio_init->queue_start_poll[i];
q->u.in.queue_start_poll = qdio_init->queue_start_poll_array ?
qdio_init->queue_start_poll_array[i] : NULL;
setup_storage_lists(q, irq_ptr, input_sbal_array, i);
input_sbal_array += QDIO_MAX_BUFFERS_PER_Q;

View file

@ -56,11 +56,6 @@
#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */
#define PCIXCC_MAX_XCRB_MESSAGE_SIZE (12*1024)
#define PCIXCC_MAX_XCRB_RESPONSE_SIZE PCIXCC_MAX_XCRB_MESSAGE_SIZE
#define PCIXCC_MAX_XCRB_DATA_SIZE (11*1024)
#define PCIXCC_MAX_XCRB_REPLY_SIZE (5*1024)
#define PCIXCC_MAX_RESPONSE_SIZE PCIXCC_MAX_XCRB_RESPONSE_SIZE
#define PCIXCC_CLEANUP_TIME (15*HZ)
@ -265,7 +260,7 @@ static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev,
* @ap_msg: pointer to AP message
* @xcRB: pointer to user input data
*
* Returns 0 on success or -EFAULT.
* Returns 0 on success or -EFAULT, -EINVAL.
*/
struct type86_fmt2_msg {
struct type86_hdr hdr;
@ -295,19 +290,12 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
CEIL4(xcRB->request_control_blk_length) +
xcRB->request_data_length;
if (ap_msg->length > PCIXCC_MAX_XCRB_MESSAGE_SIZE)
return -EFAULT;
if (CEIL4(xcRB->reply_control_blk_length) > PCIXCC_MAX_XCRB_REPLY_SIZE)
return -EFAULT;
if (CEIL4(xcRB->reply_data_length) > PCIXCC_MAX_XCRB_DATA_SIZE)
return -EFAULT;
replylen = CEIL4(xcRB->reply_control_blk_length) +
CEIL4(xcRB->reply_data_length) +
sizeof(struct type86_fmt2_msg);
if (replylen > PCIXCC_MAX_XCRB_RESPONSE_SIZE) {
xcRB->reply_control_blk_length = PCIXCC_MAX_XCRB_RESPONSE_SIZE -
(sizeof(struct type86_fmt2_msg) +
CEIL4(xcRB->reply_data_length));
}
return -EINVAL;
replylen = sizeof(struct type86_fmt2_msg) +
CEIL4(xcRB->reply_control_blk_length) +
xcRB->reply_data_length;
if (replylen > PCIXCC_MAX_XCRB_MESSAGE_SIZE)
return -EINVAL;
/* prepare type6 header */
msg->hdr = static_type6_hdrX;
@ -326,7 +314,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
return -EFAULT;
if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) >
xcRB->request_control_blk_length)
return -EFAULT;
return -EINVAL;
function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len;
memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code));
@ -678,7 +666,7 @@ static void zcrypt_pcixcc_receive(struct ap_device *ap_dev,
break;
case PCIXCC_RESPONSE_TYPE_XCRB:
length = t86r->fmt2.offset2 + t86r->fmt2.count2;
length = min(PCIXCC_MAX_XCRB_RESPONSE_SIZE, length);
length = min(PCIXCC_MAX_XCRB_MESSAGE_SIZE, length);
memcpy(msg->message, reply->message, length);
break;
default:
@ -1043,7 +1031,7 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
struct zcrypt_device *zdev;
int rc = 0;
zdev = zcrypt_device_alloc(PCIXCC_MAX_RESPONSE_SIZE);
zdev = zcrypt_device_alloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE);
if (!zdev)
return -ENOMEM;
zdev->ap_dev = ap_dev;

View file

@ -4552,7 +4552,7 @@ static int qeth_qdio_establish(struct qeth_card *card)
init_data.no_output_qs = card->qdio.no_out_queues;
init_data.input_handler = card->discipline.input_handler;
init_data.output_handler = card->discipline.output_handler;
init_data.queue_start_poll = queue_start_poll;
init_data.queue_start_poll_array = queue_start_poll;
init_data.int_parm = (unsigned long) card;
init_data.input_sbal_addr_array = (void **) in_sbal_ptrs;
init_data.output_sbal_addr_array = (void **) out_sbal_ptrs;