Upgrade to 4.4.50-rt62
[kvmfornfv.git] / kernel / drivers / s390 / cio / chsc.c
index a831d18..1e16331 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/mutex.h>
 #include <linux/pci.h>
 
 #include <asm/cio.h>
@@ -94,12 +95,13 @@ struct chsc_ssd_area {
 int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
 {
        struct chsc_ssd_area *ssd_area;
+       unsigned long flags;
        int ccode;
        int ret;
        int i;
        int mask;
 
-       spin_lock_irq(&chsc_page_lock);
+       spin_lock_irqsave(&chsc_page_lock, flags);
        memset(chsc_page, 0, PAGE_SIZE);
        ssd_area = chsc_page;
        ssd_area->request.length = 0x0010;
@@ -143,7 +145,7 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
                        ssd->fla[i] = ssd_area->fla[i];
        }
 out:
-       spin_unlock_irq(&chsc_page_lock);
+       spin_unlock_irqrestore(&chsc_page_lock, flags);
        return ret;
 }
 
@@ -224,8 +226,9 @@ out_unreg:
 
 void chsc_chp_offline(struct chp_id chpid)
 {
-       char dbf_txt[15];
+       struct channel_path *chp = chpid_to_chp(chpid);
        struct chp_link link;
+       char dbf_txt[15];
 
        sprintf(dbf_txt, "chpr%x.%02x", chpid.cssid, chpid.id);
        CIO_TRACE_EVENT(2, dbf_txt);
@@ -236,6 +239,11 @@ void chsc_chp_offline(struct chp_id chpid)
        link.chpid = chpid;
        /* Wait until previous actions have settled. */
        css_wait_for_slow_path();
+
+       mutex_lock(&chp->lock);
+       chp_update_desc(chp);
+       mutex_unlock(&chp->lock);
+
        for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &link);
 }
 
@@ -690,8 +698,9 @@ static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
 
 void chsc_chp_online(struct chp_id chpid)
 {
-       char dbf_txt[15];
+       struct channel_path *chp = chpid_to_chp(chpid);
        struct chp_link link;
+       char dbf_txt[15];
 
        sprintf(dbf_txt, "cadd%x.%02x", chpid.cssid, chpid.id);
        CIO_TRACE_EVENT(2, dbf_txt);
@@ -701,6 +710,11 @@ void chsc_chp_online(struct chp_id chpid)
                link.chpid = chpid;
                /* Wait until previous actions have settled. */
                css_wait_for_slow_path();
+
+               mutex_lock(&chp->lock);
+               chp_update_desc(chp);
+               mutex_unlock(&chp->lock);
+
                for_each_subchannel_staged(__s390_process_res_acc, NULL,
                                           &link);
                css_schedule_reprobe();
@@ -819,9 +833,10 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable)
                u32 fmt : 4;
                u32 : 16;
        } __attribute__ ((packed)) *secm_area;
+       unsigned long flags;
        int ret, ccode;
 
-       spin_lock_irq(&chsc_page_lock);
+       spin_lock_irqsave(&chsc_page_lock, flags);
        memset(chsc_page, 0, PAGE_SIZE);
        secm_area = chsc_page;
        secm_area->request.length = 0x0050;
@@ -851,7 +866,7 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable)
                CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n",
                              secm_area->response.code);
 out:
-       spin_unlock_irq(&chsc_page_lock);
+       spin_unlock_irqrestore(&chsc_page_lock, flags);
        return ret;
 }
 
@@ -967,22 +982,20 @@ static void
 chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,
                          struct cmg_chars *chars)
 {
-       struct cmg_chars *cmg_chars;
        int i, mask;
 
-       cmg_chars = chp->cmg_chars;
        for (i = 0; i < NR_MEASUREMENT_CHARS; i++) {
                mask = 0x80 >> (i + 3);
                if (cmcv & mask)
-                       cmg_chars->values[i] = chars->values[i];
+                       chp->cmg_chars.values[i] = chars->values[i];
                else
-                       cmg_chars->values[i] = 0;
+                       chp->cmg_chars.values[i] = 0;
        }
 }
 
 int chsc_get_channel_measurement_chars(struct channel_path *chp)
 {
-       struct cmg_chars *cmg_chars;
+       unsigned long flags;
        int ccode, ret;
 
        struct {
@@ -1006,12 +1019,13 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
                u32 data[NR_MEASUREMENT_CHARS];
        } __attribute__ ((packed)) *scmc_area;
 
-       chp->cmg_chars = NULL;
-       cmg_chars = kmalloc(sizeof(*cmg_chars), GFP_KERNEL);
-       if (!cmg_chars)
-               return -ENOMEM;
+       chp->shared = -1;
+       chp->cmg = -1;
+
+       if (!css_chsc_characteristics.scmc || !css_chsc_characteristics.secm)
+               return 0;
 
-       spin_lock_irq(&chsc_page_lock);
+       spin_lock_irqsave(&chsc_page_lock, flags);
        memset(chsc_page, 0, PAGE_SIZE);
        scmc_area = chsc_page;
        scmc_area->request.length = 0x0010;
@@ -1031,25 +1045,19 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
                              scmc_area->response.code);
                goto out;
        }
-       if (scmc_area->not_valid) {
-               chp->cmg = -1;
-               chp->shared = -1;
+       if (scmc_area->not_valid)
                goto out;
-       }
+
        chp->cmg = scmc_area->cmg;
        chp->shared = scmc_area->shared;
        if (chp->cmg != 2 && chp->cmg != 3) {
                /* No cmg-dependent data. */
                goto out;
        }
-       chp->cmg_chars = cmg_chars;
        chsc_initialize_cmg_chars(chp, scmc_area->cmcv,
                                  (struct cmg_chars *) &scmc_area->data);
 out:
-       spin_unlock_irq(&chsc_page_lock);
-       if (!chp->cmg_chars)
-               kfree(cmg_chars);
-
+       spin_unlock_irqrestore(&chsc_page_lock, flags);
        return ret;
 }
 
@@ -1130,6 +1138,7 @@ struct css_chsc_char css_chsc_characteristics;
 int __init
 chsc_determine_css_characteristics(void)
 {
+       unsigned long flags;
        int result;
        struct {
                struct chsc_header request;
@@ -1142,7 +1151,7 @@ chsc_determine_css_characteristics(void)
                u32 chsc_char[508];
        } __attribute__ ((packed)) *scsc_area;
 
-       spin_lock_irq(&chsc_page_lock);
+       spin_lock_irqsave(&chsc_page_lock, flags);
        memset(chsc_page, 0, PAGE_SIZE);
        scsc_area = chsc_page;
        scsc_area->request.length = 0x0010;
@@ -1164,7 +1173,7 @@ chsc_determine_css_characteristics(void)
                CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n",
                              scsc_area->response.code);
 exit:
-       spin_unlock_irq(&chsc_page_lock);
+       spin_unlock_irqrestore(&chsc_page_lock, flags);
        return result;
 }