From: Martin Schwidefsky <schwidefsky@de.ibm.com>
To: linux-kernel@vger.kernel.org, linux-s390@vger.kernel.org
Cc: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>,
Martin Schwidefsky <schwidefsky@de.ibm.com>,
Heiko Carstens <heiko.carstens@de.ibm.com>
Subject: [patch 05/38] cio: Introduce separate files for channel-path related code.
Date: Fri, 27 Apr 2007 16:05:08 +0200 [thread overview]
Message-ID: <20070427140512.863578656@de.ibm.com> (raw)
In-Reply-To: 20070427140503.087958775@de.ibm.com
[-- Attachment #1: 103-cio-chpid02.diff --]
[-- Type: text/plain, Size: 35004 bytes --]
From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
---
drivers/s390/cio/Makefile | 2
drivers/s390/cio/chp.c | 433 ++++++++++++++++++++++++++++++++++++++
drivers/s390/cio/chp.h | 37 +++
drivers/s390/cio/chsc.c | 473 +++---------------------------------------
drivers/s390/cio/chsc.h | 30 --
drivers/s390/cio/cio.c | 8
drivers/s390/cio/css.h | 1
drivers/s390/cio/device_fsm.c | 6
drivers/s390/cio/device_ops.c | 7
drivers/s390/s390mach.c | 1
10 files changed, 535 insertions(+), 463 deletions(-)
Index: quilt-2.6/drivers/s390/cio/chp.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ quilt-2.6/drivers/s390/cio/chp.c 2007-04-27 16:04:53.000000000 +0200
@@ -0,0 +1,433 @@
+/*
+ * drivers/s390/cio/chp.c
+ *
+ * Copyright IBM Corp. 1999,2007
+ * Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
+ * Arnd Bergmann (arndb@de.ibm.com)
+ * Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#include <linux/bug.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <asm/errno.h>
+
+#include "chpid.h"
+#include "cio.h"
+#include "css.h"
+#include "ioasm.h"
+#include "cio_debug.h"
+#include "chp.h"
+
+#define to_channelpath(device) container_of(device, struct channel_path, dev)
+
+/* Return channel_path struct for given chpid. */
+static inline struct channel_path *chpid_to_chp(struct chp_id chpid)
+{
+ return css[chpid.cssid]->chps[chpid.id];
+}
+
+/* Set vary state for given chpid. */
+static void set_chp_logically_online(struct chp_id chpid, int onoff)
+{
+ chpid_to_chp(chpid)->state = onoff;
+}
+
+/* On succes return 0 if channel-path is varied offline, 1 if it is varied
+ * online. Return -ENODEV if channel-path is not registered. */
+int chp_get_status(struct chp_id chpid)
+{
+ return (chpid_to_chp(chpid) ? chpid_to_chp(chpid)->state : -ENODEV);
+}
+
+/**
+ * chp_get_sch_opm - return opm for subchannel
+ * @sch: subchannel
+ *
+ * Calculate and return the operational path mask (opm) based on the chpids
+ * used by the subchannel and the status of the associated channel-paths.
+ */
+u8 chp_get_sch_opm(struct subchannel *sch)
+{
+ struct chp_id chpid;
+ int opm;
+ int i;
+
+ opm = 0;
+ chp_id_init(&chpid);
+ for (i=0; i < 8; i++) {
+ opm <<= 1;
+ chpid.id = sch->schib.pmcw.chpid[i];
+ if (chp_get_status(chpid) != 0)
+ opm |= 1;
+ }
+ return opm;
+}
+
+/**
+ * chp_is_registered - check if a channel-path is registered
+ * @chpid: channel-path ID
+ *
+ * Return non-zero if a channel-path with the given chpid is registered,
+ * zero otherwise.
+ */
+int chp_is_registered(struct chp_id chpid)
+{
+ return chpid_to_chp(chpid) != NULL;
+}
+
+/*
+ * Function: s390_vary_chpid
+ * Varies the specified chpid online or offline
+ */
+static int s390_vary_chpid(struct chp_id chpid, int on)
+{
+ char dbf_text[15];
+ int status;
+
+ sprintf(dbf_text, on?"varyon%x.%02x":"varyoff%x.%02x", chpid.cssid,
+ chpid.id);
+ CIO_TRACE_EVENT( 2, dbf_text);
+
+ status = chp_get_status(chpid);
+ if (status < 0) {
+ printk(KERN_ERR "Can't vary unknown chpid %x.%02x\n",
+ chpid.cssid, chpid.id);
+ return -EINVAL;
+ }
+
+ if (!on && !status) {
+ printk(KERN_ERR "chpid %x.%02x is already offline\n",
+ chpid.cssid, chpid.id);
+ return -EINVAL;
+ }
+
+ set_chp_logically_online(chpid, on);
+ chsc_chp_vary(chpid, on);
+ return 0;
+}
+
+/*
+ * Channel measurement related functions
+ */
+static ssize_t chp_measurement_chars_read(struct kobject *kobj, char *buf,
+ loff_t off, size_t count)
+{
+ struct channel_path *chp;
+ unsigned int size;
+
+ chp = to_channelpath(container_of(kobj, struct device, kobj));
+ if (!chp->cmg_chars)
+ return 0;
+
+ size = sizeof(struct cmg_chars);
+
+ if (off > size)
+ return 0;
+ if (off + count > size)
+ count = size - off;
+ memcpy(buf, chp->cmg_chars + off, count);
+ return count;
+}
+
+static struct bin_attribute chp_measurement_chars_attr = {
+ .attr = {
+ .name = "measurement_chars",
+ .mode = S_IRUSR,
+ .owner = THIS_MODULE,
+ },
+ .size = sizeof(struct cmg_chars),
+ .read = chp_measurement_chars_read,
+};
+
+static void chp_measurement_copy_block(struct cmg_entry *buf,
+ struct channel_subsystem *css,
+ struct chp_id chpid)
+{
+ void *area;
+ struct cmg_entry *entry, reference_buf;
+ int idx;
+
+ if (chpid.id < 128) {
+ area = css->cub_addr1;
+ idx = chpid.id;
+ } else {
+ area = css->cub_addr2;
+ idx = chpid.id - 128;
+ }
+ entry = area + (idx * sizeof(struct cmg_entry));
+ do {
+ memcpy(buf, entry, sizeof(*entry));
+ memcpy(&reference_buf, entry, sizeof(*entry));
+ } while (reference_buf.values[0] != buf->values[0]);
+}
+
+static ssize_t chp_measurement_read(struct kobject *kobj, char *buf,
+ loff_t off, size_t count)
+{
+ struct channel_path *chp;
+ struct channel_subsystem *css;
+ unsigned int size;
+
+ chp = to_channelpath(container_of(kobj, struct device, kobj));
+ css = to_css(chp->dev.parent);
+
+ size = sizeof(struct cmg_entry);
+
+ /* Only allow single reads. */
+ if (off || count < size)
+ return 0;
+ chp_measurement_copy_block((struct cmg_entry *)buf, css, chp->chpid);
+ count = size;
+ return count;
+}
+
+static struct bin_attribute chp_measurement_attr = {
+ .attr = {
+ .name = "measurement",
+ .mode = S_IRUSR,
+ .owner = THIS_MODULE,
+ },
+ .size = sizeof(struct cmg_entry),
+ .read = chp_measurement_read,
+};
+
+void chp_remove_cmg_attr(struct channel_path *chp)
+{
+ device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
+ device_remove_bin_file(&chp->dev, &chp_measurement_attr);
+}
+
+int chp_add_cmg_attr(struct channel_path *chp)
+{
+ int ret;
+
+ ret = device_create_bin_file(&chp->dev, &chp_measurement_chars_attr);
+ if (ret)
+ return ret;
+ ret = device_create_bin_file(&chp->dev, &chp_measurement_attr);
+ if (ret)
+ device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
+ return ret;
+}
+
+/*
+ * Files for the channel path entries.
+ */
+static ssize_t chp_status_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct channel_path *chp = container_of(dev, struct channel_path, dev);
+
+ if (!chp)
+ return 0;
+ return (chp_get_status(chp->chpid) ? sprintf(buf, "online\n") :
+ sprintf(buf, "offline\n"));
+}
+
+static ssize_t chp_status_write(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct channel_path *cp = container_of(dev, struct channel_path, dev);
+ char cmd[10];
+ int num_args;
+ int error;
+
+ num_args = sscanf(buf, "%5s", cmd);
+ if (!num_args)
+ return count;
+
+ if (!strnicmp(cmd, "on", 2) || !strcmp(cmd, "1"))
+ error = s390_vary_chpid(cp->chpid, 1);
+ else if (!strnicmp(cmd, "off", 3) || !strcmp(cmd, "0"))
+ error = s390_vary_chpid(cp->chpid, 0);
+ else
+ error = -EINVAL;
+
+ return error < 0 ? error : count;
+
+}
+
+static DEVICE_ATTR(status, 0644, chp_status_show, chp_status_write);
+
+static ssize_t chp_type_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct channel_path *chp = container_of(dev, struct channel_path, dev);
+
+ if (!chp)
+ return 0;
+ return sprintf(buf, "%x\n", chp->desc.desc);
+}
+
+static DEVICE_ATTR(type, 0444, chp_type_show, NULL);
+
+static ssize_t chp_cmg_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct channel_path *chp = to_channelpath(dev);
+
+ if (!chp)
+ return 0;
+ if (chp->cmg == -1) /* channel measurements not available */
+ return sprintf(buf, "unknown\n");
+ return sprintf(buf, "%x\n", chp->cmg);
+}
+
+static DEVICE_ATTR(cmg, 0444, chp_cmg_show, NULL);
+
+static ssize_t chp_shared_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct channel_path *chp = to_channelpath(dev);
+
+ if (!chp)
+ return 0;
+ if (chp->shared == -1) /* channel measurements not available */
+ return sprintf(buf, "unknown\n");
+ return sprintf(buf, "%x\n", chp->shared);
+}
+
+static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL);
+
+static struct attribute * chp_attrs[] = {
+ &dev_attr_status.attr,
+ &dev_attr_type.attr,
+ &dev_attr_cmg.attr,
+ &dev_attr_shared.attr,
+ NULL,
+};
+
+static struct attribute_group chp_attr_group = {
+ .attrs = chp_attrs,
+};
+
+static void chp_release(struct device *dev)
+{
+ struct channel_path *cp;
+
+ cp = container_of(dev, struct channel_path, dev);
+ kfree(cp);
+}
+
+/**
+ * chp_new - register a new channel-path
+ * @chpid - channel-path ID
+ *
+ * Create and register data structure representing new channel-path. Return
+ * zero on success, non-zero otherwise.
+ */
+int chp_new(struct chp_id chpid)
+{
+ struct channel_path *chp;
+ int ret;
+
+ chp = kzalloc(sizeof(struct channel_path), GFP_KERNEL);
+ if (!chp)
+ return -ENOMEM;
+
+ /* fill in status, etc. */
+ chp->chpid = chpid;
+ chp->state = 1;
+ chp->dev.parent = &css[chpid.cssid]->device;
+ chp->dev.release = chp_release;
+ snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid,
+ chpid.id);
+
+ /* Obtain channel path description and fill it in. */
+ ret = chsc_determine_channel_path_description(chpid, &chp->desc);
+ if (ret)
+ goto out_free;
+ /* Get channel-measurement characteristics. */
+ if (css_characteristics_avail && css_chsc_characteristics.scmc
+ && css_chsc_characteristics.secm) {
+ ret = chsc_get_channel_measurement_chars(chp);
+ if (ret)
+ goto out_free;
+ } else {
+ static int msg_done;
+
+ if (!msg_done) {
+ printk(KERN_WARNING "cio: Channel measurements not "
+ "available, continuing.\n");
+ msg_done = 1;
+ }
+ chp->cmg = -1;
+ }
+
+ /* make it known to the system */
+ ret = device_register(&chp->dev);
+ if (ret) {
+ printk(KERN_WARNING "%s: could not register %x.%02x\n",
+ __func__, chpid.cssid, chpid.id);
+ goto out_free;
+ }
+ ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group);
+ if (ret) {
+ device_unregister(&chp->dev);
+ goto out_free;
+ }
+ mutex_lock(&css[chpid.cssid]->mutex);
+ if (css[chpid.cssid]->cm_enabled) {
+ ret = chp_add_cmg_attr(chp);
+ if (ret) {
+ sysfs_remove_group(&chp->dev.kobj, &chp_attr_group);
+ device_unregister(&chp->dev);
+ mutex_unlock(&css[chpid.cssid]->mutex);
+ goto out_free;
+ }
+ }
+ css[chpid.cssid]->chps[chpid.id] = chp;
+ mutex_unlock(&css[chpid.cssid]->mutex);
+ return ret;
+out_free:
+ kfree(chp);
+ return ret;
+}
+
+/**
+ * chp_get_chp_desc - return newly allocated channel-path description
+ * @chpid: channel-path ID
+ *
+ * On success return a newly allocated copy of the channel-path description
+ * data associated with the given channel-path ID. Return %NULL on error.
+ */
+void *chp_get_chp_desc(struct chp_id chpid)
+{
+ struct channel_path *chp;
+ struct channel_path_desc *desc;
+
+ chp = chpid_to_chp(chpid);
+ if (!chp)
+ return NULL;
+ desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL);
+ if (!desc)
+ return NULL;
+ memcpy(desc, &chp->desc, sizeof(struct channel_path_desc));
+ return desc;
+}
+
+/**
+ * chp_process_crw - process channel-path status change
+ * @id: channel-path ID number
+ * @status: non-zero if channel-path has become available, zero otherwise
+ *
+ * Handle channel-report-words indicating that the status of a channel-path
+ * has changed.
+ */
+int chp_process_crw(int id, int status)
+{
+ struct chp_id chpid;
+
+ chp_id_init(&chpid);
+ chpid.id = id;
+ if (status) {
+ if (!chp_is_registered(chpid))
+ chp_new(chpid);
+ return chsc_chp_online(chpid);
+ } else {
+ chsc_chp_offline(chpid);
+ return 0;
+ }
+}
Index: quilt-2.6/drivers/s390/cio/chp.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ quilt-2.6/drivers/s390/cio/chp.h 2007-04-27 16:04:53.000000000 +0200
@@ -0,0 +1,37 @@
+/*
+ * drivers/s390/cio/chp.h
+ *
+ * Copyright IBM Corp. 2007
+ * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#ifndef S390_CHP_H
+#define S390_CHP_H S390_CHP_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+
+#include "chpid.h"
+#include "chsc.h"
+
+struct channel_path {
+ struct chp_id chpid;
+ int state;
+ struct channel_path_desc desc;
+ /* Channel-measurement related stuff: */
+ int cmg;
+ int shared;
+ void *cmg_chars;
+ struct device dev;
+};
+
+int chp_get_status(struct chp_id chpid);
+u8 chp_get_sch_opm(struct subchannel *sch);
+int chp_is_registered(struct chp_id chpid);
+void *chp_get_chp_desc(struct chp_id chpid);
+int chp_process_crw(int id, int available);
+void chp_remove_cmg_attr(struct channel_path *chp);
+int chp_add_cmg_attr(struct channel_path *chp);
+int chp_new(struct chp_id chpid);
+
+#endif /* S390_CHP_H */
Index: quilt-2.6/drivers/s390/cio/chsc.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/chsc.c 2007-04-27 16:04:53.000000000 +0200
+++ quilt-2.6/drivers/s390/cio/chsc.c 2007-04-27 16:04:53.000000000 +0200
@@ -21,54 +21,11 @@
#include "cio_debug.h"
#include "ioasm.h"
#include "chpid.h"
+#include "chp.h"
#include "chsc.h"
static void *sei_page;
-static int new_channel_path(struct chp_id chpid);
-
-static inline struct channel_path *chpid_to_chp(struct chp_id chpid)
-{
- return css[chpid.cssid]->chps[chpid.id];
-}
-
-static void set_chp_logically_online(struct chp_id chpid, int onoff)
-{
- chpid_to_chp(chpid)->state = onoff;
-}
-
-static int get_chp_status(struct chp_id chpid)
-{
- return (chpid_to_chp(chpid) ? chpid_to_chp(chpid)->state : -ENODEV);
-}
-
-void chsc_validate_chpids(struct subchannel *sch)
-{
- int mask, chp;
- struct chp_id chpid;
-
- chp_id_init(&chpid);
- for (chp = 0; chp <= 7; chp++) {
- mask = 0x80 >> chp;
- chpid.id = sch->schib.pmcw.chpid[chp];
- if (!get_chp_status(chpid))
- /* disable using this path */
- sch->opm &= ~mask;
- }
-}
-
-void chpid_is_actually_online(struct chp_id chpid)
-{
- int state;
-
- state = get_chp_status(chpid);
- if (state < 0) {
- need_rescan = 1;
- queue_work(slow_path_wq, &slow_path_work);
- } else
- WARN_ON(!state);
-}
-
/* FIXME: this is _always_ called for every subchannel. shouldn't we
* process more than one at a time? */
static int
@@ -214,8 +171,8 @@
mask = 0x80 >> j;
chpid.id = sch->ssd_info.chpid[j];
if ((sch->schib.pmcw.pim & mask) &&
- (get_chp_status(chpid) < 0))
- new_channel_path(chpid);
+ !chp_is_registered(chpid))
+ chp_new(chpid);
}
}
return ret;
@@ -227,7 +184,7 @@
int j;
int mask;
struct subchannel *sch;
- struct channel_path *chpid;
+ struct chp_id *chpid;
struct schib schib;
sch = to_subchannel(dev);
@@ -235,7 +192,7 @@
for (j = 0; j < 8; j++) {
mask = 0x80 >> j;
if ((sch->schib.pmcw.pim & mask) &&
- (sch->schib.pmcw.chpid[j] == chpid->chpid.id))
+ (sch->schib.pmcw.chpid[j] == chpid->id))
break;
}
if (j >= 8)
@@ -285,51 +242,48 @@
return 0;
}
-static void s390_set_chpid_offline(struct chp_id chpid)
+void chsc_chp_offline(struct chp_id chpid)
{
char dbf_txt[15];
- struct device *dev;
sprintf(dbf_txt, "chpr%x.%02x", chpid.cssid, chpid.id);
CIO_TRACE_EVENT(2, dbf_txt);
- if (get_chp_status(chpid) <= 0)
+ if (chp_get_status(chpid) <= 0)
return;
- dev = get_device(&(chpid_to_chp(chpid)->dev));
- bus_for_each_dev(&css_bus_type, NULL, to_channelpath(dev),
+ bus_for_each_dev(&css_bus_type, NULL, &chpid,
s390_subchannel_remove_chpid);
if (need_rescan || css_slow_subchannels_exist())
queue_work(slow_path_wq, &slow_path_work);
- put_device(dev);
}
struct res_acc_data {
- struct channel_path *chp;
+ struct chp_id chpid;
u32 fla_mask;
u16 fla;
};
-static int
-s390_process_res_acc_sch(struct res_acc_data *res_data, struct subchannel *sch)
+static int s390_process_res_acc_sch(struct res_acc_data *res_data,
+ struct subchannel *sch)
{
int found;
int chp;
int ccode;
-
+
found = 0;
for (chp = 0; chp <= 7; chp++)
/*
* check if chpid is in information updated by ssd
*/
if (sch->ssd_info.valid &&
- sch->ssd_info.chpid[chp] == res_data->chp->chpid.id &&
+ sch->ssd_info.chpid[chp] == res_data->chpid.id &&
(sch->ssd_info.fla[chp] & res_data->fla_mask)
== res_data->fla) {
found = 1;
break;
}
-
+
if (found == 0)
return 0;
@@ -416,8 +370,8 @@
int rc;
char dbf_txt[15];
- sprintf(dbf_txt, "accpr%x.%02x", res_data->chp->chpid.cssid,
- res_data->chp->chpid.id);
+ sprintf(dbf_txt, "accpr%x.%02x", res_data->chpid.cssid,
+ res_data->chpid.id);
CIO_TRACE_EVENT( 2, dbf_txt);
if (res_data->fla != 0) {
sprintf(dbf_txt, "fla%x", res_data->fla);
@@ -503,7 +457,7 @@
else {
chp_id_init(&chpid);
chpid.id = id;
- s390_set_chpid_offline(chpid);
+ chsc_chp_offline(chpid);
}
return 0;
@@ -512,7 +466,6 @@
static int chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
{
struct res_acc_data res_data;
- struct device *dev;
struct chp_id chpid;
int status;
int rc;
@@ -524,14 +477,13 @@
chp_id_init(&chpid);
chpid.id = sei_area->rsid;
/* allocate a new channel path structure, if needed */
- status = get_chp_status(chpid);
+ status = chp_get_status(chpid);
if (status < 0)
- new_channel_path(chpid);
+ chp_new(chpid);
else if (!status)
return 0;
- dev = get_device(&(chpid_to_chp(chpid)->dev));
memset(&res_data, 0, sizeof(struct res_acc_data));
- res_data.chp = to_channelpath(dev);
+ res_data.chpid = chpid;
if ((sei_area->vf & 0xc0) != 0) {
res_data.fla = sei_area->fla;
if ((sei_area->vf & 0xc0) == 0xc0)
@@ -542,7 +494,6 @@
res_data.fla_mask = 0xff00;
}
rc = s390_process_res_acc(&res_data);
- put_device(dev);
return rc;
}
@@ -634,10 +585,10 @@
__chp_add(struct subchannel_id schid, void *data)
{
int i, mask;
- struct channel_path *chp;
+ struct chp_id *chpid;
struct subchannel *sch;
- chp = data;
+ chpid = data;
sch = get_subchannel_by_schid(schid);
if (!sch)
/* Check if the subchannel is now available. */
@@ -646,7 +597,7 @@
for (i=0; i<8; i++) {
mask = 0x80 >> i;
if ((sch->schib.pmcw.pim & mask) &&
- (sch->schib.pmcw.chpid[i] == chp->chpid.id)) {
+ (sch->schib.pmcw.chpid[i] == chpid->id)) {
if (stsch(sch->schid, &sch->schib) != 0) {
/* Endgame. */
spin_unlock_irq(sch->lock);
@@ -672,52 +623,24 @@
return 0;
}
-static int chp_add(struct chp_id chpid)
+int chsc_chp_online(struct chp_id chpid)
{
int rc;
char dbf_txt[15];
- struct device *dev;
- if (!get_chp_status(chpid))
- return 0; /* no need to do the rest */
-
sprintf(dbf_txt, "cadd%x.%02x", chpid.cssid, chpid.id);
CIO_TRACE_EVENT(2, dbf_txt);
- dev = get_device(&(chpid_to_chp(chpid)->dev));
- rc = for_each_subchannel(__chp_add, to_channelpath(dev));
+ if (chp_get_status(chpid) == 0)
+ return 0;
+ rc = for_each_subchannel(__chp_add, &chpid);
if (css_slow_subchannels_exist())
rc = -EAGAIN;
if (rc != -EAGAIN)
rc = 0;
- put_device(dev);
return rc;
}
-/*
- * Handling of crw machine checks with channel path source.
- */
-int chp_process_crw(int id, int on)
-{
- struct chp_id chpid;
-
- chp_id_init(&chpid);
- chpid.id = id;
- if (on == 0) {
- /* Path has gone. We use the link incident routine.*/
- s390_set_chpid_offline(chpid);
- return 0; /* De-register is async anyway. */
- }
- /*
- * Path has come. Allocate a new channel path structure,
- * if needed.
- */
- if (get_chp_status(chpid) < 0)
- new_channel_path(chpid);
- /* Avoid the extra overhead in process_rec_acc. */
- return chp_add(chpid);
-}
-
static int check_for_io_on_path(struct subchannel *sch, int index)
{
int cc;
@@ -844,34 +767,13 @@
return 0;
}
-/*
- * Function: s390_vary_chpid
- * Varies the specified chpid online or offline
+/**
+ * chsc_chp_vary - propagate channel-path vary operation to subchannels
+ * @chpid: channl-path ID
+ * @on: non-zero for vary online, zero for vary offline
*/
-static int s390_vary_chpid(struct chp_id chpid, int on)
+int chsc_chp_vary(struct chp_id chpid, int on)
{
- char dbf_text[15];
- int status;
-
- sprintf(dbf_text, on?"varyon%x.%02x":"varyoff%x.%02x", chpid.cssid,
- chpid.id);
- CIO_TRACE_EVENT( 2, dbf_text);
-
- status = get_chp_status(chpid);
- if (status < 0) {
- printk(KERN_ERR "Can't vary unknown chpid %x.%02x\n",
- chpid.cssid, chpid.id);
- return -EINVAL;
- }
-
- if (!on && !status) {
- printk(KERN_ERR "chpid %x.%02x is already offline\n",
- chpid.cssid, chpid.id);
- return -EINVAL;
- }
-
- set_chp_logically_online(chpid, on);
-
/*
* Redo PathVerification on the devices the chpid connects to
*/
@@ -887,112 +789,6 @@
return 0;
}
-/*
- * Channel measurement related functions
- */
-static ssize_t
-chp_measurement_chars_read(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
-{
- struct channel_path *chp;
- unsigned int size;
-
- chp = to_channelpath(container_of(kobj, struct device, kobj));
- if (!chp->cmg_chars)
- return 0;
-
- size = sizeof(struct cmg_chars);
-
- if (off > size)
- return 0;
- if (off + count > size)
- count = size - off;
- memcpy(buf, chp->cmg_chars + off, count);
- return count;
-}
-
-static struct bin_attribute chp_measurement_chars_attr = {
- .attr = {
- .name = "measurement_chars",
- .mode = S_IRUSR,
- .owner = THIS_MODULE,
- },
- .size = sizeof(struct cmg_chars),
- .read = chp_measurement_chars_read,
-};
-
-static void chp_measurement_copy_block(struct cmg_entry *buf,
- struct channel_subsystem *css, struct chp_id chpid)
-{
- void *area;
- struct cmg_entry *entry, reference_buf;
- int idx;
-
- if (chpid.id < 128) {
- area = css->cub_addr1;
- idx = chpid.id;
- } else {
- area = css->cub_addr2;
- idx = chpid.id - 128;
- }
- entry = area + (idx * sizeof(struct cmg_entry));
- do {
- memcpy(buf, entry, sizeof(*entry));
- memcpy(&reference_buf, entry, sizeof(*entry));
- } while (reference_buf.values[0] != buf->values[0]);
-}
-
-static ssize_t
-chp_measurement_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
-{
- struct channel_path *chp;
- struct channel_subsystem *css;
- unsigned int size;
-
- chp = to_channelpath(container_of(kobj, struct device, kobj));
- css = to_css(chp->dev.parent);
-
- size = sizeof(struct cmg_entry);
-
- /* Only allow single reads. */
- if (off || count < size)
- return 0;
- chp_measurement_copy_block((struct cmg_entry *)buf, css, chp->chpid);
- count = size;
- return count;
-}
-
-static struct bin_attribute chp_measurement_attr = {
- .attr = {
- .name = "measurement",
- .mode = S_IRUSR,
- .owner = THIS_MODULE,
- },
- .size = sizeof(struct cmg_entry),
- .read = chp_measurement_read,
-};
-
-static void
-chsc_remove_chp_cmg_attr(struct channel_path *chp)
-{
- device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
- device_remove_bin_file(&chp->dev, &chp_measurement_attr);
-}
-
-static int
-chsc_add_chp_cmg_attr(struct channel_path *chp)
-{
- int ret;
-
- ret = device_create_bin_file(&chp->dev, &chp_measurement_chars_attr);
- if (ret)
- return ret;
- ret = device_create_bin_file(&chp->dev, &chp_measurement_attr);
- if (ret)
- device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
- return ret;
-}
-
static void
chsc_remove_cmg_attr(struct channel_subsystem *css)
{
@@ -1001,7 +797,7 @@
for (i = 0; i <= __MAX_CHPID; i++) {
if (!css->chps[i])
continue;
- chsc_remove_chp_cmg_attr(css->chps[i]);
+ chp_remove_cmg_attr(css->chps[i]);
}
}
@@ -1014,7 +810,7 @@
for (i = 0; i <= __MAX_CHPID; i++) {
if (!css->chps[i])
continue;
- ret = chsc_add_chp_cmg_attr(css->chps[i]);
+ ret = chp_add_cmg_attr(css->chps[i]);
if (ret)
goto cleanup;
}
@@ -1023,12 +819,11 @@
for (--i; i >= 0; i--) {
if (!css->chps[i])
continue;
- chsc_remove_chp_cmg_attr(css->chps[i]);
+ chp_remove_cmg_attr(css->chps[i]);
}
return ret;
}
-
static int
__chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
{
@@ -1143,108 +938,8 @@
return ret;
}
-/*
- * Files for the channel path entries.
- */
-static ssize_t
-chp_status_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct channel_path *chp = container_of(dev, struct channel_path, dev);
-
- if (!chp)
- return 0;
- return (get_chp_status(chp->chpid) ? sprintf(buf, "online\n") :
- sprintf(buf, "offline\n"));
-}
-
-static ssize_t
-chp_status_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
- struct channel_path *cp = container_of(dev, struct channel_path, dev);
- char cmd[10];
- int num_args;
- int error;
-
- num_args = sscanf(buf, "%5s", cmd);
- if (!num_args)
- return count;
-
- if (!strnicmp(cmd, "on", 2) || !strcmp(cmd, "1"))
- error = s390_vary_chpid(cp->chpid, 1);
- else if (!strnicmp(cmd, "off", 3) || !strcmp(cmd, "0"))
- error = s390_vary_chpid(cp->chpid, 0);
- else
- error = -EINVAL;
-
- return error < 0 ? error : count;
-
-}
-
-static DEVICE_ATTR(status, 0644, chp_status_show, chp_status_write);
-
-static ssize_t
-chp_type_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct channel_path *chp = container_of(dev, struct channel_path, dev);
-
- if (!chp)
- return 0;
- return sprintf(buf, "%x\n", chp->desc.desc);
-}
-
-static DEVICE_ATTR(type, 0444, chp_type_show, NULL);
-
-static ssize_t
-chp_cmg_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct channel_path *chp = to_channelpath(dev);
-
- if (!chp)
- return 0;
- if (chp->cmg == -1) /* channel measurements not available */
- return sprintf(buf, "unknown\n");
- return sprintf(buf, "%x\n", chp->cmg);
-}
-
-static DEVICE_ATTR(cmg, 0444, chp_cmg_show, NULL);
-
-static ssize_t
-chp_shared_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct channel_path *chp = to_channelpath(dev);
-
- if (!chp)
- return 0;
- if (chp->shared == -1) /* channel measurements not available */
- return sprintf(buf, "unknown\n");
- return sprintf(buf, "%x\n", chp->shared);
-}
-
-static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL);
-
-static struct attribute * chp_attrs[] = {
- &dev_attr_status.attr,
- &dev_attr_type.attr,
- &dev_attr_cmg.attr,
- &dev_attr_shared.attr,
- NULL,
-};
-
-static struct attribute_group chp_attr_group = {
- .attrs = chp_attrs,
-};
-
-static void
-chp_release(struct device *dev)
-{
- struct channel_path *cp;
-
- cp = container_of(dev, struct channel_path, dev);
- kfree(cp);
-}
-
-static int chsc_determine_channel_path_description(struct chp_id chpid,
- struct channel_path_desc *desc)
+int chsc_determine_channel_path_description(struct chp_id chpid,
+ struct channel_path_desc *desc)
{
int ccode, ret;
@@ -1331,8 +1026,7 @@
}
}
-static int
-chsc_get_channel_measurement_chars(struct channel_path *chp)
+int chsc_get_channel_measurement_chars(struct channel_path *chp)
{
int ccode, ret;
@@ -1407,97 +1101,6 @@
return ret;
}
-/*
- * Entries for chpids on the system bus.
- * This replaces /proc/chpids.
- */
-static int new_channel_path(struct chp_id chpid)
-{
- struct channel_path *chp;
- int ret;
-
- chp = kzalloc(sizeof(struct channel_path), GFP_KERNEL);
- if (!chp)
- return -ENOMEM;
-
- /* fill in status, etc. */
- chp->chpid = chpid;
- chp->state = 1;
- chp->dev.parent = &css[chpid.cssid]->device;
- chp->dev.release = chp_release;
- snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid,
- chpid.id);
-
- /* Obtain channel path description and fill it in. */
- ret = chsc_determine_channel_path_description(chpid, &chp->desc);
- if (ret)
- goto out_free;
- /* Get channel-measurement characteristics. */
- if (css_characteristics_avail && css_chsc_characteristics.scmc
- && css_chsc_characteristics.secm) {
- ret = chsc_get_channel_measurement_chars(chp);
- if (ret)
- goto out_free;
- } else {
- static int msg_done;
-
- if (!msg_done) {
- printk(KERN_WARNING "cio: Channel measurements not "
- "available, continuing.\n");
- msg_done = 1;
- }
- chp->cmg = -1;
- }
-
- /* make it known to the system */
- ret = device_register(&chp->dev);
- if (ret) {
- printk(KERN_WARNING "%s: could not register %x.%02x\n",
- __func__, chpid.cssid, chpid.id);
- goto out_free;
- }
- ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group);
- if (ret) {
- device_unregister(&chp->dev);
- goto out_free;
- }
- mutex_lock(&css[chpid.cssid]->mutex);
- if (css[chpid.cssid]->cm_enabled) {
- ret = chsc_add_chp_cmg_attr(chp);
- if (ret) {
- sysfs_remove_group(&chp->dev.kobj, &chp_attr_group);
- device_unregister(&chp->dev);
- mutex_unlock(&css[chpid.cssid]->mutex);
- goto out_free;
- }
- }
- css[chpid.cssid]->chps[chpid.id] = chp;
- mutex_unlock(&css[chpid.cssid]->mutex);
- return ret;
-out_free:
- kfree(chp);
- return ret;
-}
-
-void *
-chsc_get_chp_desc(struct subchannel *sch, int chp_no)
-{
- struct channel_path *chp;
- struct channel_path_desc *desc;
- struct chp_id chpid;
-
- chp_id_init(&chpid);
- chpid.id = sch->schib.pmcw.chpid[chp_no];
- chp = chpid_to_chp(chpid);
- if (!chp)
- return NULL;
- desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL);
- if (!desc)
- return NULL;
- memcpy(desc, &chp->desc, sizeof(struct channel_path_desc));
- return desc;
-}
-
static int __init
chsc_alloc_sei_area(void)
{
Index: quilt-2.6/drivers/s390/cio/chsc.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/chsc.h 2007-04-27 16:04:52.000000000 +0200
+++ quilt-2.6/drivers/s390/cio/chsc.h 2007-04-27 16:04:53.000000000 +0200
@@ -5,10 +5,6 @@
#include <linux/device.h>
#include "chpid.h"
-#define CHSC_SEI_ACC_CHPID 1
-#define CHSC_SEI_ACC_LINKADDR 2
-#define CHSC_SEI_ACC_FULLLINKADDR 3
-
#define CHSC_SDA_OC_MSS 0x2
struct chsc_header {
@@ -37,23 +33,10 @@
u8 chpp;
} __attribute__ ((packed));
-struct channel_path {
- struct chp_id chpid;
- int state;
- struct channel_path_desc desc;
- /* Channel-measurement related stuff: */
- int cmg;
- int shared;
- void *cmg_chars;
- struct device dev;
-};
-
-extern void s390_process_css( void );
-extern void chsc_validate_chpids(struct subchannel *);
-extern void chpid_is_actually_online(struct chp_id);
+struct channel_path;
+
extern int css_get_ssd_info(struct subchannel *);
extern int chsc_process_crw(void);
-extern int chp_process_crw(int, int);
struct css_general_char {
u64 : 41;
@@ -89,12 +72,15 @@
extern int chsc_determine_css_characteristics(void);
extern int css_characteristics_avail;
-extern void *chsc_get_chp_desc(struct subchannel*, int);
-
extern int chsc_enable_facility(int);
struct channel_subsystem;
extern int chsc_secm(struct channel_subsystem *, int);
-#define to_channelpath(device) container_of(device, struct channel_path, dev)
+int chsc_chp_vary(struct chp_id chpid, int on);
+int chsc_determine_channel_path_description(struct chp_id chpid,
+ struct channel_path_desc *desc);
+int chsc_chp_online(struct chp_id chpid);
+void chsc_chp_offline(struct chp_id chpid);
+int chsc_get_channel_measurement_chars(struct channel_path *chp);
#endif
Index: quilt-2.6/drivers/s390/cio/cio.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/cio.c 2007-04-27 16:04:52.000000000 +0200
+++ quilt-2.6/drivers/s390/cio/cio.c 2007-04-27 16:04:53.000000000 +0200
@@ -29,6 +29,7 @@
#include "ioasm.h"
#include "blacklist.h"
#include "cio_debug.h"
+#include "chp.h"
#include "../s390mach.h"
debug_info_t *cio_debug_msg_id;
@@ -592,9 +593,10 @@
err = -ENODEV;
goto out;
}
- sch->opm = 0xff;
- if (!cio_is_console(sch->schid))
- chsc_validate_chpids(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;
CIO_DEBUG(KERN_INFO, 0,
Index: quilt-2.6/drivers/s390/cio/css.h
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/css.h 2007-04-27 16:01:49.000000000 +0200
+++ quilt-2.6/drivers/s390/cio/css.h 2007-04-27 16:04:53.000000000 +0200
@@ -4,6 +4,7 @@
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
+#include <linux/device.h>
#include <asm/cio.h>
Index: quilt-2.6/drivers/s390/cio/device_fsm.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_fsm.c 2007-04-27 16:04:52.000000000 +0200
+++ quilt-2.6/drivers/s390/cio/device_fsm.c 2007-04-27 16:04:53.000000000 +0200
@@ -23,6 +23,7 @@
#include "chsc.h"
#include "ioasm.h"
#include "chpid.h"
+#include "chp.h"
int
device_is_online(struct subchannel *sch)
@@ -221,7 +222,10 @@
if (old_lpm & mask)
continue;
chpid.id = sch->schib.pmcw.chpid[i];
- chpid_is_actually_online(chpid);
+ if (!chp_is_registered(chpid)) {
+ need_rescan = 1;
+ queue_work(slow_path_wq, &slow_path_work);
+ }
}
}
Index: quilt-2.6/drivers/s390/cio/device_ops.c
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/device_ops.c 2007-04-27 16:01:49.000000000 +0200
+++ quilt-2.6/drivers/s390/cio/device_ops.c 2007-04-27 16:04:53.000000000 +0200
@@ -22,6 +22,8 @@
#include "css.h"
#include "chsc.h"
#include "device.h"
+#include "chpid.h"
+#include "chp.h"
int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags)
{
@@ -606,9 +608,12 @@
ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
{
struct subchannel *sch;
+ struct chp_id chpid;
sch = to_subchannel(cdev->dev.parent);
- return chsc_get_chp_desc(sch, chp_no);
+ chp_id_init(&chpid);
+ chpid.id = sch->schib.pmcw.chpid[chp_no];
+ return chp_get_chp_desc(chpid);
}
// FIXME: these have to go:
Index: quilt-2.6/drivers/s390/cio/Makefile
===================================================================
--- quilt-2.6.orig/drivers/s390/cio/Makefile 2007-04-27 16:01:49.000000000 +0200
+++ quilt-2.6/drivers/s390/cio/Makefile 2007-04-27 16:04:53.000000000 +0200
@@ -2,7 +2,7 @@
# Makefile for the S/390 common i/o drivers
#
-obj-y += airq.o blacklist.o chsc.o cio.o css.o
+obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o
ccw_device-objs += device.o device_fsm.o device_ops.o
ccw_device-objs += device_id.o device_pgid.o device_status.o
obj-y += ccw_device.o cmf.o
Index: quilt-2.6/drivers/s390/s390mach.c
===================================================================
--- quilt-2.6.orig/drivers/s390/s390mach.c 2007-04-27 16:01:49.000000000 +0200
+++ quilt-2.6/drivers/s390/s390mach.c 2007-04-27 16:04:53.000000000 +0200
@@ -21,6 +21,7 @@
#include "cio/cio.h"
#include "cio/chsc.h"
#include "cio/css.h"
+#include "cio/chp.h"
#include "s390mach.h"
static struct semaphore m_sem;
--
blue skies,
Martin.
"Reality continues to ruin my life." - Calvin.
next prev parent reply other threads:[~2007-04-27 14:05 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-04-27 14:05 [patch 00/38] s390 patches for 2.6.22 Martin Schwidefsky
2007-04-27 14:05 ` [patch 01/38] memory detection: stop at first memory hole Martin Schwidefsky
2007-04-27 14:05 ` [patch 02/38] cio/ipl: Clean interface between cio and ipl code Martin Schwidefsky
2007-04-27 14:05 ` [patch 03/38] cio: Introduce struct chp_id Martin Schwidefsky
2007-04-27 14:05 ` [patch 04/38] cio: Allow 0 and 1 as input for channel path status attribute Martin Schwidefsky
2007-04-27 14:05 ` Martin Schwidefsky [this message]
2007-04-27 14:05 ` [patch 06/38] cio: observe chpid valid flag Martin Schwidefsky
2007-04-27 14:05 ` [patch 07/38] cio: Clean up online_store Martin Schwidefsky
2007-04-27 14:05 ` [patch 08/38] cio: Channel-path configure function Martin Schwidefsky
2007-04-27 14:05 ` [patch 09/38] cio: Use add_uevent_var Martin Schwidefsky
2007-04-27 14:05 ` [patch 10/38] cio: Re-start path verification after aborting internal I/O Martin Schwidefsky
2007-04-27 14:05 ` [patch 11/38] cio: replace subchannel evaluation queue with bitmap Martin Schwidefsky
2007-04-27 14:05 ` [patch 12/38] cio: fix subchannel channel-path data usage Martin Schwidefsky
2007-04-27 14:05 ` [patch 13/38] cio: Dont call css_update_ssd_info from interrupt context Martin Schwidefsky
2007-04-27 14:05 ` [patch 14/38] cio: ccwgroup register vs. unregister Martin Schwidefsky
2007-04-27 14:05 ` [patch 15/38] cio: cm_enable memory leak Martin Schwidefsky
2007-04-27 14:05 ` [patch 16/38] cio: Unregister ccw devices directly Martin Schwidefsky
2007-04-27 14:05 ` [patch 17/38] System call cleanup Martin Schwidefsky
2007-04-27 14:05 ` [patch 18/38] Improved oops output Martin Schwidefsky
2007-04-27 14:25 ` Christoph Hellwig
2007-04-27 15:24 ` Martin Schwidefsky
2007-04-27 16:01 ` Chuck Ebbert
2007-04-27 16:15 ` Martin Schwidefsky
2007-04-27 16:21 ` Chuck Ebbert
2007-04-27 18:14 ` Andi Kleen
2007-04-27 20:56 ` Martin Schwidefsky
2007-04-27 21:10 ` Chuck Ebbert
2007-04-27 14:05 ` [patch 19/38] Use generic bug Martin Schwidefsky
2007-04-27 14:05 ` [patch 20/38] Minor fault path optimization Martin Schwidefsky
2007-04-28 4:49 ` Paul Mackerras
2007-04-28 8:34 ` Christoph Hellwig
2007-04-30 0:57 ` Paul Mackerras
2007-04-30 10:56 ` [PATCH] powerpc: minor " Christoph Hellwig
2007-05-02 10:45 ` [patch 20/38] Minor " Martin Schwidefsky
2007-05-02 10:49 ` Christoph Hellwig
2007-04-27 14:05 ` [patch 21/38] No execute support cleanup Martin Schwidefsky
2007-04-27 14:05 ` [patch 22/38] Get rid of console setup functions Martin Schwidefsky
2007-04-27 14:05 ` [patch 23/38] Improved kernel stack overflow checking Martin Schwidefsky
2007-04-27 14:05 ` [patch 24/38] dasd: Add sysfs attribute status and generate uevents Martin Schwidefsky
2007-04-27 14:05 ` [patch 25/38] dasd: Add ipldev parameter Martin Schwidefsky
2007-04-27 14:05 ` [patch 26/38] zfcpdump support Martin Schwidefsky
2007-04-27 14:05 ` [patch 27/38] ctc: kmalloc->kzalloc/casting cleanups Martin Schwidefsky
2007-04-27 14:05 ` [patch 28/38] sclp: initialize early Martin Schwidefsky
2007-04-27 14:05 ` [patch 29/38] vmlogrdr: stop IUCV connection in vmlogrdr_release Martin Schwidefsky
2007-04-27 14:05 ` [patch 30/38] sclp: fix coding style Martin Schwidefsky
2007-04-27 14:05 ` [patch 31/38] crypto: cleanup Martin Schwidefsky
2007-04-27 14:05 ` [patch 32/38] vtime: cleanup per_cpu usage Martin Schwidefsky
2007-04-27 14:05 ` [patch 33/38] Processor degradation notification Martin Schwidefsky
2007-04-27 14:05 ` [patch 34/38] split page_test_and_clear_dirty Martin Schwidefsky
2007-04-27 14:05 ` [patch 35/38] Switch etr from tasklet to workqueue Martin Schwidefsky
2007-04-27 14:05 ` [patch 36/38] Remove debugging junk Martin Schwidefsky
2007-04-27 14:05 ` [patch 37/38] Clean up smp code in preparation for some larger changes Martin Schwidefsky
2007-04-27 14:05 ` [patch 38/38] SPIN_LOCK_UNLOCKED cleanup in drivers/s390 Martin Schwidefsky
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070427140512.863578656@de.ibm.com \
--to=schwidefsky@de.ibm.com \
--cc=heiko.carstens@de.ibm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-s390@vger.kernel.org \
--cc=peter.oberparleiter@de.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.