cregit-Linux how code gets into the kernel

Release 4.7 drivers/s390/cio/device.c

Directory: drivers/s390/cio
/*
 *  bus driver for ccw devices
 *
 *    Copyright IBM Corp. 2002, 2008
 *    Author(s): Arnd Bergmann (arndb@de.ibm.com)
 *               Cornelia Huck (cornelia.huck@de.ibm.com)
 *               Martin Schwidefsky (schwidefsky@de.ibm.com)
 */


#define KMSG_COMPONENT "cio"

#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt

#include <linux/module.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/device.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/kernel_stat.h>

#include <asm/ccwdev.h>
#include <asm/cio.h>
#include <asm/param.h>		/* HZ */
#include <asm/cmb.h>
#include <asm/isc.h>

#include "chp.h"
#include "cio.h"
#include "cio_debug.h"
#include "css.h"
#include "device.h"
#include "ioasm.h"
#include "io_sch.h"
#include "blacklist.h"
#include "chsc.h"


static struct timer_list recovery_timer;
static DEFINE_SPINLOCK(recovery_lock);

static int recovery_phase;

static const unsigned long recovery_delay[] = { 3, 30, 300 };


static atomic_t ccw_device_init_count = ATOMIC_INIT(0);
static DECLARE_WAIT_QUEUE_HEAD(ccw_device_init_wq);

static struct bus_type ccw_bus_type;

/******************* bus type handling ***********************/

/* The Linux driver model distinguishes between a bus type and
 * the bus itself. Of course we only have one channel
 * subsystem driver and one channel system per machine, but
 * we still use the abstraction. T.R. says it's a good idea. */

static int ccw_bus_match (struct device * dev, struct device_driver * drv) { struct ccw_device *cdev = to_ccwdev(dev); struct ccw_driver *cdrv = to_ccwdrv(drv); const struct ccw_device_id *ids = cdrv->ids, *found; if (!ids) return 0; found = ccw_device_id_match(ids, &cdev->id); if (!found) return 0; cdev->id.driver_info = found->driver_info; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
martin schwidefskymartin schwidefsky90100.00%1100.00%
Total90100.00%1100.00%

/* Store modalias string delimited by prefix/suffix string into buffer with * specified size. Return length of resulting string (excluding trailing '\0') * even if string doesn't fit buffer (snprintf semantics). */
static int snprint_alias(char *buf, size_t size, struct ccw_device_id *id, const char *suffix) { int len; len = snprintf(buf, size, "ccw:t%04Xm%02X", id->cu_type, id->cu_model); if (len > size) return len; buf += len; size -= len; if (id->dev_type != 0) len += snprintf(buf, size, "dt%04Xdm%02X%s", id->dev_type, id->dev_model, suffix); else len += snprintf(buf, size, "dtdm%s", suffix); return len; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter10597.22%133.33%
martin schwidefskymartin schwidefsky21.85%133.33%
cornelia huckcornelia huck10.93%133.33%
Total108100.00%3100.00%

/* Set up environment variables for ccw device uevent. Return 0 on success, * non-zero otherwise. */
static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env) { struct ccw_device *cdev = to_ccwdev(dev); struct ccw_device_id *id = &(cdev->id); int ret; char modalias_buf[30]; /* CU_TYPE= */ ret = add_uevent_var(env, "CU_TYPE=%04X", id->cu_type); if (ret) return ret; /* CU_MODEL= */ ret = add_uevent_var(env, "CU_MODEL=%02X", id->cu_model); if (ret) return ret; /* The next two can be zero, that's ok for us */ /* DEV_TYPE= */ ret = add_uevent_var(env, "DEV_TYPE=%04X", id->dev_type); if (ret) return ret; /* DEV_MODEL= */ ret = add_uevent_var(env, "DEV_MODEL=%02X", id->dev_model); if (ret) return ret; /* MODALIAS= */ snprint_alias(modalias_buf, sizeof(modalias_buf), id, ""); ret = add_uevent_var(env, "MODALIAS=%s", modalias_buf); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
martin schwidefskymartin schwidefsky6640.99%120.00%
peter oberparleiterpeter oberparleiter4427.33%120.00%
cornelia huckcornelia huck4226.09%120.00%
kay sieverskay sievers84.97%120.00%
paul jacksonpaul jackson10.62%120.00%
Total161100.00%5100.00%

static void io_subchannel_irq(struct subchannel *); static int io_subchannel_probe(struct subchannel *); static int io_subchannel_remove(struct subchannel *); static void io_subchannel_shutdown(struct subchannel *); static int io_subchannel_sch_event(struct subchannel *, int); static int io_subchannel_chp_event(struct subchannel *, struct chp_link *, int); static void recovery_func(unsigned long data); static struct css_device_id io_subchannel_ids[] = { { .match_flags = 0x1, .type = SUBCHANNEL_TYPE_IO, }, { /* end of list */ }, }; MODULE_DEVICE_TABLE(css, io_subchannel_ids);
static int io_subchannel_prepare(struct subchannel *sch) { struct ccw_device *cdev; /* * Don't allow suspend while a ccw device registration * is still outstanding. */ cdev = sch_get_cdev(sch); if (cdev && !device_is_registered(&cdev->dev)) return -EAGAIN; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck44100.00%1100.00%
Total44100.00%1100.00%


static int io_subchannel_settle(void) { int ret; ret = wait_event_interruptible(ccw_device_init_wq, atomic_read(&ccw_device_init_count) == 0); if (ret) return -EINTR; flush_workqueue(cio_work_q); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott42100.00%3100.00%
Total42100.00%3100.00%

static struct css_driver io_subchannel_driver = { .drv = { .owner = THIS_MODULE, .name = "io_subchannel", }, .subchannel_type = io_subchannel_ids, .irq = io_subchannel_irq, .sch_event = io_subchannel_sch_event, .chp_event = io_subchannel_chp_event, .probe = io_subchannel_probe, .remove = io_subchannel_remove, .shutdown = io_subchannel_shutdown, .prepare = io_subchannel_prepare, .settle = io_subchannel_settle, };
int __init io_subchannel_init(void) { int ret; setup_timer(&recovery_timer, recovery_func, 0); ret = bus_register(&ccw_bus_type); if (ret) return ret; ret = css_driver_register(&io_subchannel_driver); if (ret) bus_unregister(&ccw_bus_type); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
martin schwidefskymartin schwidefsky2645.61%225.00%
peter oberparleiterpeter oberparleiter1017.54%112.50%
sebastian ottsebastian ott1017.54%225.00%
andrew mortonandrew morton610.53%225.00%
cornelia huckcornelia huck58.77%112.50%
Total57100.00%8100.00%

/************************ device handling **************************/ /* * A ccw_device has some interfaces in sysfs in addition to the * standard ones. * The following entries are designed to export the information which * resided in 2.4 in /proc/subchannels. Subchannel and device number * are obvious, so they don't have an entry :) * TODO: Split chpids and pimpampom up? Where is "in use" in the tree? */
static ssize_t chpids_show (struct device * dev, struct device_attribute *attr, char * buf) { struct subchannel *sch = to_subchannel(dev); struct chsc_ssd_info *ssd = &sch->ssd_info; ssize_t ret = 0; int chp; int mask; for (chp = 0; chp < 8; chp++) { mask = 0x80 >> chp; if (ssd->path_mask & mask) ret += sprintf(buf + ret, "%02x ", ssd->chpid[chp].id); else ret += sprintf(buf + ret, "00 "); } ret += sprintf (buf+ret, "\n"); return min((ssize_t)PAGE_SIZE, ret); }

Contributors

PersonTokensPropCommitsCommitProp
martin schwidefskymartin schwidefsky9470.15%125.00%
peter oberparleiterpeter oberparleiter3425.37%125.00%
yani ioannouyani ioannou53.73%125.00%
patrick mochelpatrick mochel10.75%125.00%
Total134100.00%4100.00%


static ssize_t pimpampom_show (struct device * dev, struct device_attribute *attr, char * buf) { struct subchannel *sch = to_subchannel(dev); struct pmcw *pmcw = &sch->schib.pmcw; return sprintf (buf, "%02x %02x %02x\n", pmcw->pim, pmcw->pam, pmcw->pom); }

Contributors

PersonTokensPropCommitsCommitProp
martin schwidefskymartin schwidefsky5690.32%133.33%
yani ioannouyani ioannou58.06%133.33%
patrick mochelpatrick mochel11.61%133.33%
Total62100.00%3100.00%


static ssize_t devtype_show (struct device *dev, struct device_attribute *attr, char *buf) { struct ccw_device *cdev = to_ccwdev(dev); struct ccw_device_id *id = &(cdev->id); if (id->dev_type != 0) return sprintf(buf, "%04x/%02x\n", id->dev_type, id->dev_model); else return sprintf(buf, "n/a\n"); }

Contributors

PersonTokensPropCommitsCommitProp
martin schwidefskymartin schwidefsky6890.67%133.33%
yani ioannouyani ioannou56.67%133.33%
patrick mochelpatrick mochel22.67%133.33%
Total75100.00%3100.00%


static ssize_t cutype_show (struct device *dev, struct device_attribute *attr, char *buf) { struct ccw_device *cdev = to_ccwdev(dev); struct ccw_device_id *id = &(cdev->id); return sprintf(buf, "%04x/%02x\n", id->cu_type, id->cu_model); }

Contributors

PersonTokensPropCommitsCommitProp
martin schwidefskymartin schwidefsky5289.66%133.33%
yani ioannouyani ioannou58.62%133.33%
patrick mochelpatrick mochel11.72%133.33%
Total58100.00%3100.00%


static ssize_t modalias_show (struct device *dev, struct device_attribute *attr, char *buf) { struct ccw_device *cdev = to_ccwdev(dev); struct ccw_device_id *id = &(cdev->id); int len; len = snprint_alias(buf, PAGE_SIZE, id, "\n"); return len > PAGE_SIZE ? PAGE_SIZE : len; }

Contributors

PersonTokensPropCommitsCommitProp
bastian blankbastian blank5379.10%133.33%
peter oberparleiterpeter oberparleiter1217.91%133.33%
martin schwidefskymartin schwidefsky22.99%133.33%
Total67100.00%3100.00%


static ssize_t online_show (struct device *dev, struct device_attribute *attr, char *buf) { struct ccw_device *cdev = to_ccwdev(dev); return sprintf(buf, cdev->online ? "1\n" : "0\n"); }

Contributors

PersonTokensPropCommitsCommitProp
martin schwidefskymartin schwidefsky3681.82%240.00%
yani ioannouyani ioannou511.36%120.00%
bastian blankbastian blank24.55%120.00%
patrick mochelpatrick mochel12.27%120.00%
Total44100.00%5100.00%


int ccw_device_is_orphan(struct ccw_device *cdev) { return sch_is_pseudo_sch(to_subchannel(cdev->dev.parent)); }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck23100.00%1100.00%
Total23100.00%1100.00%


static void ccw_device_unregister(struct ccw_device *cdev) { if (device_is_registered(&cdev->dev)) { /* Undo device_add(). */ device_del(&cdev->dev); } if (cdev->private->flags.initialized) { cdev->private->flags.initialized = 0; /* Release reference from device_initialize(). */ put_device(&cdev->dev); } }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott3657.14%360.00%
cornelia huckcornelia huck2742.86%240.00%
Total63100.00%5100.00%

static void io_subchannel_quiesce(struct subchannel *); /** * ccw_device_set_offline() - disable a ccw device for I/O * @cdev: target ccw device * * This function calls the driver's set_offline() function for @cdev, if * given, and then disables @cdev. * Returns: * %0 on success and a negative error value on failure. * Context: * enabled, ccw device lock not held */
int ccw_device_set_offline(struct ccw_device *cdev) { struct subchannel *sch; int ret, state; if (!cdev) return -ENODEV; if (!cdev->online || !cdev->drv) return -EINVAL; if (cdev->drv->set_offline) { ret = cdev->drv->set_offline(cdev); if (ret != 0) return ret; } spin_lock_irq(cdev->ccwlock); sch = to_subchannel(cdev->dev.parent); cdev->online = 0; /* Wait until a final state or DISCONNECTED is reached */ while (!dev_fsm_final_state(cdev) && cdev->private->state != DEV_STATE_DISCONNECTED) { spin_unlock_irq(cdev->ccwlock); wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) || cdev->private->state == DEV_STATE_DISCONNECTED)); spin_lock_irq(cdev->ccwlock); } do { ret = ccw_device_offline(cdev); if (!ret) break; CIO_MSG_EVENT(0, "ccw_device_offline returned %d, device " "0.%x.%04x\n", ret, cdev->private->dev_id.ssid, cdev->private->dev_id.devno); if (ret != -EBUSY) goto error; state = cdev->private->state; spin_unlock_irq(cdev->ccwlock); io_subchannel_quiesce(sch); spin_lock_irq(cdev->ccwlock); cdev->private->state = state; } while (ret == -EBUSY); spin_unlock_irq(cdev->ccwlock); wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) || cdev->private->state == DEV_STATE_DISCONNECTED)); /* Inform the user if set offline failed. */ if (cdev->private->state == DEV_STATE_BOXED) { pr_warn("%s: The device entered boxed state while being set offline\n", dev_name(&cdev->dev)); } else if (cdev->private->state == DEV_STATE_NOT_OPER) { pr_warn("%s: The device stopped operating while being set offline\n", dev_name(&cdev->dev)); } /* Give up reference from ccw_device_set_online(). */ put_device(&cdev->dev); return 0; error: cdev->private->state = DEV_STATE_OFFLINE; dev_fsm_event(cdev, DEV_EVENT_NOTOPER); spin_unlock_irq(cdev->ccwlock); /* Give up reference from ccw_device_set_online(). */ put_device(&cdev->dev); return -ENODEV; }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott10527.42%216.67%
michael ernstmichael ernst8522.19%18.33%
andrew mortonandrew morton5915.40%325.00%
peter oberparleiterpeter oberparleiter4812.53%18.33%
martin schwidefskymartin schwidefsky4511.75%18.33%
cornelia huckcornelia huck379.66%325.00%
joe perchesjoe perches41.04%18.33%
Total383100.00%12100.00%

/** * ccw_device_set_online() - enable a ccw device for I/O * @cdev: target ccw device * * This function first enables @cdev and then calls the driver's set_online() * function for @cdev, if given. If set_online() returns an error, @cdev is * disabled again. * Returns: * %0 on success and a negative error value on failure. * Context: * enabled, ccw device lock not held */
int ccw_device_set_online(struct ccw_device *cdev) { int ret; int ret2; if (!cdev) return -ENODEV; if (cdev->online || !cdev->drv) return -EINVAL; /* Hold on to an extra reference while device is online. */ if (!get_device(&cdev->dev)) return -ENODEV; spin_lock_irq(cdev->ccwlock); ret = ccw_device_online(cdev); spin_unlock_irq(cdev->ccwlock); if (ret == 0) wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); else { CIO_MSG_EVENT(0, "ccw_device_online returned %d, " "device 0.%x.%04x\n", ret, cdev->private->dev_id.ssid, cdev->private->dev_id.devno); /* Give up online reference since onlining failed. */ put_device(&cdev->dev); return ret; } spin_lock_irq(cdev->ccwlock); /* Check if online processing was successful */ if ((cdev->private->state != DEV_STATE_ONLINE) && (cdev->private->state != DEV_STATE_W4SENSE)) { spin_unlock_irq(cdev->ccwlock); /* Inform the user that set online failed. */ if (cdev->private->state == DEV_STATE_BOXED) { pr_warn("%s: Setting the device online failed because it is boxed\n", dev_name(&cdev->dev)); } else if (cdev->private->state == DEV_STATE_NOT_OPER) { pr_warn("%s: Setting the device online failed because it is not operational\n", dev_name(&cdev->dev)); } /* Give up online reference since onlining failed. */ put_device(&cdev->dev); return -ENODEV; } spin_unlock_irq(cdev->ccwlock); if (cdev->drv->set_online) ret = cdev->drv->set_online(cdev); if (ret) goto rollback; spin_lock_irq(cdev->ccwlock); cdev->online = 1; spin_unlock_irq(cdev->ccwlock); return 0; rollback: spin_lock_irq(cdev->ccwlock); /* Wait until a final state or DISCONNECTED is reached */ while (!dev_fsm_final_state(cdev) && cdev->private->state != DEV_STATE_DISCONNECTED) { spin_unlock_irq(cdev->ccwlock); wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) || cdev->private->state == DEV_STATE_DISCONNECTED)); spin_lock_irq(cdev->ccwlock); } ret2 = ccw_device_offline(cdev); if (ret2) goto error; spin_unlock_irq(cdev->ccwlock); wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) || cdev->private->state == DEV_STATE_DISCONNECTED)); /* Give up online reference since onlining failed. */ put_device(&cdev->dev); return ret; error: CIO_MSG_EVENT(0, "rollback ccw_device_offline returned %d, " "device 0.%x.%04x\n", ret2, cdev->private->dev_id.ssid, cdev->private->dev_id.devno); cdev->private->state = DEV_STATE_OFFLINE; spin_unlock_irq(cdev->ccwlock); /* Give up online reference since onlining failed. */ put_device(&cdev->dev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
michael ernstmichael ernst15732.98%216.67%
martin schwidefskymartin schwidefsky15031.51%216.67%
cornelia huckcornelia huck7716.18%325.00%
peter oberparleiterpeter oberparleiter4810.08%18.33%
andrew mortonandrew morton265.46%216.67%
sebastian ottsebastian ott142.94%18.33%
joe perchesjoe perches40.84%18.33%
Total476100.00%12100.00%


static int online_store_handle_offline(struct ccw_device *cdev) { if (cdev->private->state == DEV_STATE_DISCONNECTED) { spin_lock_irq(cdev->ccwlock); ccw_device_sched_todo(cdev, CDEV_TODO_UNREG_EVAL); spin_unlock_irq(cdev->ccwlock); return 0; } if (cdev->drv && cdev->drv->set_offline) return ccw_device_set_offline(cdev); return -EINVAL; }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton2028.99%228.57%
peter oberparleiterpeter oberparleiter1927.54%114.29%
cornelia huckcornelia huck1217.39%114.29%
sebastian ottsebastian ott1014.49%228.57%
martin schwidefskymartin schwidefsky811.59%114.29%
Total69100.00%7100.00%


static int online_store_recog_and_online(struct ccw_device *cdev) { /* Do device recognition, if needed. */ if (cdev->private->state == DEV_STATE_BOXED) { spin_lock_irq(cdev->ccwlock); ccw_device_recognition(cdev); spin_unlock_irq(cdev->ccwlock); wait_event(cdev->private->wait_q, cdev->private->flags.recog_done); if (cdev->private->state != DEV_STATE_OFFLINE) /* recognition failed */ return -EAGAIN; } if (cdev->drv && cdev->drv->set_online) return ccw_device_set_online(cdev); return -EINVAL; }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton4142.27%225.00%
sebastian ottsebastian ott2323.71%337.50%
peter oberparleiterpeter oberparleiter1414.43%112.50%
cornelia huckcornelia huck1212.37%112.50%
martin schwidefskymartin schwidefsky77.22%112.50%
Total97100.00%8100.00%


static int online_store_handle_online(struct ccw_device *cdev, int force) { int ret; ret = online_store_recog_and_online(cdev); if (ret && !force) return ret; if (force && cdev->private->state == DEV_STATE_BOXED) { ret = ccw_device_stlck(cdev); if (ret) return ret; if (cdev->id.cu_type == 0) cdev->private->state = DEV_STATE_NOT_OPER; ret = online_store_recog_and_online(cdev); if (ret) return ret; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton3536.08%337.50%
cornelia huckcornelia huck2121.65%112.50%
martin schwidefskymartin schwidefsky2020.62%225.00%
sebastian ottsebastian ott1212.37%112.50%
michael ernstmichael ernst99.28%112.50%
Total97100.00%8100.00%


static ssize_t online_store (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct ccw_device *cdev = to_ccwdev(dev); int force, ret; unsigned long i; /* Prevent conflict between multiple on-/offline processing requests. */ if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0) return -EAGAIN; /* Prevent conflict between internal I/Os and on-/offline processing. */ if (!dev_fsm_final_state(cdev) && cdev->private->state != DEV_STATE_DISCONNECTED) { ret = -EAGAIN; goto out; } /* Prevent conflict between pending work and on-/offline processing.*/ if (work_pending(&cdev->private->todo_work)) { ret = -EAGAIN; goto out; } if (!strncmp(buf, "force\n", count)) { force = 1; i = 1; ret = 0; } else { force = 0; ret = kstrtoul(buf, 16, &i); } if (ret) goto out; device_lock(dev); switch (i) { case 0: ret = online_store_handle_offline(cdev); break; case 1: ret = online_store_handle_online(cdev, force); break; default: ret = -EINVAL; } device_unlock(dev); out: atomic_set(&cdev->private->onoff, 0); return (ret < 0) ? ret : count; }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck12853.56%216.67%
peter oberparleiterpeter oberparleiter5020.92%216.67%
sebastian ottsebastian ott2912.13%325.00%
martin schwidefskymartin schwidefsky166.69%18.33%
andrew mortonandrew morton135.44%216.67%
michael ernstmichael ernst20.84%18.33%
jingoo hanjingoo han10.42%18.33%
Total239100.00%12100.00%


static ssize_t available_show (struct device *dev, struct device_attribute *attr, char *buf) { struct ccw_device *cdev = to_ccwdev(dev); struct subchannel *sch; if (ccw_device_is_orphan(cdev)) return sprintf(buf, "no device\n"); switch (cdev->private->state) { case DEV_STATE_BOXED: return sprintf(buf, "boxed\n"); case DEV_STATE_DISCONNECTED: case DEV_STATE_DISCONNECTED_SENSE_ID: case DEV_STATE_NOT_OPER: sch = to_subchannel(dev->parent); if (!sch->lpm) return sprintf(buf, "no path\n"); else return sprintf(buf, "no device\n"); default: /* All other states considered fine. */ return sprintf(buf, "good\n"); } }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton10383.74%133.33%
cornelia huckcornelia huck1512.20%133.33%
yani ioannouyani ioannou54.07%133.33%
Total123100.00%3100.00%


static ssize_t initiate_logging(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct subchannel *sch = to_subchannel(dev); int rc; rc = chsc_siosl(sch->schid); if (rc < 0) { pr_warn("Logging for subchannel 0.%x.%04x failed with errno=%d\n", sch->schid.ssid, sch->schid.sch_no, rc); return rc; } pr_notice("Logging for subchannel 0.%x.%04x was triggered\n", sch->schid.ssid, sch->schid.sch_no); return count; }

Contributors

PersonTokensPropCommitsCommitProp
michael ernstmichael ernst9497.92%150.00%
joe perchesjoe perches22.08%150.00%
Total96100.00%2100.00%


static ssize_t vpm_show(struct device *dev, struct device_attribute *attr, char *buf) { struct subchannel *sch = to_subchannel(dev); return sprintf(buf, "%02x\n", sch->vpm); }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott42100.00%1100.00%
Total42100.00%1100.00%

static DEVICE_ATTR(chpids, 0444, chpids_show, NULL); static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL); static DEVICE_ATTR(devtype, 0444, devtype_show, NULL); static DEVICE_ATTR(cutype, 0444, cutype_show, NULL); static DEVICE_ATTR(modalias, 0444, modalias_show, NULL); static DEVICE_ATTR(online, 0644, online_show, online_store); static DEVICE_ATTR(availability, 0444, available_show, NULL); static DEVICE_ATTR(logging, 0200, NULL, initiate_logging); static DEVICE_ATTR(vpm, 0444, vpm_show, NULL); static struct attribute *io_subchannel_attrs[] = { &dev_attr_chpids.attr, &dev_attr_pimpampom.attr, &dev_attr_logging.attr, &dev_attr_vpm.attr, NULL, }; static struct attribute_group io_subchannel_attr_group = { .attrs = io_subchannel_attrs, }; static struct attribute * ccwdev_attrs[] = { &dev_attr_devtype.attr, &dev_attr_cutype.attr, &dev_attr_modalias.attr, &dev_attr_online.attr, &dev_attr_cmb_enable.attr, &dev_attr_availability.attr, NULL, }; static struct attribute_group ccwdev_attr_group = { .attrs = ccwdev_attrs, }; static const struct attribute_group *ccwdev_attr_groups[] = { &ccwdev_attr_group, NULL, };
static int ccw_device_add(struct ccw_device *cdev) { struct device *dev = &cdev->dev; dev->bus = &ccw_bus_type; return device_add(dev); }

Contributors

PersonTokensPropCommitsCommitProp
martin schwidefskymartin schwidefsky3088.24%125.00%
cornelia huckcornelia huck25.88%125.00%
sebastian ottsebastian ott25.88%250.00%
Total34100.00%4100.00%


static int match_dev_id(struct device *dev, void *data) { struct ccw_device *cdev = to_ccwdev(dev); struct ccw_dev_id *dev_id = data; return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id); }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck3168.89%240.00%
andrew mortonandrew morton920.00%120.00%
peter oberparleiterpeter oberparleiter48.89%120.00%
heiko carstensheiko carstens12.22%120.00%
Total45100.00%5100.00%

/** * get_ccwdev_by_dev_id() - obtain device from a ccw device id * @dev_id: id of the device to be searched * * This function searches all devices attached to the ccw bus for a device * matching @dev_id. * Returns: * If a device is found its reference count is increased and returned; * else %NULL is returned. */
struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id) { struct device *dev; dev = bus_find_device(&ccw_bus_type, NULL, dev_id, match_dev_id); return dev ? to_ccwdev(dev) : NULL; }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck3585.37%150.00%
peter oberparleiterpeter oberparleiter614.63%150.00%
Total41100.00%2100.00%

EXPORT_SYMBOL_GPL(get_ccwdev_by_dev_id);
static void ccw_device_do_unbind_bind(struct ccw_device *cdev) { int ret; if (device_is_registered(&cdev->dev)) { device_release_driver(&cdev->dev); ret = device_attach(&cdev->dev); WARN_ON(ret == -ENODEV); } }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck1936.54%111.11%
martin schwidefskymartin schwidefsky1732.69%444.44%
andrew mortonandrew morton1121.15%222.22%
peter oberparleiterpeter oberparleiter35.77%111.11%
sebastian ottsebastian ott23.85%111.11%
Total52100.00%9100.00%


static void ccw_device_release(struct device *dev) { struct ccw_device *cdev; cdev = to_ccwdev(dev); /* Release reference of parent subchannel. */ put_device(cdev->dev.parent); kfree(cdev->private); kfree(cdev); }

Contributors

PersonTokensPropCommitsCommitProp
martin schwidefskymartin schwidefsky3577.78%150.00%
cornelia huckcornelia huck1022.22%150.00%
Total45100.00%2100.00%


static struct ccw_device * io_subchannel_allocate_dev(struct subchannel *sch) { struct ccw_device *cdev; cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); if (cdev) { cdev->private = kzalloc(sizeof(struct ccw_device_private), GFP_KERNEL | GFP_DMA); if (cdev->private) return cdev; } kfree(cdev); return ERR_PTR(-ENOMEM); }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck5269.33%125.00%
martin schwidefskymartin schwidefsky2330.67%375.00%
Total75100.00%4100.00%

static void ccw_device_todo(struct work_struct *work);
static int io_subchannel_initialize_dev(struct subchannel *sch, struct ccw_device *cdev) { struct ccw_device_private *priv = cdev->private; int ret; priv->cdev = cdev; priv->int_class = IRQIO_CIO; priv->state = DEV_STATE_NOT_OPER; priv->dev_id.devno = sch->schib.pmcw.dev; priv->dev_id.ssid = sch->schid.ssid; priv->schid = sch->schid; INIT_WORK(&priv->todo_work, ccw_device_todo); INIT_LIST_HEAD(&priv->cmb_list); init_waitqueue_head(&priv->wait_q); init_timer(&priv->timer); atomic_set(&priv->onoff, 0); cdev->ccwlock = sch->lock; cdev->dev.parent = &sch->dev; cdev->dev.release = ccw_device_release; cdev->dev.groups = ccwdev_attr_groups; /* Do first half of device_register. */ device_initialize(&cdev->dev); ret = dev_set_name(&cdev->dev, "0.%x.%04x", cdev->private->dev_id.ssid, cdev->private->dev_id.devno); if (ret) goto out_put; if (!get_device(&sch->dev)) { ret = -ENODEV; goto out_put; } priv->flags.initialized = 1; spin_lock_irq(sch->lock); sch_set_cdev(sch, cdev); spin_unlock_irq(sch->lock); return 0; out_put: /* Release reference from device_initialize(). */ put_device(&cdev->dev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott17865.93%220.00%
cornelia huckcornelia huck7126.30%440.00%
martin schwidefskymartin schwidefsky82.96%110.00%
andrew mortonandrew morton82.96%110.00%
peter oberparleiterpeter oberparleiter41.48%110.00%
heiko carstensheiko carstens10.37%110.00%
Total270100.00%10100.00%


static struct ccw_device * io_subchannel_create_ccwdev(struct subchannel *sch) { struct ccw_device *cdev; int ret; cdev = io_subchannel_allocate_dev(sch); if (!IS_ERR(cdev)) { ret = io_subchannel_initialize_dev(sch, cdev); if (ret) cdev = ERR_PTR(ret); } return cdev; }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck61100.00%1100.00%
Total61100.00%1100.00%

static void io_subchannel_recog(struct ccw_device *, struct subchannel *);
static void sch_create_and_recog_new_device(struct subchannel *sch) { struct ccw_device *cdev; /* Need to allocate a new ccw device. */ cdev = io_subchannel_create_ccwdev(sch); if (IS_ERR(cdev)) { /* OK, we did everything we could... */ css_sch_device_unregister(sch); return; } /* Start recognition for the new ccw device. */ io_subchannel_recog(cdev, sch); }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter3164.58%125.00%
cornelia huckcornelia huck1735.42%375.00%
Total48100.00%4100.00%

/* * Register recognized device. */
static void io_subchannel_register(struct ccw_device *cdev) { struct subchannel *sch; int ret, adjust_init_count = 1; unsigned long flags; sch = to_subchannel(cdev->dev.parent); /* * Check if subchannel is still registered. It may have become * unregistered if a machine check hit us after finishing * device recognition but before the register work could be * queued. */ if (!device_is_registered(&sch->dev)) goto out_err; css_update_ssd_info(sch); /* * io_subchannel_register() will also be called after device * recognition has been done for a boxed device (which will already * be registered). We need to reprobe since we may now have sense id * information. */ if (device_is_registered(&cdev->dev)) { if (!cdev->drv) { ret = device_reprobe(&cdev->dev); if (ret) /* We can't do much here. */ CIO_MSG_EVENT(0, "device_reprobe() returned" " %d for 0.%x.%04x\n", ret, cdev->private->dev_id.ssid, cdev->private->dev_id.devno); } adjust_init_count = 0; goto out; } /* * Now we know this subchannel will stay, we can throw * our delayed uevent. */ dev_set_uevent_suppress(&sch->dev, 0); kobject_uevent(&sch->dev.kobj, KOBJ_ADD); /* make it known to the system */ ret = ccw_device_add(cdev); if (ret) { CIO_MSG_EVENT(0, "Could not register ccw dev 0.%x.%04x: %d\n", cdev->private->dev_id.ssid, cdev->private->dev_id.devno, ret); spin_lock_irqsave(sch->lock, flags); sch_set_cdev(sch, NULL); spin_unlock_irqrestore(sch->lock, flags); /* Release initial device reference. */ put_device(&cdev->dev); goto out_err; } out: cdev->private->flags.recog_done = 1; wake_up(&cdev->private->wait_q); out_err: if (adjust_init_count && atomic_dec_and_test(&ccw_device_init_count)) wake_up(&ccw_device_init_wq); }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck14755.06%228.57%
peter oberparleiterpeter oberparleiter10840.45%228.57%
sebastian ottsebastian ott114.12%228.57%
michael ernstmichael ernst10.37%114.29%
Total267100.00%7100.00%


static void ccw_device_call_sch_unregister(struct ccw_device *cdev) { struct subchannel *sch; /* Get subchannel reference for local processing. */ if (!get_device(cdev->dev.parent)) return; sch = to_subchannel(cdev->dev.parent); css_sch_device_unregister(sch); /* Release subchannel reference for local processing. */ put_device(&sch->dev); }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck3461.82%133.33%
peter oberparleiterpeter oberparleiter2138.18%266.67%
Total55100.00%3100.00%

/* * subchannel recognition done. Called from the state machine. */
void io_subchannel_recog_done(struct ccw_device *cdev) { if (css_init_done == 0) { cdev->private->flags.recog_done = 1; return; } switch (cdev->private->state) { case DEV_STATE_BOXED: /* Device did not respond in time. */ case DEV_STATE_NOT_OPER: cdev->private->flags.recog_done = 1; /* Remove device found not operational. */ ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); if (atomic_dec_and_test(&ccw_device_init_count)) wake_up(&ccw_device_init_wq); break; case DEV_STATE_OFFLINE: /* * We can't register the device in interrupt context so * we schedule a work item. */ ccw_device_sched_todo(cdev, CDEV_TODO_REGISTER); break; } }

Contributors

PersonTokensPropCommitsCommitProp
martin schwidefskymartin schwidefsky4448.35%222.22%
peter oberparleiterpeter oberparleiter2426.37%222.22%
andrew mortonandrew morton1213.19%111.11%
cornelia huckcornelia huck77.69%333.33%
sebastian ottsebastian ott44.40%111.11%
Total91100.00%9100.00%


static void io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) { /* Increase counter of devices currently in recognition. */ atomic_inc(&ccw_device_init_count); /* Start async. device sensing. */ spin_lock_irq(sch->lock); ccw_device_recognition(cdev); spin_unlock_irq(sch->lock); }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck2865.12%133.33%
martin schwidefskymartin schwidefsky1330.23%133.33%
peter oberparleiterpeter oberparleiter24.65%133.33%
Total43100.00%3100.00%


static int ccw_device_move_to_sch(struct ccw_device *cdev, struct subchannel *sch) { struct subchannel *old_sch; int rc, old_enabled = 0; old_sch = to_subchannel(cdev->dev.parent); /* Obtain child reference for new parent. */ if (!get_device(&sch->dev)) return -ENODEV; if (!sch_is_pseudo_sch(old_sch)) { spin_lock_irq(old_sch->lock); old_enabled = old_sch->schib.pmcw.ena; rc = 0; if (old_enabled) rc = cio_disable_subchannel(old_sch); spin_unlock_irq(old_sch->lock); if (rc == -EBUSY) { /* Release child reference for new parent. */ put_device(&sch->dev); return rc; } } mutex_lock(&sch->reg_mutex); rc = device_move(&cdev->dev, &sch->dev, DPM_ORDER_PARENT_BEFORE_DEV); mutex_unlock(&sch->reg_mutex); if (rc) { 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); if (old_enabled) { /* Try to reenable the old subchannel. */ spin_lock_irq(old_sch->lock); cio_enable_subchannel(old_sch, (u32)(addr_t)old_sch); spin_unlock_irq(old_sch->lock); } /* Release child reference for new parent. */ put_device(&sch->dev); return rc; } /* Clean up old subchannel. */ if (!sch_is_pseudo_sch(old_sch)) { spin_lock_irq(old_sch->lock); sch_set_cdev(old_sch, NULL); spin_unlock_irq(old_sch->lock); css_schedule_eval(old_sch->schid); } /* Release child reference for old parent. */ put_device(&old_sch->dev); /* Initialize new subchannel. */ spin_lock_irq(sch->lock); cdev->private->schid = sch->schid; cdev->ccwlock = sch->lock; if (!sch_is_pseudo_sch(sch)) sch_set_cdev(sch, cdev); spin_unlock_irq(sch->lock); if (!sch_is_pseudo_sch(sch)) css_update_ssd_info(sch); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter11231.02%17.69%
sebastian ottsebastian ott10829.92%17.69%
cornelia huckcornelia huck10428.81%646.15%
martin schwidefskymartin schwidefsky328.86%215.38%
andrew mortonandrew morton41.11%215.38%
michael ernstmichael ernst10.28%17.69%
Total361100.00%13100.00%


static int ccw_device_move_to_orph(struct ccw_device *cdev) { struct subchannel *sch = to_subchannel(cdev->dev.parent); struct channel_subsystem *css = to_css(sch->dev.parent); return ccw_device_move_to_sch(cdev, css->pseudo_subchannel); }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter3775.51%125.00%
cornelia huckcornelia huck714.29%125.00%
martin schwidefskymartin schwidefsky510.20%250.00%
Total49100.00%4100.00%


static void io_subchannel_irq(struct subchannel *sch) { struct ccw_device *cdev; cdev = sch_get_cdev(sch); CIO_TRACE_EVENT(6, "IRQ"); CIO_TRACE_EVENT(6, dev_name(&sch->dev)); if (cdev) dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); else inc_irq_stat(IRQIO_CIO); }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck4880.00%233.33%
kay sieverskay sievers46.67%116.67%
peter oberparleiterpeter oberparleiter46.67%116.67%
sebastian ottsebastian ott23.33%116.67%
heiko carstensheiko carstens23.33%116.67%
Total60100.00%6100.00%


void io_subchannel_init_config(struct subchannel *sch) { memset(&sch->config, 0, sizeof(sch->config)); sch->config.csense = 1; }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott35100.00%1100.00%
Total35100.00%1100.00%


static void io_subchannel_init_fields(struct subchannel *sch) { if (cio_is_console(sch->schid)) sch->opm = 0xff; else sch->opm = chp_get_sch_opm(sch); sch->lpm = sch->schib.pmcw.pam & sch->opm; sch->isc = cio_is_console(sch->schid) ? CONSOLE_ISC : IO_SCH_ISC; CIO_MSG_EVENT(6, "Detected device %04x on subchannel 0.%x.%04X" " - PIM = %02X, PAM = %02X, POM = %02X\n", sch->schib.pmcw.dev, sch->schid.ssid, sch->schid.sch_no, sch->schib.pmcw.pim, sch->schib.pmcw.pam, sch->schib.pmcw.pom); io_subchannel_init_config(sch); }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck12096.77%250.00%
sebastian ottsebastian ott32.42%125.00%
martin schwidefskymartin schwidefsky10.81%125.00%
Total124100.00%4100.00%

/* * Note: We always return 0 so that we bind to the device even on error. * This is needed so that our remove function is called on unregister. */
static int io_subchannel_probe(struct subchannel *sch) { struct io_subchannel_private *io_priv; struct ccw_device *cdev; int rc; if (cio_is_console(sch->schid)) { rc = sysfs_create_group(&sch->dev.kobj, &io_subchannel_attr_group); if (rc) CIO_MSG_EVENT(0, "Failed to create io subchannel " "attributes for subchannel " "0.%x.%04x (rc=%d)\n", sch->schid.ssid, sch->schid.sch_no, rc); /* * The console subchannel already has an associated ccw_device. * Throw the delayed uevent for the subchannel, register * the ccw_device and exit. */ dev_set_uevent_suppress(&sch->dev, 0); kobject_uevent(&sch->dev.kobj, KOBJ_ADD); cdev = sch_get_cdev(sch); rc = ccw_device_add(cdev); if (rc) { /* Release online reference. */ put_device(&cdev->dev); goto out_schedule; } if (atomic_dec_and_test(&ccw_device_init_count)) wake_up(&ccw_device_init_wq); return 0; } io_subchannel_init_fields(sch); rc = cio_commit_config(sch); if (rc) goto out_schedule; rc = sysfs_create_group(&sch->dev.kobj, &io_subchannel_attr_group); if (rc) goto out_schedule; /* Allocate I/O subchannel private data. */ io_priv = kzalloc(sizeof(*io_priv), GFP_KERNEL | GFP_DMA); if (!io_priv) goto out_schedule; set_io_private(sch, io_priv); css_schedule_eval(sch->schid); return 0; out_schedule: spin_lock_irq(sch->lock); css_sched_sch_todo(sch, SCH_TODO_UNREG); spin_unlock_irq(sch->lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck9637.35%628.57%
peter oberparleiterpeter oberparleiter7328.40%419.05%
sebastian ottsebastian ott4216.34%628.57%
martin schwidefskymartin schwidefsky4015.56%314.29%
lei minglei ming51.95%14.76%
andrew mortonandrew morton10.39%14.76%
Total257100.00%21100.00%


static int io_subchannel_remove (struct subchannel *sch) { struct io_subchannel_private *io_priv = to_io_private(sch); struct ccw_device *cdev; cdev = sch_get_cdev(sch); if (!cdev) goto out_free; io_subchannel_quiesce(sch); /* Set ccw device to not operational and drop reference. */ spin_lock_irq(cdev->ccwlock); sch_set_cdev(sch, NULL); set_io_private(sch, NULL); cdev->private->state = DEV_STATE_NOT_OPER; spin_unlock_irq(cdev->ccwlock); ccw_device_unregister(cdev); out_free: kfree(io_priv); sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck3329.73%541.67%
andrew mortonandrew morton3329.73%216.67%
sebastian ottsebastian ott2522.52%325.00%
martin schwidefskymartin schwidefsky1513.51%18.33%
peter oberparleiterpeter oberparleiter54.50%18.33%
Total111100.00%12100.00%


static void io_subchannel_verify(struct subchannel *sch) { struct ccw_device *cdev; cdev = sch_get_cdev(sch); if (cdev) dev_fsm_event(cdev, DEV_EVENT_VERIFY); }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton2882.35%133.33%
cornelia huckcornelia huck617.65%266.67%
Total34100.00%3100.00%


static void io_subchannel_terminate_path(struct subchannel *sch, u8 mask) { struct ccw_device *cdev; cdev = sch_get_cdev(sch); if (!cdev) return; if (cio_update_schib(sch)) goto err; /* Check for I/O on path. */ if (scsw_actl(&sch->schib.scsw) == 0 || sch->schib.pmcw.lpum != mask) goto out; if (cdev->private->state == DEV_STATE_ONLINE) { ccw_device_kill_io(cdev); goto out; } if (cio_clear(sch)) goto err; out: /* Trigger path verification. */ dev_fsm_event(cdev, DEV_EVENT_VERIFY); return; err: dev_fsm_event(cdev, DEV_EVENT_NOTOPER); }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter5142.50%116.67%
andrew mortonandrew morton4335.83%116.67%
cornelia huckcornelia huck2621.67%466.67%
Total120100.00%6100.00%


static int io_subchannel_chp_event(struct subchannel *sch, struct chp_link *link, int event) { struct ccw_device *cdev = sch_get_cdev(sch); int mask; mask = chp_ssd_get_mask(&sch->ssd_info, link); if (!mask) return 0; switch (event) { case CHP_VARY_OFF: sch->opm &= ~mask; sch->lpm &= ~mask; if (cdev) cdev->private->path_gone_mask |= mask; io_subchannel_terminate_path(sch, mask); break; case CHP_VARY_ON: sch->opm |= mask; sch->lpm |= mask; if (cdev) cdev->private->path_new_mask |= mask; io_subchannel_verify(sch); break; case CHP_OFFLINE: if (cio_update_schib(sch)) return -ENODEV; if (cdev) cdev->private->path_gone_mask |= mask; io_subchannel_terminate_path(sch, mask); break; case CHP_ONLINE: if (cio_update_schib(sch)) return -ENODEV; sch->lpm |= mask & sch->opm; if (cdev) cdev->private->path_new_mask |= mask; io_subchannel_verify(sch); break; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck11053.14%444.44%
sebastian ottsebastian ott6129.47%222.22%
martin schwidefskymartin schwidefsky3114.98%222.22%
andrew mortonandrew morton52.42%111.11%
Total207100.00%9100.00%


static void io_subchannel_quiesce(struct subchannel *sch) { struct ccw_device *cdev; int ret; spin_lock_irq(sch->lock); cdev = sch_get_cdev(sch); if (cio_is_console(sch->schid)) goto out_unlock; if (!sch->schib.pmcw.ena) goto out_unlock; ret = cio_disable_subchannel(sch); if (ret != -EBUSY) goto out_unlock; if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, ERR_PTR(-EIO)); while (ret == -EBUSY) { cdev->private->state = DEV_STATE_QUIESCE; cdev->private->iretry = 255; ret = ccw_device_cancel_halt_clear(cdev); if (ret == -EBUSY) { ccw_device_set_timeout(cdev, HZ/10); spin_unlock_irq(sch->lock); wait_event(cdev->private->wait_q, cdev->private->state != DEV_STATE_QUIESCE); spin_lock_irq(sch->lock); } ret = cio_disable_subchannel(sch); } out_unlock: spin_unlock_irq(sch->lock); }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck7035.35%114.29%
sebastian ottsebastian ott6432.32%228.57%
martin schwidefskymartin schwidefsky4221.21%114.29%
peter oberparleiterpeter oberparleiter2211.11%342.86%
Total198100.00%7100.00%


static void io_subchannel_shutdown(struct subchannel *sch) { io_subchannel_quiesce(sch); }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott16100.00%1100.00%
Total16100.00%1100.00%


static int device_is_disconnected(struct ccw_device *cdev) { if (!cdev) return 0; return (cdev->private->state == DEV_STATE_DISCONNECTED || cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID); }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck2360.53%150.00%
martin schwidefskymartin schwidefsky1539.47%150.00%
Total38100.00%2100.00%


static int recovery_check(struct device *dev, void *data) { struct ccw_device *cdev = to_ccwdev(dev); int *redo = data; spin_lock_irq(cdev->ccwlock); switch (cdev->private->state) { case DEV_STATE_DISCONNECTED: CIO_MSG_EVENT(3, "recovery: trigger 0.%x.%04x\n", cdev->private->dev_id.ssid, cdev->private->dev_id.devno); dev_fsm_event(cdev, DEV_EVENT_VERIFY); *redo = 1; break; case DEV_STATE_DISCONNECTED_SENSE_ID: *redo = 1; break; } spin_unlock_irq(cdev->ccwlock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck5854.72%233.33%
martin schwidefskymartin schwidefsky2725.47%116.67%
andrew mortonandrew morton2119.81%350.00%
Total106100.00%6100.00%


static void recovery_work_func(struct work_struct *unused) { int redo = 0; bus_for_each_dev(&ccw_bus_type, NULL, &redo, recovery_check); if (redo) { spin_lock_irq(&recovery_lock); if (!timer_pending(&recovery_timer)) { if (recovery_phase < ARRAY_SIZE(recovery_delay) - 1) recovery_phase++; mod_timer(&recovery_timer, jiffies + recovery_delay[recovery_phase] * HZ); } spin_unlock_irq(&recovery_lock); } else CIO_MSG_EVENT(4, "recovery: end\n"); }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck95100.00%3100.00%
Total95100.00%3100.00%

static DECLARE_WORK(recovery_work, recovery_work_func);
static void recovery_func(unsigned long data) { /* * We can't do our recovery in softirq context and it's not * performance critical, so we schedule it. */ schedule_work(&recovery_work); }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck1164.71%150.00%
martin schwidefskymartin schwidefsky635.29%150.00%
Total17100.00%2100.00%


static void ccw_device_schedule_recovery(void) { unsigned long flags; CIO_MSG_EVENT(4, "recovery: schedule\n"); spin_lock_irqsave(&recovery_lock, flags); if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) { recovery_phase = 0; mod_timer(&recovery_timer, jiffies + recovery_delay[0] * HZ); } spin_unlock_irqrestore(&recovery_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck6388.73%266.67%
martin schwidefskymartin schwidefsky811.27%133.33%
Total71100.00%3100.00%


static int purge_fn(struct device *dev, void *data) { struct ccw_device *cdev = to_ccwdev(dev); struct ccw_dev_id *id = &cdev->private->dev_id; spin_lock_irq(cdev->ccwlock); if (is_blacklisted(id->ssid, id->devno) && (cdev->private->state == DEV_STATE_OFFLINE) && (atomic_cmpxchg(&cdev->private->onoff, 0, 1) == 0)) { CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", id->ssid, id->devno); ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); atomic_set(&cdev->private->onoff, 0); } spin_unlock_irq(cdev->ccwlock); /* Abort loop in case of pending signal. */ if (signal_pending(current)) return -EINTR; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter143100.00%3100.00%
Total143100.00%3100.00%

/** * ccw_purge_blacklisted - purge unused, blacklisted devices * * Unregister all ccw devices that are offline and on the blacklist. */
int ccw_purge_blacklisted(void) { CIO_MSG_EVENT(2, "ccw: purging blacklisted devices\n"); bus_for_each_dev(&ccw_bus_type, NULL, NULL, purge_fn); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter29100.00%1100.00%
Total29100.00%1100.00%


void ccw_device_set_disconnected(struct ccw_device *cdev) { if (!cdev) return; ccw_device_set_timeout(cdev, 0); cdev->private->flags.fake_irb = 0; cdev->private->state = DEV_STATE_DISCONNECTED; if (cdev->online) ccw_device_schedule_recovery(); }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck4998.00%266.67%
peter oberparleiterpeter oberparleiter12.00%133.33%
Total50100.00%3100.00%


void ccw_device_set_notoper(struct ccw_device *cdev) { struct subchannel *sch = to_subchannel(cdev->dev.parent); CIO_TRACE_EVENT(2, "notoper"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); ccw_device_set_timeout(cdev, 0); cio_disable_subchannel(sch); cdev->private->state = DEV_STATE_NOT_OPER; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter6093.75%150.00%
cornelia huckcornelia huck46.25%150.00%
Total64100.00%2100.00%

enum io_sch_action { IO_SCH_UNREG, IO_SCH_ORPH_UNREG, IO_SCH_ATTACH, IO_SCH_UNREG_ATTACH, IO_SCH_ORPH_ATTACH, IO_SCH_REPROBE, IO_SCH_VERIFY, IO_SCH_DISC, IO_SCH_NOP, };
static enum io_sch_action sch_get_action(struct subchannel *sch) { struct ccw_device *cdev; cdev = sch_get_cdev(sch); if (cio_update_schib(sch)) { /* Not operational. */ if (!cdev) return IO_SCH_UNREG; if (ccw_device_notify(cdev, CIO_GONE) != NOTIFY_OK) return IO_SCH_UNREG; return IO_SCH_ORPH_UNREG; } /* Operational. */ if (!cdev) return IO_SCH_ATTACH; if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { if (ccw_device_notify(cdev, CIO_GONE) != NOTIFY_OK) return IO_SCH_UNREG_ATTACH; return IO_SCH_ORPH_ATTACH; } if ((sch->schib.pmcw.pam & sch->opm) == 0) { if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK) return IO_SCH_UNREG; return IO_SCH_DISC; } if (device_is_disconnected(cdev)) return IO_SCH_REPROBE; if (cdev->online && !cdev->private->flags.resuming) return IO_SCH_VERIFY; if (cdev->private->state == DEV_STATE_NOT_OPER) return IO_SCH_UNREG_ATTACH; return IO_SCH_NOP; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter14678.49%233.33%
sebastian ottsebastian ott2815.05%350.00%
cornelia huckcornelia huck126.45%116.67%
Total186100.00%6100.00%

/** * io_subchannel_sch_event - process subchannel event * @sch: subchannel * @process: non-zero if function is called in process context * * An unspecified event occurred for this subchannel. Adjust data according * to the current operational state of the subchannel and device. Return * zero when the event has been handled sufficiently or -EAGAIN when this * function should be called again in process context. */
static int io_subchannel_sch_event(struct subchannel *sch, int process) { unsigned long flags; struct ccw_device *cdev; struct ccw_dev_id dev_id; enum io_sch_action action; int rc = -EAGAIN; spin_lock_irqsave(sch->lock, flags); if (!device_is_registered(&sch->dev)) goto out_unlock; if (work_pending(&sch->todo_work)) goto out_unlock; cdev = sch_get_cdev(sch); if (cdev && work_pending(&cdev->private->todo_work)) goto out_unlock; action = sch_get_action(sch); CIO_MSG_EVENT(2, "event: sch 0.%x.%04x, process=%d, action=%d\n", sch->schid.ssid, sch->schid.sch_no, process, action); /* Perform immediate actions while holding the lock. */ switch (action) { case IO_SCH_REPROBE: /* Trigger device recognition. */ ccw_device_trigger_reprobe(cdev); rc = 0; goto out_unlock; case IO_SCH_VERIFY: /* Trigger path verification. */ io_subchannel_verify(sch); rc = 0; goto out_unlock; case IO_SCH_DISC: ccw_device_set_disconnected(cdev); rc = 0; goto out_unlock; case IO_SCH_ORPH_UNREG: case IO_SCH_ORPH_ATTACH: ccw_device_set_disconnected(cdev); break; case IO_SCH_UNREG_ATTACH: case IO_SCH_UNREG: if (!cdev) break; if (cdev->private->state == DEV_STATE_SENSE_ID) { /* * Note: delayed work triggered by this event * and repeated calls to sch_event are synchronized * by the above check for work_pending(cdev). */ dev_fsm_event(cdev, DEV_EVENT_NOTOPER); } else ccw_device_set_notoper(cdev); break; case IO_SCH_NOP: rc = 0; goto out_unlock; default: break; } spin_unlock_irqrestore(sch->lock, flags); /* All other actions require process context. */ if (!process) goto out; /* Handle attached ccw device. */ switch (action) { case IO_SCH_ORPH_UNREG: case IO_SCH_ORPH_ATTACH: /* Move ccw device to orphanage. */ rc = ccw_device_move_to_orph(cdev); if (rc) goto out; break; case IO_SCH_UNREG_ATTACH: spin_lock_irqsave(sch->lock, flags); if (cdev->private->flags.resuming) { /* Device will be handled later. */ rc = 0; goto out_unlock; } sch_set_cdev(sch, NULL); spin_unlock_irqrestore(sch->lock, flags); /* Unregister ccw device. */ ccw_device_unregister(cdev); break; default: break; } /* Handle subchannel. */ switch (action) { case IO_SCH_ORPH_UNREG: case IO_SCH_UNREG: if (!cdev || !cdev->private->flags.resuming) css_sch_device_unregister(sch); break; case IO_SCH_ORPH_ATTACH: case IO_SCH_UNREG_ATTACH: case IO_SCH_ATTACH: dev_id.ssid = sch->schid.ssid; dev_id.devno = sch->schib.pmcw.dev; cdev = get_ccwdev_by_dev_id(&dev_id); if (!cdev) { sch_create_and_recog_new_device(sch); break; } rc = ccw_device_move_to_sch(cdev, sch); if (rc) { /* Release reference from get_ccwdev_by_dev_id() */ put_device(&cdev->dev); goto out; } spin_lock_irqsave(sch->lock, flags); ccw_device_trigger_reprobe(cdev); spin_unlock_irqrestore(sch->lock, flags); /* Release reference from get_ccwdev_by_dev_id() */ put_device(&cdev->dev); break; default: break; } return 0; out_unlock: spin_unlock_irqrestore(sch->lock, flags); out: return rc; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter33264.59%545.45%
cornelia huckcornelia huck9919.26%218.18%
sebastian ottsebastian ott8316.15%436.36%
Total514100.00%11100.00%


static void ccw_device_set_int_class(struct ccw_device *cdev) { struct ccw_driver *cdrv = cdev->drv; /* Note: we interpret class 0 in this context as an uninitialized * field since it translates to a non-I/O interrupt class. */ if (cdrv->int_class != 0) cdev->private->int_class = cdrv->int_class; else cdev->private->int_class = IRQIO_CIO; }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott48100.00%1100.00%
Total48100.00%1100.00%

#ifdef CONFIG_CCW_CONSOLE
int __init ccw_device_enable_console(struct ccw_device *cdev) { struct subchannel *sch = to_subchannel(cdev->dev.parent); int rc; if (!cdev->drv || !cdev->handler) return -EINVAL; io_subchannel_init_fields(sch); rc = cio_commit_config(sch); if (rc) return rc; sch->driver = &io_subchannel_driver; io_subchannel_recog(cdev, sch); /* Now wait for the async. recognition to come to an end. */ spin_lock_irq(cdev->ccwlock); while (!dev_fsm_final_state(cdev)) ccw_device_wait_idle(cdev); /* Hold on to an extra reference while device is online. */ get_device(&cdev->dev); rc = ccw_device_online(cdev); if (rc) goto out_unlock; while (!dev_fsm_final_state(cdev)) ccw_device_wait_idle(cdev); if (cdev->private->state == DEV_STATE_ONLINE) cdev->online = 1; else rc = -EIO; out_unlock: spin_unlock_irq(cdev->ccwlock); if (rc) /* Give up online reference since onlining failed. */ put_device(&cdev->dev); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck9150.28%116.67%
sebastian ottsebastian ott8949.17%466.67%
peter oberparleiterpeter oberparleiter10.55%116.67%
Total181100.00%6100.00%


struct ccw_device * __init ccw_device_create_console(struct ccw_driver *drv) { struct io_subchannel_private *io_priv; struct ccw_device *cdev; struct subchannel *sch; sch = cio_probe_console(); if (IS_ERR(sch)) return ERR_CAST(sch); io_priv = kzalloc(sizeof(*io_priv), GFP_KERNEL | GFP_DMA); if (!io_priv) { put_device(&sch->dev); return ERR_PTR(-ENOMEM); } set_io_private(sch, io_priv); cdev = io_subchannel_create_ccwdev(sch); if (IS_ERR(cdev)) { put_device(&sch->dev); kfree(io_priv); return cdev; } cdev->drv = drv; ccw_device_set_int_class(cdev); return cdev; }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott11080.88%685.71%
cornelia huckcornelia huck2619.12%114.29%
Total136100.00%7100.00%


void __init ccw_device_destroy_console(struct ccw_device *cdev) { struct subchannel *sch = to_subchannel(cdev->dev.parent); struct io_subchannel_private *io_priv = to_io_private(sch); set_io_private(sch, NULL); put_device(&sch->dev); put_device(&cdev->dev); kfree(io_priv); }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott5993.65%375.00%
cornelia huckcornelia huck46.35%125.00%
Total63100.00%4100.00%

/** * ccw_device_wait_idle() - busy wait for device to become idle * @cdev: ccw device * * Poll until activity control is zero, that is, no function or data * transfer is pending/active. * Called with device lock being held. */
void ccw_device_wait_idle(struct ccw_device *cdev) { struct subchannel *sch = to_subchannel(cdev->dev.parent); while (1) { cio_tsch(sch); if (sch->schib.scsw.cmd.actl == 0) break; udelay_simple(100); } }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott55100.00%1100.00%
Total55100.00%1100.00%

static int ccw_device_pm_restore(struct device *dev);
int ccw_device_force_console(struct ccw_device *cdev) { return ccw_device_pm_restore(&cdev->dev); }

Contributors

PersonTokensPropCommitsCommitProp
martin schwidefskymartin schwidefsky1368.42%150.00%
sebastian ottsebastian ott631.58%150.00%
Total19100.00%2100.00%

EXPORT_SYMBOL_GPL(ccw_device_force_console); #endif /* * get ccw_device matching the busid, but only if owned by cdrv */
static int __ccwdev_check_busid(struct device *dev, void *id) { char *bus_id; bus_id = id; return (strcmp(bus_id, dev_name(dev)) == 0); }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck3489.47%133.33%
kay sieverskay sievers410.53%266.67%
Total38100.00%3100.00%

/** * get_ccwdev_by_busid() - obtain device from a bus id * @cdrv: driver the device is owned by * @bus_id: bus id of the device to be searched * * This function searches all devices owned by @cdrv for a device with a bus * id matching @bus_id. * Returns: * If a match is found, its reference count of the found device is increased * and it is returned; else %NULL is returned. */
struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id) { struct device *dev; dev = driver_find_device(&cdrv->driver, NULL, (void *)bus_id, __ccwdev_check_busid); return dev ? to_ccwdev(dev) : NULL; }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck5096.15%150.00%
sebastian ottsebastian ott23.85%150.00%
Total52100.00%2100.00%

/************************** device driver handling ************************/ /* This is the implementation of the ccw_driver class. The probe, remove * and release methods are initially very similar to the device_driver * implementations, with the difference that they have ccw_device * arguments. * * A ccw driver also contains the information that is needed for * device matching. */
static int ccw_device_probe (struct device *dev) { struct ccw_device *cdev = to_ccwdev(dev); struct ccw_driver *cdrv = to_ccwdrv(dev->driver); int ret; cdev->drv = cdrv; /* to let the driver call _set_online */ ccw_device_set_int_class(cdev); ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV; if (ret) { cdev->drv = NULL; cdev->private->int_class = IRQIO_CIO; return ret; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck7785.56%125.00%
peter oberparleiterpeter oberparleiter910.00%125.00%
sebastian ottsebastian ott33.33%125.00%
heiko carstensheiko carstens11.11%125.00%
Total90100.00%4100.00%


static int ccw_device_remove(struct device *dev) { struct ccw_device *cdev = to_ccwdev(dev); struct ccw_driver *cdrv = cdev->drv; int ret; if (cdrv->remove) cdrv->remove(cdev); spin_lock_irq(cdev->ccwlock); if (cdev->online) { cdev->online = 0; ret = ccw_device_offline(cdev); spin_unlock_irq(cdev->ccwlock); if (ret == 0) wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); else CIO_MSG_EVENT(0, "ccw_device_offline returned %d, " "device 0.%x.%04x\n", ret, cdev->private->dev_id.ssid, cdev->private->dev_id.devno); /* Give up reference obtained in ccw_device_set_online(). */ put_device(&cdev->dev); spin_lock_irq(cdev->ccwlock); } ccw_device_set_timeout(cdev, 0); cdev->drv = NULL; cdev->private->int_class = IRQIO_CIO; spin_unlock_irq(cdev->ccwlock); __disable_cmf(cdev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck14681.11%233.33%
sebastian ottsebastian ott2614.44%233.33%
peter oberparleiterpeter oberparleiter73.89%116.67%
heiko carstensheiko carstens10.56%116.67%
Total180100.00%6100.00%


static void ccw_device_shutdown(struct device *dev) { struct ccw_device *cdev; cdev = to_ccwdev(dev); if (cdev->drv && cdev->drv->shutdown) cdev->drv->shutdown(cdev); __disable_cmf(cdev); }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck4897.96%150.00%
sebastian ottsebastian ott12.04%150.00%
Total49100.00%2100.00%


static int ccw_device_pm_prepare(struct device *dev) { struct ccw_device *cdev = to_ccwdev(dev); if (work_pending(&cdev->private->todo_work)) return -EAGAIN; /* Fail while device is being set online/offline. */ if (atomic_read(&cdev->private->onoff)) return -EAGAIN; if (cdev->online && cdev->drv && cdev->drv->prepare) return cdev->drv->prepare(cdev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott8298.80%150.00%
peter oberparleiterpeter oberparleiter11.20%150.00%
Total83100.00%2100.00%


static void ccw_device_pm_complete(struct device *dev) { struct ccw_device *cdev = to_ccwdev(dev); if (cdev->online && cdev->drv && cdev->drv->complete) cdev->drv->complete(cdev); }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott46100.00%1100.00%
Total46100.00%1100.00%


static int ccw_device_pm_freeze(struct device *dev) { struct ccw_device *cdev = to_ccwdev(dev); struct subchannel *sch = to_subchannel(cdev->dev.parent); int ret, cm_enabled; /* Fail suspend while device is in transistional state. */ if (!dev_fsm_final_state(cdev)) return -EAGAIN; if (!cdev->online) return 0; if (cdev->drv && cdev->drv->freeze) { ret = cdev->drv->freeze(cdev); if (ret) return ret; } spin_lock_irq(sch->lock); cm_enabled = cdev->private->cmb != NULL; spin_unlock_irq(sch->lock); if (cm_enabled) { /* Don't have the css write on memory. */ ret = ccw_set_cmf(cdev, 0); if (ret) return ret; } /* From here on, disallow device driver I/O. */ spin_lock_irq(sch->lock); ret = cio_disable_subchannel(sch); spin_unlock_irq(sch->lock); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott167100.00%1100.00%
Total167100.00%1100.00%


static int ccw_device_pm_thaw(struct device *dev) { struct ccw_device *cdev = to_ccwdev(dev); struct subchannel *sch = to_subchannel(cdev->dev.parent); int ret, cm_enabled; if (!cdev->online) return 0; spin_lock_irq(sch->lock); /* Allow device driver I/O again. */ ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); cm_enabled = cdev->private->cmb != NULL; spin_unlock_irq(sch->lock); if (ret) return ret; if (cm_enabled) { ret = ccw_set_cmf(cdev, 1); if (ret) return ret; } if (cdev->drv && cdev->drv->thaw) ret = cdev->drv->thaw(cdev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott145100.00%1100.00%
Total145100.00%1100.00%


static void __ccw_device_pm_restore(struct ccw_device *cdev) { struct subchannel *sch = to_subchannel(cdev->dev.parent); spin_lock_irq(sch->lock); if (cio_is_console(sch->schid)) { cio_enable_subchannel(sch, (u32)(addr_t)sch); goto out_unlock; } /* * While we were sleeping, devices may have gone or become * available again. Kick re-detection. */ cdev->private->flags.resuming = 1; cdev->private->path_new_mask = LPM_ANYPATH; css_sched_sch_todo(sch, SCH_TODO_EVAL); spin_unlock_irq(sch->lock); css_wait_for_slow_path(); /* cdev may have been moved to a different subchannel. */ sch = to_subchannel(cdev->dev.parent); spin_lock_irq(sch->lock); if (cdev->private->state != DEV_STATE_ONLINE && cdev->private->state != DEV_STATE_OFFLINE) goto out_unlock; ccw_device_recognition(cdev); spin_unlock_irq(sch->lock); wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev) || cdev->private->state == DEV_STATE_DISCONNECTED); spin_lock_irq(sch->lock); out_unlock: cdev->private->flags.resuming = 0; spin_unlock_irq(sch->lock); }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott195100.00%4100.00%
Total195100.00%4100.00%


static int resume_handle_boxed(struct ccw_device *cdev) { cdev->private->state = DEV_STATE_BOXED; if (ccw_device_notify(cdev, CIO_BOXED) == NOTIFY_OK) return 0; ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); return -ENODEV; }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott4193.18%266.67%
peter oberparleiterpeter oberparleiter36.82%133.33%
Total44100.00%3100.00%


static int resume_handle_disc(struct ccw_device *cdev) { cdev->private->state = DEV_STATE_DISCONNECTED; if (ccw_device_notify(cdev, CIO_GONE) == NOTIFY_OK) return 0; ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); return -ENODEV; }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott4193.18%266.67%
peter oberparleiterpeter oberparleiter36.82%133.33%
Total44100.00%3100.00%


static int ccw_device_pm_restore(struct device *dev) { struct ccw_device *cdev = to_ccwdev(dev); struct subchannel *sch; int ret = 0; __ccw_device_pm_restore(cdev); sch = to_subchannel(cdev->dev.parent); spin_lock_irq(sch->lock); if (cio_is_console(sch->schid)) goto out_restore; /* check recognition results */ switch (cdev->private->state) { case DEV_STATE_OFFLINE: case DEV_STATE_ONLINE: cdev->private->flags.donotify = 0; break; case DEV_STATE_BOXED: ret = resume_handle_boxed(cdev); if (ret) goto out_unlock; goto out_restore; default: ret = resume_handle_disc(cdev); if (ret) goto out_unlock; goto out_restore; } /* check if the device type has changed */ if (!ccw_device_test_sense_data(cdev)) { ccw_device_update_sense_data(cdev); ccw_device_sched_todo(cdev, CDEV_TODO_REBIND); ret = -ENODEV; goto out_unlock; } if (!cdev->online) goto out_unlock; if (ccw_device_online(cdev)) { ret = resume_handle_disc(cdev); if (ret) goto out_unlock; goto out_restore; } spin_unlock_irq(sch->lock); wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); spin_lock_irq(sch->lock); if (ccw_device_notify(cdev, CIO_OPER) == NOTIFY_BAD) { ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); ret = -ENODEV; goto out_unlock; } /* reenable cmf, if needed */ if (cdev->private->cmb) { spin_unlock_irq(sch->lock); ret = ccw_set_cmf(cdev, 1); spin_lock_irq(sch->lock); if (ret) { CIO_MSG_EVENT(2, "resume: cdev 0.%x.%04x: cmf failed " "(rc=%d)\n", cdev->private->dev_id.ssid, cdev->private->dev_id.devno, ret); ret = 0; } } out_restore: spin_unlock_irq(sch->lock); if (cdev->online && cdev->drv && cdev->drv->restore) ret = cdev->drv->restore(cdev); return ret; out_unlock: spin_unlock_irq(sch->lock); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott37499.47%375.00%
peter oberparleiterpeter oberparleiter20.53%125.00%
Total376100.00%4100.00%

static const struct dev_pm_ops ccw_pm_ops = { .prepare = ccw_device_pm_prepare, .complete = ccw_device_pm_complete, .freeze = ccw_device_pm_freeze, .thaw = ccw_device_pm_thaw, .restore = ccw_device_pm_restore, }; static struct bus_type ccw_bus_type = { .name = "ccw", .match = ccw_bus_match, .uevent = ccw_uevent, .probe = ccw_device_probe, .remove = ccw_device_remove, .shutdown = ccw_device_shutdown, .pm = &ccw_pm_ops, }; /** * ccw_driver_register() - register a ccw driver * @cdriver: driver to be registered * * This function is mainly a wrapper around driver_register(). * Returns: * %0 on success and a negative error value on failure. */
int ccw_driver_register(struct ccw_driver *cdriver) { struct device_driver *drv = &cdriver->driver; drv->bus = &ccw_bus_type; return driver_register(drv); }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck33100.00%1100.00%
Total33100.00%1100.00%

/** * ccw_driver_unregister() - deregister a ccw driver * @cdriver: driver to be deregistered * * This function is mainly a wrapper around driver_unregister(). */
void ccw_driver_unregister(struct ccw_driver *cdriver) { driver_unregister(&cdriver->driver); }

Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck18100.00%1100.00%
Total18100.00%1100.00%


static void ccw_device_todo(struct work_struct *work) { struct ccw_device_private *priv; struct ccw_device *cdev; struct subchannel *sch; enum cdev_todo todo; priv = container_of(work, struct ccw_device_private, todo_work); cdev = priv->cdev; sch = to_subchannel(cdev->dev.parent); /* Find out todo. */ spin_lock_irq(cdev->ccwlock); todo = priv->todo; priv->todo = CDEV_TODO_NOTHING; CIO_MSG_EVENT(4, "cdev_todo: cdev=0.%x.%04x todo=%d\n", priv->dev_id.ssid, priv->dev_id.devno, todo); spin_unlock_irq(cdev->ccwlock); /* Perform todo. */ switch (todo) { case CDEV_TODO_ENABLE_CMF: cmf_reenable(cdev); break; case CDEV_TODO_REBIND: ccw_device_do_unbind_bind(cdev); break; case CDEV_TODO_REGISTER: io_subchannel_register(cdev); break; case CDEV_TODO_UNREG_EVAL: if (!sch_is_pseudo_sch(sch)) css_schedule_eval(sch->schid); /* fall-through */ case CDEV_TODO_UNREG: if (sch_is_pseudo_sch(sch)) ccw_device_unregister(cdev); else ccw_device_call_sch_unregister(cdev); break; default: break; } /* Release workqueue ref. */ put_device(&cdev->dev); }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter193100.00%1100.00%
Total193100.00%1100.00%

/** * ccw_device_sched_todo - schedule ccw device operation * @cdev: ccw device * @todo: todo * * Schedule the operation identified by @todo to be performed on the slow path * workqueue. Do nothing if another operation with higher priority is already * scheduled. Needs to be called with ccwdev lock held. */
void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo) { CIO_MSG_EVENT(4, "cdev_todo: sched cdev=0.%x.%04x todo=%d\n", cdev->private->dev_id.ssid, cdev->private->dev_id.devno, todo); if (cdev->private->todo >= todo) return; cdev->private->todo = todo; /* Get workqueue ref. */ if (!get_device(&cdev->dev)) return; if (!queue_work(cio_work_q, &cdev->private->todo_work)) { /* Already queued, release workqueue ref. */ put_device(&cdev->dev); } }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter9698.97%150.00%
sebastian ottsebastian ott11.03%150.00%
Total97100.00%2100.00%

/** * ccw_device_siosl() - initiate logging * @cdev: ccw device * * This function is used to invoke model-dependent logging within the channel * subsystem. */
int ccw_device_siosl(struct ccw_device *cdev) { struct subchannel *sch = to_subchannel(cdev->dev.parent); return chsc_siosl(sch->schid); }

Contributors

PersonTokensPropCommitsCommitProp
michael ernstmichael ernst32100.00%1100.00%
Total32100.00%1100.00%

EXPORT_SYMBOL_GPL(ccw_device_siosl); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(ccw_device_set_online); EXPORT_SYMBOL(ccw_device_set_offline); EXPORT_SYMBOL(ccw_driver_register); EXPORT_SYMBOL(ccw_driver_unregister); EXPORT_SYMBOL(get_ccwdev_by_busid);

Overall Contributors

PersonTokensPropCommitsCommitProp
cornelia huckcornelia huck271027.66%4327.04%
sebastian ottsebastian ott259626.50%5534.59%
peter oberparleiterpeter oberparleiter200320.45%2012.58%
martin schwidefskymartin schwidefsky139014.19%127.55%
andrew mortonandrew morton5365.47%95.66%
michael ernstmichael ernst4074.15%42.52%
bastian blankbastian blank720.73%10.63%
yani ioannouyani ioannou300.31%10.63%
kay sieverskay sievers160.16%31.89%
joe perchesjoe perches100.10%10.63%
heiko carstensheiko carstens70.07%31.89%
patrick mochelpatrick mochel60.06%10.63%
lei minglei ming50.05%10.63%
tim schmielautim schmielau40.04%10.63%
jingoo hanjingoo han10.01%10.63%
paul jacksonpaul jackson10.01%10.63%
david brownelldavid brownell10.01%10.63%
alexey dobriyanalexey dobriyan10.01%10.63%
Total9796100.00%159100.00%
Directory: drivers/s390/cio
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}