[S390] cio: obtain mdc value per channel path
authorSebastian Ott <sebott@linux.vnet.ibm.com>
Wed, 5 Jan 2011 11:47:56 +0000 (12:47 +0100)
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>
Wed, 5 Jan 2011 11:47:28 +0000 (12:47 +0100)
Add support to accumulate the number of 64K-bytes blocks all paths
to a device at least support for a transport command.

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/ccwdev.h
drivers/s390/cio/chsc.c
drivers/s390/cio/chsc.h
drivers/s390/cio/device_ops.c

index e850111..ff6f62e 100644 (file)
@@ -204,6 +204,8 @@ int ccw_device_tm_start_timeout(struct ccw_device *, struct tcw *,
                            unsigned long, u8, int);
 int ccw_device_tm_intrg(struct ccw_device *cdev);
 
+int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask);
+
 extern int ccw_device_set_online(struct ccw_device *cdev);
 extern int ccw_device_set_offline(struct ccw_device *cdev);
 
index 1aaddea..0689fcf 100644 (file)
@@ -695,6 +695,25 @@ out:
        return ret;
 }
 
+int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid,
+                                         struct channel_path_desc_fmt1 *desc)
+{
+       struct chsc_response_struct *chsc_resp;
+       struct chsc_scpd *scpd_area;
+       int ret;
+
+       spin_lock_irq(&chsc_page_lock);
+       scpd_area = chsc_page;
+       ret = chsc_determine_channel_path_desc(chpid, 0, 0, 1, 0, scpd_area);
+       if (ret)
+               goto out;
+       chsc_resp = (void *)&scpd_area->response;
+       memcpy(desc, &chsc_resp->data, sizeof(*desc));
+out:
+       spin_unlock_irq(&chsc_page_lock);
+       return ret;
+}
+
 static void
 chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,
                          struct cmg_chars *chars)
index 6693f5e..3f15b2a 100644 (file)
@@ -35,6 +35,22 @@ struct channel_path_desc {
        u8 chpp;
 } __attribute__ ((packed));
 
+struct channel_path_desc_fmt1 {
+       u8 flags;
+       u8 lsn;
+       u8 desc;
+       u8 chpid;
+       u32:24;
+       u8 chpp;
+       u32 unused[3];
+       u16 mdc;
+       u16:13;
+       u8 r:1;
+       u8 s:1;
+       u8 f:1;
+       u32 zeros[2];
+} __attribute__ ((packed));
+
 struct channel_path;
 
 struct css_chsc_char {
@@ -92,6 +108,8 @@ int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt,
                                     int c, int m, void *page);
 int chsc_determine_base_channel_path_desc(struct chp_id chpid,
                                          struct channel_path_desc *desc);
+int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid,
+                                         struct channel_path_desc_fmt1 *desc);
 void 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);
index 6da8454..651976b 100644 (file)
@@ -686,6 +686,46 @@ int ccw_device_tm_start_timeout(struct ccw_device *cdev, struct tcw *tcw,
 }
 EXPORT_SYMBOL(ccw_device_tm_start_timeout);
 
+/**
+ * ccw_device_get_mdc - accumulate max data count
+ * @cdev: ccw device for which the max data count is accumulated
+ * @mask: mask of paths to use
+ *
+ * Return the number of 64K-bytes blocks all paths at least support
+ * for a transport command. Return values <= 0 indicate failures.
+ */
+int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask)
+{
+       struct subchannel *sch = to_subchannel(cdev->dev.parent);
+       struct channel_path_desc_fmt1 desc;
+       struct chp_id chpid;
+       int mdc = 0, ret, i;
+
+       /* Adjust requested path mask to excluded varied off paths. */
+       if (mask)
+               mask &= sch->lpm;
+       else
+               mask = sch->lpm;
+
+       chp_id_init(&chpid);
+       for (i = 0; i < 8; i++) {
+               if (!(mask & (0x80 >> i)))
+                       continue;
+               chpid.id = sch->schib.pmcw.chpid[i];
+               ret = chsc_determine_fmt1_channel_path_desc(chpid, &desc);
+               if (ret)
+                       return ret;
+               if (!desc.f)
+                       return 0;
+               if (!desc.r)
+                       mdc = 1;
+               mdc = mdc ? min(mdc, (int)desc.mdc) : desc.mdc;
+       }
+
+       return mdc;
+}
+EXPORT_SYMBOL(ccw_device_get_mdc);
+
 /**
  * ccw_device_tm_intrg - perform interrogate function
  * @cdev: ccw device on which to perform the interrogate function