[S390] qdio (new feature): enhancing info-retrieval from QDIO-adapters
authorUrsula Braun <braunu@de.ibm.com>
Thu, 17 Apr 2008 05:46:22 +0000 (07:46 +0200)
committerHeiko Carstens <heiko.carstens@de.ibm.com>
Thu, 17 Apr 2008 05:47:04 +0000 (07:47 +0200)
Next generation of OSA adapters allows retrieval of further self-describing
infos. This is the preparational infrastructure patch for further exploitation
in the qeth driver.

Signed-off-by: Ursula Braun <braunu@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/qdio.c
drivers/s390/cio/qdio.h

index b1d18aa471c9aee4b4e49fc609118151692bd766..c359386708e96d23ca2e8aa937116818f9a2d30a 100644 (file)
@@ -2217,9 +2217,78 @@ qdio_synchronize(struct ccw_device *cdev, unsigned int flags,
        return cc;
 }
 
+static int
+qdio_get_ssqd_information(struct subchannel_id *schid,
+                         struct qdio_chsc_ssqd **ssqd_area)
+{
+       int result;
+
+       QDIO_DBF_TEXT0(0, setup, "getssqd");
+       *ssqd_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC);
+       if (!ssqd_area) {
+               QDIO_PRINT_WARN("Could not get memory for chsc on sch x%x.\n",
+                               schid->sch_no);
+               return -ENOMEM;
+       }
+
+       (*ssqd_area)->request = (struct chsc_header) {
+               .length = 0x0010,
+               .code   = 0x0024,
+       };
+       (*ssqd_area)->first_sch = schid->sch_no;
+       (*ssqd_area)->last_sch = schid->sch_no;
+       (*ssqd_area)->ssid = schid->ssid;
+       result = chsc(*ssqd_area);
+
+       if (result) {
+               QDIO_PRINT_WARN("CHSC returned cc %i on sch 0.%x.%x.\n",
+                               result, schid->ssid, schid->sch_no);
+               goto out;
+       }
+
+       if ((*ssqd_area)->response.code != QDIO_CHSC_RESPONSE_CODE_OK) {
+               QDIO_PRINT_WARN("CHSC response is 0x%x on sch 0.%x.%x.\n",
+                               (*ssqd_area)->response.code,
+                               schid->ssid, schid->sch_no);
+               goto out;
+       }
+       if (!((*ssqd_area)->flags & CHSC_FLAG_QDIO_CAPABILITY) ||
+           !((*ssqd_area)->flags & CHSC_FLAG_VALIDITY) ||
+           ((*ssqd_area)->sch != schid->sch_no)) {
+               QDIO_PRINT_WARN("huh? problems checking out sch 0.%x.%x... " \
+                               "using all SIGAs.\n",
+                               schid->ssid, schid->sch_no);
+               goto out;
+       }
+       return 0;
+out:
+       return -EINVAL;
+}
+
+int
+qdio_get_ssqd_pct(struct ccw_device *cdev)
+{
+       struct qdio_chsc_ssqd *ssqd_area;
+       struct subchannel_id schid;
+       char dbf_text[15];
+       int rc;
+       int pct = 0;
+
+       QDIO_DBF_TEXT0(0, setup, "getpct");
+       schid = ccw_device_get_subchannel_id(cdev);
+       rc = qdio_get_ssqd_information(&schid, &ssqd_area);
+       if (!rc)
+               pct = (int)ssqd_area->pct;
+       if (rc != -ENOMEM)
+               mempool_free(ssqd_area, qdio_mempool_scssc);
+       sprintf(dbf_text, "pct: %d", pct);
+       QDIO_DBF_TEXT2(0, setup, dbf_text);
+       return pct;
+}
+EXPORT_SYMBOL(qdio_get_ssqd_pct);
+
 static void
-qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac,
-                           unsigned long token)
+qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned long token)
 {
        struct qdio_q *q;
        int i;
@@ -2227,7 +2296,7 @@ qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac,
        char dbf_text[15];
 
        /*check if QEBSM is disabled */
-       if (!(irq_ptr->is_qebsm) || !(qdioac & 0x01)) {
+       if (!(irq_ptr->is_qebsm) || !(irq_ptr->qdioac & 0x01)) {
                irq_ptr->is_qebsm  = 0;
                irq_ptr->sch_token = 0;
                irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM;
@@ -2256,102 +2325,27 @@ qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac,
 }
 
 static void
-qdio_get_ssqd_information(struct qdio_irq *irq_ptr)
+qdio_get_ssqd_siga(struct qdio_irq *irq_ptr)
 {
-       int result;
-       unsigned char qdioac;
-       struct {
-               struct chsc_header request;
-               u16 reserved1:10;
-               u16 ssid:2;
-               u16 fmt:4;
-               u16 first_sch;
-               u16 reserved2;
-               u16 last_sch;
-               u32 reserved3;
-               struct chsc_header response;
-               u32 reserved4;
-               u8  flags;
-               u8  reserved5;
-               u16 sch;
-               u8  qfmt;
-               u8  parm;
-               u8  qdioac1;
-               u8  sch_class;
-               u8  reserved7;
-               u8  icnt;
-               u8  reserved8;
-               u8  ocnt;
-               u8 reserved9;
-               u8 mbccnt;
-               u16 qdioac2;
-               u64 sch_token;
-       } *ssqd_area;
+       int rc;
+       struct qdio_chsc_ssqd *ssqd_area;
 
        QDIO_DBF_TEXT0(0,setup,"getssqd");
-       qdioac = 0;
-       ssqd_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC);
-       if (!ssqd_area) {
-               QDIO_PRINT_WARN("Could not get memory for chsc. Using all " \
-                               "SIGAs for sch x%x.\n", irq_ptr->schid.sch_no);
+       irq_ptr->qdioac = 0;
+       rc = qdio_get_ssqd_information(&irq_ptr->schid, &ssqd_area);
+       if (rc) {
+               QDIO_PRINT_WARN("using all SIGAs for sch x%x.n",
+                       irq_ptr->schid.sch_no);
                irq_ptr->qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY |
                                  CHSC_FLAG_SIGA_OUTPUT_NECESSARY |
                                  CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */
                irq_ptr->is_qebsm = 0;
-               irq_ptr->sch_token = 0;
-               irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM;
-               return;
-       }
-
-       ssqd_area->request = (struct chsc_header) {
-               .length = 0x0010,
-               .code   = 0x0024,
-       };
-       ssqd_area->first_sch = irq_ptr->schid.sch_no;
-       ssqd_area->last_sch = irq_ptr->schid.sch_no;
-       ssqd_area->ssid = irq_ptr->schid.ssid;
-       result = chsc(ssqd_area);
-
-       if (result) {
-               QDIO_PRINT_WARN("CHSC returned cc %i. Using all " \
-                               "SIGAs for sch 0.%x.%x.\n", result,
-                               irq_ptr->schid.ssid, irq_ptr->schid.sch_no);
-               qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY |
-                       CHSC_FLAG_SIGA_OUTPUT_NECESSARY |
-                       CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */
-               irq_ptr->is_qebsm  = 0;
-               goto out;
-       }
+       } else
+               irq_ptr->qdioac = ssqd_area->qdioac1;
 
-       if (ssqd_area->response.code != QDIO_CHSC_RESPONSE_CODE_OK) {
-               QDIO_PRINT_WARN("response upon checking SIGA needs " \
-                               "is 0x%x. Using all SIGAs for sch 0.%x.%x.\n",
-                               ssqd_area->response.code,
-                               irq_ptr->schid.ssid, irq_ptr->schid.sch_no);
-               qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY |
-                       CHSC_FLAG_SIGA_OUTPUT_NECESSARY |
-                       CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */
-               irq_ptr->is_qebsm  = 0;
-               goto out;
-       }
-       if (!(ssqd_area->flags & CHSC_FLAG_QDIO_CAPABILITY) ||
-           !(ssqd_area->flags & CHSC_FLAG_VALIDITY) ||
-           (ssqd_area->sch != irq_ptr->schid.sch_no)) {
-               QDIO_PRINT_WARN("huh? problems checking out sch 0.%x.%x... " \
-                               "using all SIGAs.\n",
-                               irq_ptr->schid.ssid, irq_ptr->schid.sch_no);
-               qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY |
-                       CHSC_FLAG_SIGA_OUTPUT_NECESSARY |
-                       CHSC_FLAG_SIGA_SYNC_NECESSARY; /* worst case */
-               irq_ptr->is_qebsm  = 0;
-               goto out;
-       }
-       qdioac = ssqd_area->qdioac1;
-out:
-       qdio_check_subchannel_qebsm(irq_ptr, qdioac,
-                                   ssqd_area->sch_token);
-       mempool_free(ssqd_area, qdio_mempool_scssc);
-       irq_ptr->qdioac = qdioac;
+       qdio_check_subchannel_qebsm(irq_ptr, ssqd_area->sch_token);
+       if (rc != -ENOMEM)
+               mempool_free(ssqd_area, qdio_mempool_scssc);
 }
 
 static unsigned int
@@ -3227,7 +3221,7 @@ qdio_establish(struct qdio_initialize *init_data)
                return -EIO;
        }
 
-       qdio_get_ssqd_information(irq_ptr);
+       qdio_get_ssqd_siga(irq_ptr);
        /* if this gets set once, we're running under VM and can omit SVSes */
        if (irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_NECESSARY)
                omit_svs=1;
index da8a272fd75b678d5c622eca50d3e5e056bc06c5..c3df6b2c38b76c2d2c99a3bb8528c0598cd44ecf 100644 (file)
@@ -406,6 +406,34 @@ do_clear_global_summary(void)
 #define CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS 0x08
 #define CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS 0x04
 
+struct qdio_chsc_ssqd {
+       struct chsc_header request;
+       u16 reserved1:10;
+       u16 ssid:2;
+       u16 fmt:4;
+       u16 first_sch;
+       u16 reserved2;
+       u16 last_sch;
+       u32 reserved3;
+       struct chsc_header response;
+       u32 reserved4;
+       u8  flags;
+       u8  reserved5;
+       u16 sch;
+       u8  qfmt;
+       u8  parm;
+       u8  qdioac1;
+       u8  sch_class;
+       u8  pct;
+       u8  icnt;
+       u8  reserved7;
+       u8  ocnt;
+       u8  reserved8;
+       u8  mbccnt;
+       u16 qdioac2;
+       u64 sch_token;
+};
+
 struct qdio_perf_stats {
 #ifdef CONFIG_64BIT
        atomic64_t tl_runs;