s390/cio: Helper functions to read CSSID, IID, and CHID
authorAlexandra Winter <wintera@linux.ibm.com>
Thu, 10 Sep 2020 17:23:45 +0000 (19:23 +0200)
committerDavid S. Miller <davem@davemloft.net>
Tue, 15 Sep 2020 20:21:46 +0000 (13:21 -0700)
Add helper functions to expose Channel Subsystem ID (CSSID), MIF Image Id
(IID), Channel ID (CHID) and Channel Path ID (CHPID).
These values are required by the qeth driver's exploitation of network-
address-change-notifications to determine which entries belong to this
interface.

Store the Partition identifier in System log, as this may be used to map
a Linux view to a Hardware view for debugging purpose.

Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Acked-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
arch/s390/include/asm/ccwdev.h
drivers/s390/cio/chsc.c
drivers/s390/cio/chsc.h
drivers/s390/cio/css.c
drivers/s390/cio/css.h
drivers/s390/cio/device_ops.c

index 9739a00e2190001d959df2f2c014e5ddedec576f..c0be5fe1ddbafb2409f87a43101007b55d49a12a 100644 (file)
@@ -240,4 +240,8 @@ u8 *ccw_device_get_util_str(struct ccw_device *cdev, int chp_idx);
 int ccw_device_pnso(struct ccw_device *cdev,
                    struct chsc_pnso_area *pnso_area, u8 oc,
                    struct chsc_pnso_resume_token resume_token, int cnc);
+int ccw_device_get_cssid(struct ccw_device *cdev, u8 *cssid);
+int ccw_device_get_iid(struct ccw_device *cdev, u8 *iid);
+int ccw_device_get_chpid(struct ccw_device *cdev, int chp_idx, u8 *chpid);
+int ccw_device_get_chid(struct ccw_device *cdev, int chp_idx, u16 *chid);
 #endif /* _S390_CCWDEV_H_ */
index 8f764a295a517a243cc449aaf541c1202530f3d3..38017c4a31e99c9cd0b5363c3f9fca1fa4073104 100644 (file)
@@ -1116,7 +1116,7 @@ int chsc_enable_facility(int operation_code)
        return ret;
 }
 
-int __init chsc_get_cssid(int idx)
+int __init chsc_get_cssid_iid(int idx, u8 *cssid, u8 *iid)
 {
        struct {
                struct chsc_header request;
@@ -1127,7 +1127,8 @@ int __init chsc_get_cssid(int idx)
                u32 reserved2[3];
                struct {
                        u8 cssid;
-                       u32 : 24;
+                       u8 iid;
+                       u32 : 16;
                } list[0];
        } *sdcal_area;
        int ret;
@@ -1153,8 +1154,10 @@ int __init chsc_get_cssid(int idx)
        }
 
        if ((addr_t) &sdcal_area->list[idx] <
-           (addr_t) &sdcal_area->response + sdcal_area->response.length)
-               ret = sdcal_area->list[idx].cssid;
+           (addr_t) &sdcal_area->response + sdcal_area->response.length) {
+               *cssid = sdcal_area->list[idx].cssid;
+               *iid = sdcal_area->list[idx].iid;
+       }
        else
                ret = -ENODEV;
 exit:
index 7416957ba9f4f67756511eb0f38739fbd1718a4b..c2b83b68bc579475b0fdab1fbd91a35a81311059 100644 (file)
@@ -208,7 +208,7 @@ int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token);
 int chsc_pnso(struct subchannel_id schid, struct chsc_pnso_area *pnso_area,
              u8 oc, struct chsc_pnso_resume_token resume_token, int cnc);
 
-int __init chsc_get_cssid(int idx);
+int __init chsc_get_cssid_iid(int idx, u8 *cssid, u8 *iid);
 
 #ifdef CONFIG_SCM_BUS
 int scm_update_information(void);
index aca022239b333e6eabe0904ef4e7b6e77c00a84d..1981eb62d329ca6abf259142f45adc5de05f329b 100644 (file)
@@ -854,7 +854,7 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high)
        if (css_general_characteristics.mcss) {
                css->global_pgid.pgid_high.ext_cssid.version = 0x80;
                css->global_pgid.pgid_high.ext_cssid.cssid =
-                       (css->cssid < 0) ? 0 : css->cssid;
+                       css->id_valid ? css->cssid : 0;
        } else {
                css->global_pgid.pgid_high.cpu_addr = stap();
        }
@@ -877,7 +877,7 @@ static ssize_t real_cssid_show(struct device *dev, struct device_attribute *a,
 {
        struct channel_subsystem *css = to_css(dev);
 
-       if (css->cssid < 0)
+       if (!css->id_valid)
                return -EINVAL;
 
        return sprintf(buf, "%x\n", css->cssid);
@@ -975,7 +975,12 @@ static int __init setup_css(int nr)
        css->device.dma_mask = &css->device.coherent_dma_mask;
 
        mutex_init(&css->mutex);
-       css->cssid = chsc_get_cssid(nr);
+       ret = chsc_get_cssid_iid(nr, &css->cssid, &css->iid);
+       if (!ret) {
+               css->id_valid = true;
+               pr_info("Partition identifier %01x.%01x\n", css->cssid,
+                       css->iid);
+       }
        css_generate_pgid(css, (u32) (get_tod_clock() >> 32));
 
        ret = device_register(&css->device);
index 8d832900a63dd44081119f2905fd0d69321f4580..3f322ea0f498235cefb1b6ecd04fd3922e1a9e0a 100644 (file)
@@ -115,7 +115,9 @@ extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
 void css_update_ssd_info(struct subchannel *sch);
 
 struct channel_subsystem {
-       int cssid;
+       u8 cssid;
+       u8 iid;
+       bool id_valid; /* cssid,iid */
        struct channel_path *chps[__MAX_CHPID + 1];
        struct device device;
        struct pgid global_pgid;
index cdf44f398957f288fe41a8573a92a71507a2640c..0fe7b2f2e7f5239ee660c7779fe461ac8598fb6b 100644 (file)
@@ -733,6 +733,91 @@ int ccw_device_pnso(struct ccw_device *cdev,
 }
 EXPORT_SYMBOL_GPL(ccw_device_pnso);
 
+/**
+ * ccw_device_get_cssid() - obtain Channel Subsystem ID
+ * @cdev: device to obtain the CSSID for
+ * @cssid: The resulting Channel Subsystem ID
+ */
+int ccw_device_get_cssid(struct ccw_device *cdev, u8 *cssid)
+{
+       struct device *sch_dev = cdev->dev.parent;
+       struct channel_subsystem *css = to_css(sch_dev->parent);
+
+       if (css->id_valid)
+               *cssid = css->cssid;
+       return css->id_valid ? 0 : -ENODEV;
+}
+EXPORT_SYMBOL_GPL(ccw_device_get_cssid);
+
+/**
+ * ccw_device_get_iid() - obtain MIF-image ID
+ * @cdev: device to obtain the MIF-image ID for
+ * @iid: The resulting MIF-image ID
+ */
+int ccw_device_get_iid(struct ccw_device *cdev, u8 *iid)
+{
+       struct device *sch_dev = cdev->dev.parent;
+       struct channel_subsystem *css = to_css(sch_dev->parent);
+
+       if (css->id_valid)
+               *iid = css->iid;
+       return css->id_valid ? 0 : -ENODEV;
+}
+EXPORT_SYMBOL_GPL(ccw_device_get_iid);
+
+/**
+ * ccw_device_get_chpid() - obtain Channel Path ID
+ * @cdev: device to obtain the Channel Path ID for
+ * @chp_idx: Index of the channel path
+ * @chpid: The resulting Channel Path ID
+ */
+int ccw_device_get_chpid(struct ccw_device *cdev, int chp_idx, u8 *chpid)
+{
+       struct subchannel *sch = to_subchannel(cdev->dev.parent);
+       int mask;
+
+       if ((chp_idx < 0) || (chp_idx > 7))
+               return -EINVAL;
+       mask = 0x80 >> chp_idx;
+       if (!(sch->schib.pmcw.pim & mask))
+               return -ENODEV;
+
+       *chpid = sch->schib.pmcw.chpid[chp_idx];
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ccw_device_get_chpid);
+
+/**
+ * ccw_device_get_chid() - obtain Channel ID associated with specified CHPID
+ * @cdev: device to obtain the Channel ID for
+ * @chp_idx: Index of the channel path
+ * @chid: The resulting Channel ID
+ */
+int ccw_device_get_chid(struct ccw_device *cdev, int chp_idx, u16 *chid)
+{
+       struct chp_id cssid_chpid;
+       struct channel_path *chp;
+       int rc;
+
+       chp_id_init(&cssid_chpid);
+       rc = ccw_device_get_chpid(cdev, chp_idx, &cssid_chpid.id);
+       if (rc)
+               return rc;
+       chp = chpid_to_chp(cssid_chpid);
+       if (!chp)
+               return -ENODEV;
+
+       mutex_lock(&chp->lock);
+       if (chp->desc_fmt1.flags & 0x10)
+               *chid = chp->desc_fmt1.chid;
+       else
+               rc = -ENODEV;
+       mutex_unlock(&chp->lock);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(ccw_device_get_chid);
+
 /*
  * Allocate zeroed dma coherent 31 bit addressable memory using
  * the subchannels dma pool. Maximal size of allocation supported