mirror of
https://github.com/torvalds/linux.git
synced 2026-09-26 10:02:02 +02:00
s390 fixes for 7.3-rc5
- Fix several bugs in PCI error recovery SCLP reporting: don't report success on skipped recovery, report errors when no pdev is associated, add missing device lock, and fix struct pci_dev reference leak in zpci_report_status() - Fix several bugs in CIO code: fix use of invalid SCHIB data, guard PMCW field accesses, check device number valid bit in PMWC before accessing other fields, and fix NULL pointer dereference in ccw_device_get_util_str() - Fix virtual vs physical address confusion in channel measurement facility code on kernels with CONFIG_RANDOMIZE_IDENTITY_BASE=y - Fix couple of bugs in s390dbf: fix copy of failed static debug areas, skip view registration on failure, and reject NULL pointer in debug_dump() - Fix sriov_numvfs attribute name in zPCI documentation - Fix typos in comments -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEECMNfWEw3SLnmiLkZIg7DeRspbsIFAmq2V1AACgkQIg7DeRsp bsJ7zg/7BrnPs0WyKv9NZvVUudYbz3nUIAleJo6HcDK2SUDr+EX3W4U7OjsXL6Fv H76hx5AqF6ddtUOJ2uevCAb3PKm0eA7vmK9YiERAclrBA+tWGW0xBwCqqyc84k38 CPxOBr87Ae1jIIcfDxfBWujtKTFi/4BpSvKvKgg3mnd2egny4UnHnABx5ZcClEee p6aVjCKycQFHwNLMoJA1BxvGSpcXdiKXbm6VRJ4gCaBnVuzkLUv1ZMp/Pi1fWVbV E1AEztZ/03Tfry51q7wQLv6wD5lR3Z/Py2vZ4YIbelQwVMAMI+rFtgd5oFfo9qkF gcFJ+faE9m0E/nsoaaVCaa2Ja4+hV/vZ5ik0bq1ljEqEvInaa2XTuxNAljId351Y JrLvCdaip0FkMNMqEym0iydMAlpc491GAhzNrT3yvq6t03VVpxprPPA6VIwHg+zk UBMP+QdxtnaV8AAUzDD9E255d88N4DECBICUgf1XjFm/I7xLJFWyUvbzcqNn9VnY EGVBOeQmoByhCL9lN0+nzEM1sgT+hQB/C3WmLqiuLxrxjnc8dVr8rVHcPXFgARPw Ht3W9jxdTdl4VBwckOWmbvG4L6spXFLdEzI51cP46L1RKWhFjLl/6RoY8fUHf4Vz YnHutQevSoPI2D6G4v8K1FBz9wclxCojBPbXCmevfbL9B4ChPoQ= =r3uP -----END PGP SIGNATURE----- Merge tag 's390-7.3-4' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux Pull s390 fixes from Heiko Carstens: - Fix several bugs in PCI error recovery SCLP reporting: don't report success on skipped recovery, report errors when no pdev is associated, add missing device lock, and fix struct pci_dev reference leak in zpci_report_status() - Fix several bugs in CIO code: fix use of invalid SCHIB data, guard PMCW field accesses, check device number valid bit in PMWC before accessing other fields, and fix NULL pointer dereference in ccw_device_get_util_str() - Fix virtual vs physical address confusion in channel measurement facility code on kernels with CONFIG_RANDOMIZE_IDENTITY_BASE=y - Fix couple of bugs in s390dbf: fix copy of failed static debug areas, skip view registration on failure, and reject NULL pointer in debug_dump() - Fix sriov_numvfs attribute name in zPCI documentation - Fix typos in comments * tag 's390-7.3-4' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: s390/cio: Fix NULL pointer dereference in ccw_device_get_util_str() s390/debug: Fix NULL pointer dereference in debug_info_copy() s390/debug: Do not register views for failed static debug areas s390/debug: Reject NULL debug info in debug_dump() s390/cmf: Fix virtual vs physical address confusion s390/pci: Don't report recovery success on skipped recovery s390/pci: Report SCLP status on error events when no pdev is associated s390/pci: Fix missing device lock in zpci_report_status() s390/pci: Fix leak of struct pci_dev reference in zpci_report_status() s390/cio: Guard PMCW field accesses with dnv check s390/cio: Check pmcw.dnv before pmcw.ena in I/O entry points s390/cio: Fix cio_update_schib() to not cache invalid schib s390/pci/docs: Fix sriov_numvfs attribute name s390: Fix typos in comments
This commit is contained in:
commit
547463efb9
|
|
@ -67,7 +67,7 @@ Entries specific to zPCI functions and entries that hold zPCI information.
|
|||
|
||||
A physical function that currently supports a virtual function cannot be
|
||||
powered off until all virtual functions are removed with:
|
||||
echo 0 > /sys/bus/pci/devices/DDDD:BB:dd.f/sriov_numvf
|
||||
echo 0 > /sys/bus/pci/devices/DDDD:BB:dd.f/sriov_numvfs
|
||||
|
||||
* /sys/bus/pci/devices/DDDD:BB:dd.f/:
|
||||
|
||||
|
|
|
|||
|
|
@ -460,7 +460,11 @@ static int VNAME(var, active_entries)[EARLY_AREAS] __initdata
|
|||
#define __REGISTER_STATIC_DEBUG_INFO(var, name, pages, areas, view) \
|
||||
static int __init VNAME(var, reg)(void) \
|
||||
{ \
|
||||
debug_register_static(&var, (pages), (areas)); \
|
||||
int rc; \
|
||||
\
|
||||
rc = debug_register_static(&var, (pages), (areas)); \
|
||||
if (rc) \
|
||||
return rc; \
|
||||
debug_register_view(&var, (view)); \
|
||||
return 0; \
|
||||
} \
|
||||
|
|
@ -493,7 +497,7 @@ static debug_info_t __refdata var = \
|
|||
static debug_info_t __used __section(".s390dbf_info") *VNAME(var, info) = &var; \
|
||||
__REGISTER_STATIC_DEBUG_INFO(var, name, pages, nr_areas, view)
|
||||
|
||||
void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas);
|
||||
int debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas);
|
||||
|
||||
#endif /* MODULE */
|
||||
|
||||
|
|
|
|||
|
|
@ -434,7 +434,8 @@ static debug_info_t *debug_info_copy(debug_info_t *in, int mode)
|
|||
debug_info_free(rc);
|
||||
} while (1);
|
||||
|
||||
if (mode == NO_AREAS)
|
||||
/* debug_register_static() failure leaves areas NULL, bounds intact */
|
||||
if (mode == NO_AREAS || !in->areas)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < in->nr_areas; i++) {
|
||||
|
|
@ -823,6 +824,9 @@ ssize_t debug_dump(debug_info_t *id, struct debug_view *view,
|
|||
file_private_info_t *p_info;
|
||||
size_t size, offset = 0;
|
||||
|
||||
if (!id)
|
||||
return -EINVAL;
|
||||
|
||||
/* Need space for '\0' byte */
|
||||
if (buf_size < 1)
|
||||
return 0;
|
||||
|
|
@ -950,8 +954,12 @@ EXPORT_SYMBOL(debug_register);
|
|||
*
|
||||
* Note: This function is called automatically via an initcall generated by
|
||||
* DEFINE_STATIC_DEBUG_INFO.
|
||||
*
|
||||
* Return:
|
||||
* - 0 on success
|
||||
* - negative error code on failure
|
||||
*/
|
||||
void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
|
||||
int debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
|
||||
{
|
||||
unsigned long flags;
|
||||
debug_info_t *copy;
|
||||
|
|
@ -959,7 +967,7 @@ void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
|
|||
if (!initialized) {
|
||||
pr_err("Tried to register debug feature %s too early\n",
|
||||
id->name);
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
debug_get_param(id->name, &id->level, &pages_per_area, false);
|
||||
|
|
@ -975,7 +983,7 @@ void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
|
|||
id->active_entries = NULL;
|
||||
raw_spin_unlock_irqrestore(&id->lock, flags);
|
||||
|
||||
return;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Replace static trace area with dynamic copy. */
|
||||
|
|
@ -993,6 +1001,8 @@ void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
|
|||
mutex_lock(&debug_mutex);
|
||||
_debug_register(id);
|
||||
mutex_unlock(&debug_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove debugfs entries. */
|
||||
|
|
|
|||
|
|
@ -226,6 +226,7 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev,
|
|||
device_lock(&pdev->dev);
|
||||
if (pdev->error_state == pci_channel_io_perm_failure) {
|
||||
ers_res = PCI_ERS_RESULT_DISCONNECT;
|
||||
status_str = "skipped (permanent failure)";
|
||||
goto out_unlock;
|
||||
}
|
||||
pdev->error_state = pci_channel_io_frozen;
|
||||
|
|
@ -297,8 +298,8 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev,
|
|||
driver->err_handler->resume(pdev);
|
||||
pci_uevent_ers(pdev, PCI_ERS_RESULT_RECOVERED);
|
||||
out_unlock:
|
||||
zpci_report_status(zdev, pdev, "recovery", status_str);
|
||||
device_unlock(&pdev->dev);
|
||||
zpci_report_status(zdev, "recovery", status_str);
|
||||
|
||||
return ers_res;
|
||||
}
|
||||
|
|
@ -361,8 +362,10 @@ static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
|
|||
|
||||
__zpci_event_print_error(pdev, ccdf);
|
||||
|
||||
if (!pdev)
|
||||
if (!pdev) {
|
||||
zpci_report_status(zdev, NULL, "error event", "no pdev bound");
|
||||
goto no_pdev;
|
||||
}
|
||||
|
||||
switch (ccdf->pec) {
|
||||
case 0x002a: /* Error event concerns FMB */
|
||||
|
|
|
|||
|
|
@ -87,9 +87,23 @@ static struct debug_view debug_log_view = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static ssize_t zpci_report_pdev(struct pci_dev *pdev, char *buf, size_t size)
|
||||
{
|
||||
struct pci_driver *driver;
|
||||
const char *start = buf;
|
||||
char *end = buf + size;
|
||||
|
||||
device_lock_assert(&pdev->dev);
|
||||
buf += scnprintf(buf, end - buf, "state: %s\n", zpci_state_str(pdev->error_state));
|
||||
driver = to_pci_driver(pdev->dev.driver);
|
||||
buf += scnprintf(buf, end - buf, "driver: %s\n", (driver) ? driver->name : "n/a");
|
||||
return buf - start;
|
||||
}
|
||||
|
||||
/**
|
||||
* zpci_report_status - Report the status of operations on a PCI device
|
||||
* @zdev: The PCI device for which to report status
|
||||
* @zdev: The zPCI device for which to report status
|
||||
* @pdev: The PCI device associated with the zdev if any, NULL otherwise
|
||||
* @operation: A string representing the operation reported
|
||||
* @status: A string representing the status of the operation
|
||||
*
|
||||
|
|
@ -103,15 +117,14 @@ static struct debug_view debug_log_view = {
|
|||
*
|
||||
* Return: 0 on success an error code < 0 otherwise.
|
||||
*/
|
||||
int zpci_report_status(struct zpci_dev *zdev, const char *operation, const char *status)
|
||||
int zpci_report_status(struct zpci_dev *zdev, struct pci_dev *pdev,
|
||||
const char *operation, const char *status)
|
||||
{
|
||||
struct zpci_report_error *report;
|
||||
struct pci_driver *driver = NULL;
|
||||
struct pci_dev *pdev = NULL;
|
||||
char *buf, *end;
|
||||
int ret;
|
||||
|
||||
if (!zdev || !zdev->zbus)
|
||||
if (!zdev)
|
||||
return -ENODEV;
|
||||
|
||||
/* Protected virtualization hosts get nothing from us */
|
||||
|
|
@ -121,18 +134,13 @@ int zpci_report_status(struct zpci_dev *zdev, const char *operation, const char
|
|||
report = (void *)get_zeroed_page(GFP_KERNEL);
|
||||
if (!report)
|
||||
return -ENOMEM;
|
||||
if (zdev->zbus->bus)
|
||||
pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn);
|
||||
if (pdev)
|
||||
driver = to_pci_driver(pdev->dev.driver);
|
||||
|
||||
buf = report->data.log_data;
|
||||
end = report->data.log_data + ZPCI_REPORT_DATA_SIZE;
|
||||
buf += scnprintf(buf, end - buf, "report: %s\n", operation);
|
||||
buf += scnprintf(buf, end - buf, "status: %s\n", status);
|
||||
buf += scnprintf(buf, end - buf, "state: %s\n",
|
||||
(pdev) ? zpci_state_str(pdev->error_state) : "n/a");
|
||||
buf += scnprintf(buf, end - buf, "driver: %s\n", (driver) ? driver->name : "n/a");
|
||||
if (pdev)
|
||||
buf += zpci_report_pdev(pdev, buf, end - buf);
|
||||
ret = debug_dump(pci_debug_msg_id, &debug_log_view, buf, end - buf, true);
|
||||
if (ret < 0)
|
||||
pr_err("Reading PCI debug messages failed with code %d\n", ret);
|
||||
|
|
|
|||
|
|
@ -8,9 +8,11 @@
|
|||
*/
|
||||
#ifndef __S390_PCI_REPORT_H
|
||||
#define __S390_PCI_REPORT_H
|
||||
#include <linux/pci.h>
|
||||
|
||||
struct zpci_dev;
|
||||
|
||||
int zpci_report_status(struct zpci_dev *zdev, const char *operation, const char *status);
|
||||
int zpci_report_status(struct zpci_dev *zdev, struct pci_dev *pdev,
|
||||
const char *operation, const char *status);
|
||||
|
||||
#endif /* __S390_PCI_REPORT_H */
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ dasd_3990_erp_int_req(struct dasd_ccw_req * erp)
|
|||
|
||||
/* first time set initial retry counter and erp_function */
|
||||
/* and retry once without blocking queue */
|
||||
/* (this enables easier enqueing of the cqr) */
|
||||
/* (this enables easier enqueuing of the cqr) */
|
||||
if (erp->function != dasd_3990_erp_int_req) {
|
||||
|
||||
erp->retries = 256;
|
||||
|
|
@ -302,7 +302,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
|
|||
|
||||
/* first time set initial retry counter and erp_function */
|
||||
/* and retry once without waiting for state change pending */
|
||||
/* interrupt (this enables easier enqueing of the cqr) */
|
||||
/* interrupt (this enables easier enqueuing of the cqr) */
|
||||
if (erp->function != dasd_3990_erp_action_4) {
|
||||
|
||||
DBF_DEV_EVENT(DBF_INFO, device, "%s",
|
||||
|
|
@ -1078,7 +1078,7 @@ dasd_3990_erp_bus_out(struct dasd_ccw_req * erp)
|
|||
|
||||
/* first time set initial retry counter and erp_function */
|
||||
/* and retry once without blocking queue */
|
||||
/* (this enables easier enqueing of the cqr) */
|
||||
/* (this enables easier enqueuing of the cqr) */
|
||||
if (erp->function != dasd_3990_erp_bus_out) {
|
||||
erp->retries = 256;
|
||||
erp->function = dasd_3990_erp_bus_out;
|
||||
|
|
|
|||
|
|
@ -2060,7 +2060,7 @@ dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav,
|
|||
}
|
||||
|
||||
/*
|
||||
* Valide storage server of current device.
|
||||
* Valid storage server of current device.
|
||||
*/
|
||||
static int dasd_eckd_validate_server(struct dasd_device *device,
|
||||
unsigned long flags)
|
||||
|
|
@ -5672,7 +5672,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev,
|
|||
char *dst;
|
||||
|
||||
/*
|
||||
* raw track access needs to be mutiple of 64k and on 64k boundary
|
||||
* raw track access needs to be multiple of 64k and on 64k boundary
|
||||
* For read requests we can fix an incorrect alignment by padding
|
||||
* the request with dummy pages.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -420,7 +420,7 @@ struct raw3270_ua { /* Query Reply structure for Usable Area */
|
|||
char flags0;
|
||||
char flags1;
|
||||
short w; /* Width of usable area */
|
||||
short h; /* Heigth of usavle area */
|
||||
short h; /* Height of usavle area */
|
||||
char units; /* 0x00:in; 0x01:mm */
|
||||
int xr;
|
||||
int yr;
|
||||
|
|
|
|||
|
|
@ -444,7 +444,7 @@ static int vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv)
|
|||
spin_unlock_bh(&priv->priv_lock);
|
||||
/* An rc of 5 indicates that the record was bigger than
|
||||
* the buffer, which is OK for us. A 9 indicates that the
|
||||
* record was purged befor we could receive it.
|
||||
* record was purged before we could receive it.
|
||||
*/
|
||||
if (rc == 5)
|
||||
rc = 0;
|
||||
|
|
|
|||
|
|
@ -78,6 +78,9 @@ u8 chp_get_sch_opm(struct subchannel *sch)
|
|||
int opm;
|
||||
int i;
|
||||
|
||||
if (!sch->schib.pmcw.dnv)
|
||||
return 0;
|
||||
|
||||
opm = 0;
|
||||
chp_id_init(&chpid);
|
||||
for (i = 0; i < 8; i++) {
|
||||
|
|
|
|||
|
|
@ -453,7 +453,8 @@ EXPORT_SYMBOL_GPL(cio_commit_config);
|
|||
/**
|
||||
* cio_update_schib - Perform stsch and update schib if subchannel is valid.
|
||||
* @sch: subchannel on which to perform stsch
|
||||
* Return zero on success, -ENODEV otherwise.
|
||||
* Return zero on success, -ENODEV if the subchannel is not operational,
|
||||
* -EACCES if the subchannel has no valid device.
|
||||
*/
|
||||
int cio_update_schib(struct subchannel *sch)
|
||||
{
|
||||
|
|
@ -462,10 +463,12 @@ int cio_update_schib(struct subchannel *sch)
|
|||
if (stsch(sch->schid, &schib))
|
||||
return -ENODEV;
|
||||
|
||||
memcpy(&sch->schib, &schib, sizeof(schib));
|
||||
|
||||
if (!css_sch_is_valid(&schib))
|
||||
if (!css_sch_is_valid(&schib)) {
|
||||
memset(&sch->schib, 0, sizeof(sch->schib));
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
memcpy(&sch->schib, &schib, sizeof(schib));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/mod_devicetable.h>
|
||||
#include <asm/chpid.h>
|
||||
#include <asm/cio.h>
|
||||
#include <asm/dma-types.h>
|
||||
#include <asm/fcx.h>
|
||||
#include <asm/schid.h>
|
||||
#include <asm/tpi.h>
|
||||
|
|
@ -49,7 +50,7 @@ struct pmcw {
|
|||
|
||||
/* Target SCHIB configuration. */
|
||||
struct schib_config {
|
||||
u64 mba;
|
||||
dma64_t mba;
|
||||
u32 intparm;
|
||||
u16 mbi;
|
||||
u32 isc:3;
|
||||
|
|
@ -66,7 +67,7 @@ struct schib_config {
|
|||
struct schib {
|
||||
struct pmcw pmcw; /* path management control word */
|
||||
union scsw scsw; /* subchannel status word */
|
||||
__u64 mba; /* measurement block address */
|
||||
dma64_t mba; /* measurement block address */
|
||||
__u8 mda[4]; /* model dependent area */
|
||||
} __attribute__ ((packed,aligned(4)));
|
||||
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc,
|
|||
sch->config.mbfc = mbfc;
|
||||
/* address can be either a block address or a block index */
|
||||
if (mbfc)
|
||||
sch->config.mba = address;
|
||||
sch->config.mba = address ? virt_to_dma64((void *)address) : 0;
|
||||
else
|
||||
sch->config.mbi = address;
|
||||
|
||||
|
|
|
|||
|
|
@ -922,7 +922,7 @@ static int ccw_device_move_to_sch(struct ccw_device *cdev,
|
|||
|
||||
if (!sch_is_pseudo_sch(old_sch)) {
|
||||
spin_lock_irq(&old_sch->lock);
|
||||
old_enabled = old_sch->schib.pmcw.ena;
|
||||
old_enabled = old_sch->schib.pmcw.dnv && old_sch->schib.pmcw.ena;
|
||||
rc = 0;
|
||||
if (old_enabled)
|
||||
rc = cio_disable_subchannel(old_sch);
|
||||
|
|
@ -941,7 +941,7 @@ static int ccw_device_move_to_sch(struct ccw_device *cdev,
|
|||
CIO_MSG_EVENT(0, "device_move(0.%x.%04x,0.%x.%04x)=%d\n",
|
||||
cdev->private->dev_id.ssid,
|
||||
cdev->private->dev_id.devno, sch->schid.ssid,
|
||||
sch->schib.pmcw.dev, rc);
|
||||
sch->schid.sch_no, rc);
|
||||
if (old_enabled) {
|
||||
/* Try to re-enable the old subchannel. */
|
||||
spin_lock_irq(&old_sch->lock);
|
||||
|
|
@ -1207,7 +1207,7 @@ static void io_subchannel_quiesce(struct subchannel *sch)
|
|||
cdev = sch_get_cdev(sch);
|
||||
if (cio_is_console(sch->schid))
|
||||
goto out_unlock;
|
||||
if (!sch->schib.pmcw.ena)
|
||||
if (!sch->schib.pmcw.dnv || !sch->schib.pmcw.ena)
|
||||
goto out_unlock;
|
||||
ret = cio_disable_subchannel(sch);
|
||||
if (ret != -EBUSY)
|
||||
|
|
@ -1254,7 +1254,8 @@ static int recovery_check(struct device *dev, void *data)
|
|||
switch (cdev->private->state) {
|
||||
case DEV_STATE_ONLINE:
|
||||
sch = to_subchannel(cdev->dev.parent);
|
||||
if ((sch->schib.pmcw.pam & sch->opm) == sch->vpm)
|
||||
if (sch->schib.pmcw.dnv &&
|
||||
(sch->schib.pmcw.pam & sch->opm) == sch->vpm)
|
||||
break;
|
||||
fallthrough;
|
||||
case DEV_STATE_DISCONNECTED:
|
||||
|
|
|
|||
|
|
@ -170,6 +170,9 @@ __recover_lost_chpids(struct subchannel *sch, int old_lpm)
|
|||
int mask, i;
|
||||
struct chp_id chpid;
|
||||
|
||||
if (!sch->schib.pmcw.dnv)
|
||||
return;
|
||||
|
||||
chp_id_init(&chpid);
|
||||
for (i = 0; i<8; i++) {
|
||||
mask = 0x80 >> i;
|
||||
|
|
|
|||
|
|
@ -142,6 +142,8 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
|
|||
if (!cdev || !cdev->dev.parent)
|
||||
return -ENODEV;
|
||||
sch = to_subchannel(cdev->dev.parent);
|
||||
if (!sch->schib.pmcw.dnv)
|
||||
return -ENODEV;
|
||||
if (!sch->schib.pmcw.ena)
|
||||
return -EINVAL;
|
||||
if (cdev->private->state == DEV_STATE_NOT_OPER)
|
||||
|
|
@ -198,6 +200,8 @@ int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
|
|||
if (!cdev || !cdev->dev.parent)
|
||||
return -ENODEV;
|
||||
sch = to_subchannel(cdev->dev.parent);
|
||||
if (!sch->schib.pmcw.dnv)
|
||||
return -ENODEV;
|
||||
if (!sch->schib.pmcw.ena)
|
||||
return -EINVAL;
|
||||
if (cdev->private->state == DEV_STATE_NOT_OPER)
|
||||
|
|
@ -379,6 +383,8 @@ int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
|
|||
if (!cdev || !cdev->dev.parent)
|
||||
return -ENODEV;
|
||||
sch = to_subchannel(cdev->dev.parent);
|
||||
if (!sch->schib.pmcw.dnv)
|
||||
return -ENODEV;
|
||||
if (!sch->schib.pmcw.ena)
|
||||
return -EINVAL;
|
||||
if (cdev->private->state == DEV_STATE_NOT_OPER)
|
||||
|
|
@ -413,6 +419,8 @@ int ccw_device_resume(struct ccw_device *cdev)
|
|||
if (!cdev || !cdev->dev.parent)
|
||||
return -ENODEV;
|
||||
sch = to_subchannel(cdev->dev.parent);
|
||||
if (!sch->schib.pmcw.dnv)
|
||||
return -ENODEV;
|
||||
if (!sch->schib.pmcw.ena)
|
||||
return -EINVAL;
|
||||
if (cdev->private->state == DEV_STATE_NOT_OPER)
|
||||
|
|
@ -482,6 +490,8 @@ struct channel_path_desc_fmt0 *ccw_device_get_chp_desc(struct ccw_device *cdev,
|
|||
struct chp_id chpid;
|
||||
|
||||
sch = to_subchannel(cdev->dev.parent);
|
||||
if (!sch->schib.pmcw.dnv)
|
||||
return NULL;
|
||||
chp_id_init(&chpid);
|
||||
chpid.id = sch->schib.pmcw.chpid[chp_idx];
|
||||
return chp_get_chp_desc(chpid);
|
||||
|
|
@ -502,9 +512,13 @@ u8 *ccw_device_get_util_str(struct ccw_device *cdev, int chp_idx)
|
|||
struct chp_id chpid;
|
||||
u8 *util_str;
|
||||
|
||||
if (!sch->schib.pmcw.dnv)
|
||||
return NULL;
|
||||
chp_id_init(&chpid);
|
||||
chpid.id = sch->schib.pmcw.chpid[chp_idx];
|
||||
chp = chpid_to_chp(chpid);
|
||||
if (!chp)
|
||||
return NULL;
|
||||
|
||||
util_str = kmalloc(sizeof(chp->desc_fmt3.util_str), GFP_KERNEL);
|
||||
if (!util_str)
|
||||
|
|
@ -548,6 +562,8 @@ int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw,
|
|||
int rc;
|
||||
|
||||
sch = to_subchannel(cdev->dev.parent);
|
||||
if (!sch->schib.pmcw.dnv)
|
||||
return -ENODEV;
|
||||
if (!sch->schib.pmcw.ena)
|
||||
return -EINVAL;
|
||||
if (cdev->private->state == DEV_STATE_VERIFY) {
|
||||
|
|
@ -652,6 +668,9 @@ int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask)
|
|||
struct chp_id chpid;
|
||||
int mdc = 0, i;
|
||||
|
||||
if (!sch->schib.pmcw.dnv)
|
||||
return 0;
|
||||
|
||||
/* Adjust requested path mask to excluded varied off paths. */
|
||||
if (mask)
|
||||
mask &= sch->lpm;
|
||||
|
|
@ -694,6 +713,8 @@ int ccw_device_tm_intrg(struct ccw_device *cdev)
|
|||
{
|
||||
struct subchannel *sch = to_subchannel(cdev->dev.parent);
|
||||
|
||||
if (!sch->schib.pmcw.dnv)
|
||||
return -ENODEV;
|
||||
if (!sch->schib.pmcw.ena)
|
||||
return -EINVAL;
|
||||
if (cdev->private->state != DEV_STATE_ONLINE)
|
||||
|
|
@ -786,6 +807,8 @@ int ccw_device_get_chpid(struct ccw_device *cdev, int chp_idx, u8 *chpid)
|
|||
|
||||
if ((chp_idx < 0) || (chp_idx > 7))
|
||||
return -EINVAL;
|
||||
if (!sch->schib.pmcw.dnv)
|
||||
return -ENODEV;
|
||||
mask = 0x80 >> chp_idx;
|
||||
if (!(sch->schib.pmcw.pim & mask))
|
||||
return -ENODEV;
|
||||
|
|
|
|||
|
|
@ -399,7 +399,7 @@ static void fsm_close(struct vfio_ccw_private *private,
|
|||
|
||||
spin_lock_irq(&sch->lock);
|
||||
|
||||
if (!sch->schib.pmcw.ena)
|
||||
if (!sch->schib.pmcw.dnv || !sch->schib.pmcw.ena)
|
||||
goto err_unlock;
|
||||
|
||||
ret = cio_disable_subchannel(sch);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user