diff options
author | Jan Glauber <jang@linux.vnet.ibm.com> | 2008-12-25 07:38:43 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-12-25 07:38:58 -0500 |
commit | bbd50e172f75b1d12ef9b1bcf593b51a44199016 (patch) | |
tree | 85cffdd66bb9f4da36d604d857959964736f3fde | |
parent | 43c207e6e5b7e591b59294ee4fc9860b0e3de3b8 (diff) |
[S390] qdio: fix qeth port count detection
qeth needs to get the port count information before
qdio has allocated a page for the chsc operation.
Extend qdio_get_ssqd_desc() to store the data in the
specified structure.
Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/include/asm/qdio.h | 16 | ||||
-rw-r--r-- | drivers/s390/cio/qdio.h | 3 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_main.c | 18 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_setup.c | 33 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 15 |
5 files changed, 55 insertions, 30 deletions
diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index 4734c3f05354..27fc1746de15 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h | |||
@@ -373,16 +373,16 @@ struct qdio_initialize { | |||
373 | #define QDIO_FLAG_SYNC_OUTPUT 0x02 | 373 | #define QDIO_FLAG_SYNC_OUTPUT 0x02 |
374 | #define QDIO_FLAG_PCI_OUT 0x10 | 374 | #define QDIO_FLAG_PCI_OUT 0x10 |
375 | 375 | ||
376 | extern int qdio_initialize(struct qdio_initialize *init_data); | 376 | extern int qdio_initialize(struct qdio_initialize *); |
377 | extern int qdio_allocate(struct qdio_initialize *init_data); | 377 | extern int qdio_allocate(struct qdio_initialize *); |
378 | extern int qdio_establish(struct qdio_initialize *init_data); | 378 | extern int qdio_establish(struct qdio_initialize *); |
379 | extern int qdio_activate(struct ccw_device *); | 379 | extern int qdio_activate(struct ccw_device *); |
380 | 380 | ||
381 | extern int do_QDIO(struct ccw_device*, unsigned int flags, | 381 | extern int do_QDIO(struct ccw_device *cdev, unsigned int callflags, |
382 | int q_nr, int qidx, int count); | 382 | int q_nr, int bufnr, int count); |
383 | extern int qdio_cleanup(struct ccw_device*, int how); | 383 | extern int qdio_cleanup(struct ccw_device*, int); |
384 | extern int qdio_shutdown(struct ccw_device*, int how); | 384 | extern int qdio_shutdown(struct ccw_device*, int); |
385 | extern int qdio_free(struct ccw_device *); | 385 | extern int qdio_free(struct ccw_device *); |
386 | extern struct qdio_ssqd_desc *qdio_get_ssqd_desc(struct ccw_device *cdev); | 386 | extern int qdio_get_ssqd_desc(struct ccw_device *dev, struct qdio_ssqd_desc*); |
387 | 387 | ||
388 | #endif /* __QDIO_H__ */ | 388 | #endif /* __QDIO_H__ */ |
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index e3ea1d5f2810..e4e33839c7fe 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h | |||
@@ -378,6 +378,9 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
378 | int qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs, | 378 | int qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs, |
379 | int nr_output_qs); | 379 | int nr_output_qs); |
380 | void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr); | 380 | void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr); |
381 | int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr, | ||
382 | struct subchannel_id *schid, | ||
383 | struct qdio_ssqd_desc *data); | ||
381 | int qdio_setup_irq(struct qdio_initialize *init_data); | 384 | int qdio_setup_irq(struct qdio_initialize *init_data); |
382 | void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, | 385 | void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, |
383 | struct ccw_device *cdev); | 386 | struct ccw_device *cdev); |
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 7c8659151993..7572a0057623 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
@@ -1129,23 +1129,23 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1129 | /** | 1129 | /** |
1130 | * qdio_get_ssqd_desc - get qdio subchannel description | 1130 | * qdio_get_ssqd_desc - get qdio subchannel description |
1131 | * @cdev: ccw device to get description for | 1131 | * @cdev: ccw device to get description for |
1132 | * @data: where to store the ssqd | ||
1132 | * | 1133 | * |
1133 | * Returns a pointer to the saved qdio subchannel description, | 1134 | * Returns 0 or an error code. The results of the chsc are stored in the |
1134 | * or NULL for not setup qdio devices. | 1135 | * specified structure. |
1135 | */ | 1136 | */ |
1136 | struct qdio_ssqd_desc *qdio_get_ssqd_desc(struct ccw_device *cdev) | 1137 | int qdio_get_ssqd_desc(struct ccw_device *cdev, |
1138 | struct qdio_ssqd_desc *data) | ||
1137 | { | 1139 | { |
1138 | struct qdio_irq *irq_ptr; | ||
1139 | char dbf_text[15]; | 1140 | char dbf_text[15]; |
1140 | 1141 | ||
1142 | if (!cdev || !cdev->private) | ||
1143 | return -EINVAL; | ||
1144 | |||
1141 | sprintf(dbf_text, "qssq%4x", cdev->private->schid.sch_no); | 1145 | sprintf(dbf_text, "qssq%4x", cdev->private->schid.sch_no); |
1142 | QDIO_DBF_TEXT0(0, setup, dbf_text); | 1146 | QDIO_DBF_TEXT0(0, setup, dbf_text); |
1143 | 1147 | ||
1144 | irq_ptr = cdev->private->qdio_data; | 1148 | return qdio_setup_get_ssqd(NULL, &cdev->private->schid, data); |
1145 | if (!irq_ptr) | ||
1146 | return NULL; | ||
1147 | |||
1148 | return &irq_ptr->ssqd_desc; | ||
1149 | } | 1149 | } |
1150 | EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); | 1150 | EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); |
1151 | 1151 | ||
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index a0b6b46e7466..22ee0272a104 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c | |||
@@ -243,22 +243,31 @@ no_qebsm: | |||
243 | QDIO_DBF_TEXT0(0, setup, "noV=V"); | 243 | QDIO_DBF_TEXT0(0, setup, "noV=V"); |
244 | } | 244 | } |
245 | 245 | ||
246 | static int __get_ssqd_info(struct qdio_irq *irq_ptr) | 246 | /* |
247 | * If there is a qdio_irq we use the chsc_page and store the information | ||
248 | * in the qdio_irq, otherwise we copy it to the specified structure. | ||
249 | */ | ||
250 | int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr, | ||
251 | struct subchannel_id *schid, | ||
252 | struct qdio_ssqd_desc *data) | ||
247 | { | 253 | { |
248 | struct chsc_ssqd_area *ssqd; | 254 | struct chsc_ssqd_area *ssqd; |
249 | int rc; | 255 | int rc; |
250 | 256 | ||
251 | QDIO_DBF_TEXT0(0, setup, "getssqd"); | 257 | QDIO_DBF_TEXT0(0, setup, "getssqd"); |
252 | ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; | 258 | if (irq_ptr != NULL) |
259 | ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; | ||
260 | else | ||
261 | ssqd = (struct chsc_ssqd_area *)__get_free_page(GFP_KERNEL); | ||
253 | memset(ssqd, 0, PAGE_SIZE); | 262 | memset(ssqd, 0, PAGE_SIZE); |
254 | 263 | ||
255 | ssqd->request = (struct chsc_header) { | 264 | ssqd->request = (struct chsc_header) { |
256 | .length = 0x0010, | 265 | .length = 0x0010, |
257 | .code = 0x0024, | 266 | .code = 0x0024, |
258 | }; | 267 | }; |
259 | ssqd->first_sch = irq_ptr->schid.sch_no; | 268 | ssqd->first_sch = schid->sch_no; |
260 | ssqd->last_sch = irq_ptr->schid.sch_no; | 269 | ssqd->last_sch = schid->sch_no; |
261 | ssqd->ssid = irq_ptr->schid.ssid; | 270 | ssqd->ssid = schid->ssid; |
262 | 271 | ||
263 | if (chsc(ssqd)) | 272 | if (chsc(ssqd)) |
264 | return -EIO; | 273 | return -EIO; |
@@ -268,11 +277,17 @@ static int __get_ssqd_info(struct qdio_irq *irq_ptr) | |||
268 | 277 | ||
269 | if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) || | 278 | if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) || |
270 | !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) || | 279 | !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) || |
271 | (ssqd->qdio_ssqd.sch != irq_ptr->schid.sch_no)) | 280 | (ssqd->qdio_ssqd.sch != schid->sch_no)) |
272 | return -EINVAL; | 281 | return -EINVAL; |
273 | 282 | ||
274 | memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, | 283 | if (irq_ptr != NULL) |
275 | sizeof(struct qdio_ssqd_desc)); | 284 | memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, |
285 | sizeof(struct qdio_ssqd_desc)); | ||
286 | else { | ||
287 | memcpy(data, &ssqd->qdio_ssqd, | ||
288 | sizeof(struct qdio_ssqd_desc)); | ||
289 | free_page((unsigned long)ssqd); | ||
290 | } | ||
276 | return 0; | 291 | return 0; |
277 | } | 292 | } |
278 | 293 | ||
@@ -282,7 +297,7 @@ void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) | |||
282 | char dbf_text[15]; | 297 | char dbf_text[15]; |
283 | int rc; | 298 | int rc; |
284 | 299 | ||
285 | rc = __get_ssqd_info(irq_ptr); | 300 | rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, NULL); |
286 | if (rc) { | 301 | if (rc) { |
287 | QDIO_DBF_TEXT2(0, setup, "ssqdasig"); | 302 | QDIO_DBF_TEXT2(0, setup, "ssqdasig"); |
288 | sprintf(dbf_text, "schn%4x", irq_ptr->schid.sch_no); | 303 | sprintf(dbf_text, "schn%4x", irq_ptr->schid.sch_no); |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 52d26592c72c..ebdc549da537 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -3757,7 +3757,7 @@ static int qeth_core_driver_group(const char *buf, struct device *root_dev, | |||
3757 | 3757 | ||
3758 | int qeth_core_hardsetup_card(struct qeth_card *card) | 3758 | int qeth_core_hardsetup_card(struct qeth_card *card) |
3759 | { | 3759 | { |
3760 | struct qdio_ssqd_desc *qdio_ssqd; | 3760 | struct qdio_ssqd_desc *ssqd; |
3761 | int retries = 3; | 3761 | int retries = 3; |
3762 | int mpno = 0; | 3762 | int mpno = 0; |
3763 | int rc; | 3763 | int rc; |
@@ -3792,9 +3792,16 @@ retry: | |||
3792 | return rc; | 3792 | return rc; |
3793 | } | 3793 | } |
3794 | 3794 | ||
3795 | qdio_ssqd = qdio_get_ssqd_desc(CARD_DDEV(card)); | 3795 | ssqd = kmalloc(sizeof(struct qdio_ssqd_desc), GFP_KERNEL); |
3796 | if (qdio_ssqd) | 3796 | if (!ssqd) { |
3797 | mpno = qdio_ssqd->pcnt; | 3797 | rc = -ENOMEM; |
3798 | goto out; | ||
3799 | } | ||
3800 | rc = qdio_get_ssqd_desc(CARD_DDEV(card), ssqd); | ||
3801 | if (rc == 0) | ||
3802 | mpno = ssqd->pcnt; | ||
3803 | kfree(ssqd); | ||
3804 | |||
3798 | if (mpno) | 3805 | if (mpno) |
3799 | mpno = min(mpno - 1, QETH_MAX_PORTNO); | 3806 | mpno = min(mpno - 1, QETH_MAX_PORTNO); |
3800 | if (card->info.portno > mpno) { | 3807 | if (card->info.portno > mpno) { |