diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-05 13:11:02 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-05 13:11:02 -0500 |
commit | 39ce941ec15032c0efc3632b9f00a6b2365e1870 (patch) | |
tree | 9ac548adf0444b8a74e31c984e5a49766fc2c385 /drivers | |
parent | 3d412f60b71e588544e7b75861084f12aa1d7acd (diff) | |
parent | c5411dba58c28736d25cffef65da1e01ed7d1423 (diff) |
Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6:
[S390] dcss: Initialize workqueue before using it.
[S390] Remove BUILD_BUG_ON() in vmem code.
[S390] sclp_tty/sclp_vt220: Fix scheduling while atomic
[S390] dasd: fix panic caused by alias device offline
[S390] dasd: add ifcc handling
[S390] latencytop s390 support.
[S390] Implement ext2_find_next_bit.
[S390] Cleanup & optimize bitops.
[S390] Define GENERIC_LOCKBREAK.
[S390] console: allow vt220 console to be the only console
[S390] Fix couple of section mismatches.
[S390] Fix smp_call_function_mask semantics.
[S390] Fix linker script.
[S390] DEBUG_PAGEALLOC support for s390.
[S390] cio: Add shutdown callback for ccwgroup.
[S390] cio: Update documentation.
[S390] cio: Clean up chsc response code handling.
[S390] cio: make sense id procedure work with partial hardware response
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/s390/block/dasd.c | 19 | ||||
-rw-r--r-- | drivers/s390/block/dasd_3990_erp.c | 62 | ||||
-rw-r--r-- | drivers/s390/block/dcssblk.c | 5 | ||||
-rw-r--r-- | drivers/s390/char/sclp_tty.c | 2 | ||||
-rw-r--r-- | drivers/s390/char/sclp_vt220.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/ccwgroup.c | 12 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.c | 147 | ||||
-rw-r--r-- | drivers/s390/cio/device_id.c | 107 |
8 files changed, 188 insertions, 168 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index d640427c74c8..d984e0fae630 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -1057,12 +1057,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1057 | if (device->features & DASD_FEATURE_ERPLOG) { | 1057 | if (device->features & DASD_FEATURE_ERPLOG) { |
1058 | dasd_log_sense(cqr, irb); | 1058 | dasd_log_sense(cqr, irb); |
1059 | } | 1059 | } |
1060 | /* If we have no sense data, or we just don't want complex ERP | 1060 | /* |
1061 | * for this request, but if we have retries left, then just | 1061 | * If we don't want complex ERP for this request, then just |
1062 | * reset this request and retry it in the fastpath | 1062 | * reset this and retry it in the fastpath |
1063 | */ | 1063 | */ |
1064 | if (!(cqr->irb.esw.esw0.erw.cons && | 1064 | if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) && |
1065 | test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) && | ||
1066 | cqr->retries > 0) { | 1065 | cqr->retries > 0) { |
1067 | DEV_MESSAGE(KERN_DEBUG, device, | 1066 | DEV_MESSAGE(KERN_DEBUG, device, |
1068 | "default ERP in fastpath (%i retries left)", | 1067 | "default ERP in fastpath (%i retries left)", |
@@ -1707,7 +1706,7 @@ static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr) | |||
1707 | 1706 | ||
1708 | req = (struct request *) cqr->callback_data; | 1707 | req = (struct request *) cqr->callback_data; |
1709 | dasd_profile_end(cqr->block, cqr, req); | 1708 | dasd_profile_end(cqr->block, cqr, req); |
1710 | status = cqr->memdev->discipline->free_cp(cqr, req); | 1709 | status = cqr->block->base->discipline->free_cp(cqr, req); |
1711 | if (status <= 0) | 1710 | if (status <= 0) |
1712 | error = status ? status : -EIO; | 1711 | error = status ? status : -EIO; |
1713 | dasd_end_request(req, error); | 1712 | dasd_end_request(req, error); |
@@ -1742,12 +1741,8 @@ restart: | |||
1742 | 1741 | ||
1743 | /* Process requests that may be recovered */ | 1742 | /* Process requests that may be recovered */ |
1744 | if (cqr->status == DASD_CQR_NEED_ERP) { | 1743 | if (cqr->status == DASD_CQR_NEED_ERP) { |
1745 | if (cqr->irb.esw.esw0.erw.cons && | 1744 | erp_fn = base->discipline->erp_action(cqr); |
1746 | test_bit(DASD_CQR_FLAGS_USE_ERP, | 1745 | erp_fn(cqr); |
1747 | &cqr->flags)) { | ||
1748 | erp_fn = base->discipline->erp_action(cqr); | ||
1749 | erp_fn(cqr); | ||
1750 | } | ||
1751 | goto restart; | 1746 | goto restart; |
1752 | } | 1747 | } |
1753 | 1748 | ||
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index c361ab69ec00..f69714a0e9e7 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c | |||
@@ -164,7 +164,7 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp) | |||
164 | 164 | ||
165 | /* reset status to submit the request again... */ | 165 | /* reset status to submit the request again... */ |
166 | erp->status = DASD_CQR_FILLED; | 166 | erp->status = DASD_CQR_FILLED; |
167 | erp->retries = 1; | 167 | erp->retries = 10; |
168 | } else { | 168 | } else { |
169 | DEV_MESSAGE(KERN_ERR, device, | 169 | DEV_MESSAGE(KERN_ERR, device, |
170 | "No alternate channel path left (lpum=%x / " | 170 | "No alternate channel path left (lpum=%x / " |
@@ -301,8 +301,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense) | |||
301 | erp->function = dasd_3990_erp_action_4; | 301 | erp->function = dasd_3990_erp_action_4; |
302 | 302 | ||
303 | } else { | 303 | } else { |
304 | 304 | if (sense && (sense[25] == 0x1D)) { /* state change pending */ | |
305 | if (sense[25] == 0x1D) { /* state change pending */ | ||
306 | 305 | ||
307 | DEV_MESSAGE(KERN_INFO, device, | 306 | DEV_MESSAGE(KERN_INFO, device, |
308 | "waiting for state change pending " | 307 | "waiting for state change pending " |
@@ -311,7 +310,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense) | |||
311 | 310 | ||
312 | dasd_3990_erp_block_queue(erp, 30*HZ); | 311 | dasd_3990_erp_block_queue(erp, 30*HZ); |
313 | 312 | ||
314 | } else if (sense[25] == 0x1E) { /* busy */ | 313 | } else if (sense && (sense[25] == 0x1E)) { /* busy */ |
315 | DEV_MESSAGE(KERN_INFO, device, | 314 | DEV_MESSAGE(KERN_INFO, device, |
316 | "busy - redriving request later, " | 315 | "busy - redriving request later, " |
317 | "%d retries left", | 316 | "%d retries left", |
@@ -2120,6 +2119,34 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense) | |||
2120 | */ | 2119 | */ |
2121 | 2120 | ||
2122 | /* | 2121 | /* |
2122 | * DASD_3990_ERP_CONTROL_CHECK | ||
2123 | * | ||
2124 | * DESCRIPTION | ||
2125 | * Does a generic inspection if a control check occured and sets up | ||
2126 | * the related error recovery procedure | ||
2127 | * | ||
2128 | * PARAMETER | ||
2129 | * erp pointer to the currently created default ERP | ||
2130 | * | ||
2131 | * RETURN VALUES | ||
2132 | * erp_filled pointer to the erp | ||
2133 | */ | ||
2134 | |||
2135 | static struct dasd_ccw_req * | ||
2136 | dasd_3990_erp_control_check(struct dasd_ccw_req *erp) | ||
2137 | { | ||
2138 | struct dasd_device *device = erp->startdev; | ||
2139 | |||
2140 | if (erp->refers->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK | ||
2141 | | SCHN_STAT_CHN_CTRL_CHK)) { | ||
2142 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | ||
2143 | "channel or interface control check"); | ||
2144 | erp = dasd_3990_erp_action_4(erp, NULL); | ||
2145 | } | ||
2146 | return erp; | ||
2147 | } | ||
2148 | |||
2149 | /* | ||
2123 | * DASD_3990_ERP_INSPECT | 2150 | * DASD_3990_ERP_INSPECT |
2124 | * | 2151 | * |
2125 | * DESCRIPTION | 2152 | * DESCRIPTION |
@@ -2145,8 +2172,11 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp) | |||
2145 | if (erp_new) | 2172 | if (erp_new) |
2146 | return erp_new; | 2173 | return erp_new; |
2147 | 2174 | ||
2175 | /* check if no concurrent sens is available */ | ||
2176 | if (!erp->refers->irb.esw.esw0.erw.cons) | ||
2177 | erp_new = dasd_3990_erp_control_check(erp); | ||
2148 | /* distinguish between 24 and 32 byte sense data */ | 2178 | /* distinguish between 24 and 32 byte sense data */ |
2149 | if (sense[27] & DASD_SENSE_BIT_0) { | 2179 | else if (sense[27] & DASD_SENSE_BIT_0) { |
2150 | 2180 | ||
2151 | /* inspect the 24 byte sense data */ | 2181 | /* inspect the 24 byte sense data */ |
2152 | erp_new = dasd_3990_erp_inspect_24(erp, sense); | 2182 | erp_new = dasd_3990_erp_inspect_24(erp, sense); |
@@ -2285,6 +2315,17 @@ dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, struct dasd_ccw_req *cqr2) | |||
2285 | // return 0; /* CCW doesn't match */ | 2315 | // return 0; /* CCW doesn't match */ |
2286 | } | 2316 | } |
2287 | 2317 | ||
2318 | if (cqr1->irb.esw.esw0.erw.cons != cqr2->irb.esw.esw0.erw.cons) | ||
2319 | return 0; | ||
2320 | |||
2321 | if ((cqr1->irb.esw.esw0.erw.cons == 0) && | ||
2322 | (cqr2->irb.esw.esw0.erw.cons == 0)) { | ||
2323 | if ((cqr1->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK | | ||
2324 | SCHN_STAT_CHN_CTRL_CHK)) == | ||
2325 | (cqr2->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK | | ||
2326 | SCHN_STAT_CHN_CTRL_CHK))) | ||
2327 | return 1; /* match with ifcc*/ | ||
2328 | } | ||
2288 | /* check sense data; byte 0-2,25,27 */ | 2329 | /* check sense data; byte 0-2,25,27 */ |
2289 | if (!((memcmp (cqr1->irb.ecw, cqr2->irb.ecw, 3) == 0) && | 2330 | if (!((memcmp (cqr1->irb.ecw, cqr2->irb.ecw, 3) == 0) && |
2290 | (cqr1->irb.ecw[27] == cqr2->irb.ecw[27]) && | 2331 | (cqr1->irb.ecw[27] == cqr2->irb.ecw[27]) && |
@@ -2560,17 +2601,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) | |||
2560 | 2601 | ||
2561 | return cqr; | 2602 | return cqr; |
2562 | } | 2603 | } |
2563 | /* check if sense data are available */ | ||
2564 | if (!cqr->irb.ecw) { | ||
2565 | DEV_MESSAGE(KERN_DEBUG, device, | ||
2566 | "ERP called witout sense data avail ..." | ||
2567 | "request %p - NO ERP possible", cqr); | ||
2568 | |||
2569 | cqr->status = DASD_CQR_FAILED; | ||
2570 | |||
2571 | return cqr; | ||
2572 | |||
2573 | } | ||
2574 | 2604 | ||
2575 | /* check if error happened before */ | 2605 | /* check if error happened before */ |
2576 | erp = dasd_3990_erp_in_erp(cqr); | 2606 | erp = dasd_3990_erp_in_erp(cqr); |
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 7779bfce1c31..3faf0538b328 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c | |||
@@ -415,6 +415,8 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char | |||
415 | dev_info->gd->queue = dev_info->dcssblk_queue; | 415 | dev_info->gd->queue = dev_info->dcssblk_queue; |
416 | dev_info->gd->private_data = dev_info; | 416 | dev_info->gd->private_data = dev_info; |
417 | dev_info->gd->driverfs_dev = &dev_info->dev; | 417 | dev_info->gd->driverfs_dev = &dev_info->dev; |
418 | blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request); | ||
419 | blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096); | ||
418 | /* | 420 | /* |
419 | * load the segment | 421 | * load the segment |
420 | */ | 422 | */ |
@@ -472,9 +474,6 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char | |||
472 | if (rc) | 474 | if (rc) |
473 | goto unregister_dev; | 475 | goto unregister_dev; |
474 | 476 | ||
475 | blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request); | ||
476 | blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096); | ||
477 | |||
478 | add_disk(dev_info->gd); | 477 | add_disk(dev_info->gd); |
479 | 478 | ||
480 | switch (dev_info->segment_type) { | 479 | switch (dev_info->segment_type) { |
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index e3b3d390b4a3..2e616e33891d 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c | |||
@@ -332,7 +332,7 @@ sclp_tty_write_string(const unsigned char *str, int count) | |||
332 | if (sclp_ttybuf == NULL) { | 332 | if (sclp_ttybuf == NULL) { |
333 | while (list_empty(&sclp_tty_pages)) { | 333 | while (list_empty(&sclp_tty_pages)) { |
334 | spin_unlock_irqrestore(&sclp_tty_lock, flags); | 334 | spin_unlock_irqrestore(&sclp_tty_lock, flags); |
335 | if (in_interrupt()) | 335 | if (in_atomic()) |
336 | sclp_sync_wait(); | 336 | sclp_sync_wait(); |
337 | else | 337 | else |
338 | wait_event(sclp_tty_waitq, | 338 | wait_event(sclp_tty_waitq, |
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 40cd21bc5cc4..68071622d4bb 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c | |||
@@ -400,7 +400,7 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule, | |||
400 | while (list_empty(&sclp_vt220_empty)) { | 400 | while (list_empty(&sclp_vt220_empty)) { |
401 | spin_unlock_irqrestore(&sclp_vt220_lock, | 401 | spin_unlock_irqrestore(&sclp_vt220_lock, |
402 | flags); | 402 | flags); |
403 | if (in_interrupt()) | 403 | if (in_atomic()) |
404 | sclp_sync_wait(); | 404 | sclp_sync_wait(); |
405 | else | 405 | else |
406 | wait_event(sclp_vt220_waitq, | 406 | wait_event(sclp_vt220_waitq, |
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 3964056a9a47..03914fa81174 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c | |||
@@ -391,12 +391,24 @@ ccwgroup_remove (struct device *dev) | |||
391 | return 0; | 391 | return 0; |
392 | } | 392 | } |
393 | 393 | ||
394 | static void ccwgroup_shutdown(struct device *dev) | ||
395 | { | ||
396 | struct ccwgroup_device *gdev; | ||
397 | struct ccwgroup_driver *gdrv; | ||
398 | |||
399 | gdev = to_ccwgroupdev(dev); | ||
400 | gdrv = to_ccwgroupdrv(dev->driver); | ||
401 | if (gdrv && gdrv->shutdown) | ||
402 | gdrv->shutdown(gdev); | ||
403 | } | ||
404 | |||
394 | static struct bus_type ccwgroup_bus_type = { | 405 | static struct bus_type ccwgroup_bus_type = { |
395 | .name = "ccwgroup", | 406 | .name = "ccwgroup", |
396 | .match = ccwgroup_bus_match, | 407 | .match = ccwgroup_bus_match, |
397 | .uevent = ccwgroup_uevent, | 408 | .uevent = ccwgroup_uevent, |
398 | .probe = ccwgroup_probe, | 409 | .probe = ccwgroup_probe, |
399 | .remove = ccwgroup_remove, | 410 | .remove = ccwgroup_remove, |
411 | .shutdown = ccwgroup_shutdown, | ||
400 | }; | 412 | }; |
401 | 413 | ||
402 | /** | 414 | /** |
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index e7ba16a74ef7..007aaeb4f532 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -26,6 +26,25 @@ | |||
26 | 26 | ||
27 | static void *sei_page; | 27 | static void *sei_page; |
28 | 28 | ||
29 | static int chsc_error_from_response(int response) | ||
30 | { | ||
31 | switch (response) { | ||
32 | case 0x0001: | ||
33 | return 0; | ||
34 | case 0x0002: | ||
35 | case 0x0003: | ||
36 | case 0x0006: | ||
37 | case 0x0007: | ||
38 | case 0x0008: | ||
39 | case 0x000a: | ||
40 | return -EINVAL; | ||
41 | case 0x0004: | ||
42 | return -EOPNOTSUPP; | ||
43 | default: | ||
44 | return -EIO; | ||
45 | } | ||
46 | } | ||
47 | |||
29 | struct chsc_ssd_area { | 48 | struct chsc_ssd_area { |
30 | struct chsc_header request; | 49 | struct chsc_header request; |
31 | u16 :10; | 50 | u16 :10; |
@@ -75,11 +94,11 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd) | |||
75 | ret = (ccode == 3) ? -ENODEV : -EBUSY; | 94 | ret = (ccode == 3) ? -ENODEV : -EBUSY; |
76 | goto out_free; | 95 | goto out_free; |
77 | } | 96 | } |
78 | if (ssd_area->response.code != 0x0001) { | 97 | ret = chsc_error_from_response(ssd_area->response.code); |
98 | if (ret != 0) { | ||
79 | CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n", | 99 | CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n", |
80 | schid.ssid, schid.sch_no, | 100 | schid.ssid, schid.sch_no, |
81 | ssd_area->response.code); | 101 | ssd_area->response.code); |
82 | ret = -EIO; | ||
83 | goto out_free; | 102 | goto out_free; |
84 | } | 103 | } |
85 | if (!ssd_area->sch_valid) { | 104 | if (!ssd_area->sch_valid) { |
@@ -717,36 +736,15 @@ __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) | |||
717 | return (ccode == 3) ? -ENODEV : -EBUSY; | 736 | return (ccode == 3) ? -ENODEV : -EBUSY; |
718 | 737 | ||
719 | switch (secm_area->response.code) { | 738 | switch (secm_area->response.code) { |
720 | case 0x0001: /* Success. */ | 739 | case 0x0102: |
721 | ret = 0; | 740 | case 0x0103: |
722 | break; | ||
723 | case 0x0003: /* Invalid block. */ | ||
724 | case 0x0007: /* Invalid format. */ | ||
725 | case 0x0008: /* Other invalid block. */ | ||
726 | CIO_CRW_EVENT(2, "Error in chsc request block!\n"); | ||
727 | ret = -EINVAL; | ||
728 | break; | ||
729 | case 0x0004: /* Command not provided in model. */ | ||
730 | CIO_CRW_EVENT(2, "Model does not provide secm\n"); | ||
731 | ret = -EOPNOTSUPP; | ||
732 | break; | ||
733 | case 0x0102: /* cub adresses incorrect */ | ||
734 | CIO_CRW_EVENT(2, "Invalid addresses in chsc request block\n"); | ||
735 | ret = -EINVAL; | ||
736 | break; | ||
737 | case 0x0103: /* key error */ | ||
738 | CIO_CRW_EVENT(2, "Access key error in secm\n"); | ||
739 | ret = -EINVAL; | 741 | ret = -EINVAL; |
740 | break; | ||
741 | case 0x0105: /* error while starting */ | ||
742 | CIO_CRW_EVENT(2, "Error while starting channel measurement\n"); | ||
743 | ret = -EIO; | ||
744 | break; | ||
745 | default: | 742 | default: |
746 | CIO_CRW_EVENT(2, "Unknown CHSC response %d\n", | 743 | ret = chsc_error_from_response(secm_area->response.code); |
747 | secm_area->response.code); | ||
748 | ret = -EIO; | ||
749 | } | 744 | } |
745 | if (ret != 0) | ||
746 | CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n", | ||
747 | secm_area->response.code); | ||
750 | return ret; | 748 | return ret; |
751 | } | 749 | } |
752 | 750 | ||
@@ -827,27 +825,14 @@ int chsc_determine_channel_path_description(struct chp_id chpid, | |||
827 | goto out; | 825 | goto out; |
828 | } | 826 | } |
829 | 827 | ||
830 | switch (scpd_area->response.code) { | 828 | ret = chsc_error_from_response(scpd_area->response.code); |
831 | case 0x0001: /* Success. */ | 829 | if (ret == 0) |
830 | /* Success. */ | ||
832 | memcpy(desc, &scpd_area->desc, | 831 | memcpy(desc, &scpd_area->desc, |
833 | sizeof(struct channel_path_desc)); | 832 | sizeof(struct channel_path_desc)); |
834 | ret = 0; | 833 | else |
835 | break; | 834 | CIO_CRW_EVENT(2, "chsc: scpd failed (rc=%04x)\n", |
836 | case 0x0003: /* Invalid block. */ | ||
837 | case 0x0007: /* Invalid format. */ | ||
838 | case 0x0008: /* Other invalid block. */ | ||
839 | CIO_CRW_EVENT(2, "Error in chsc request block!\n"); | ||
840 | ret = -EINVAL; | ||
841 | break; | ||
842 | case 0x0004: /* Command not provided in model. */ | ||
843 | CIO_CRW_EVENT(2, "Model does not provide scpd\n"); | ||
844 | ret = -EOPNOTSUPP; | ||
845 | break; | ||
846 | default: | ||
847 | CIO_CRW_EVENT(2, "Unknown CHSC response %d\n", | ||
848 | scpd_area->response.code); | 835 | scpd_area->response.code); |
849 | ret = -EIO; | ||
850 | } | ||
851 | out: | 836 | out: |
852 | free_page((unsigned long)scpd_area); | 837 | free_page((unsigned long)scpd_area); |
853 | return ret; | 838 | return ret; |
@@ -923,8 +908,9 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp) | |||
923 | goto out; | 908 | goto out; |
924 | } | 909 | } |
925 | 910 | ||
926 | switch (scmc_area->response.code) { | 911 | ret = chsc_error_from_response(scmc_area->response.code); |
927 | case 0x0001: /* Success. */ | 912 | if (ret == 0) { |
913 | /* Success. */ | ||
928 | if (!scmc_area->not_valid) { | 914 | if (!scmc_area->not_valid) { |
929 | chp->cmg = scmc_area->cmg; | 915 | chp->cmg = scmc_area->cmg; |
930 | chp->shared = scmc_area->shared; | 916 | chp->shared = scmc_area->shared; |
@@ -935,22 +921,9 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp) | |||
935 | chp->cmg = -1; | 921 | chp->cmg = -1; |
936 | chp->shared = -1; | 922 | chp->shared = -1; |
937 | } | 923 | } |
938 | ret = 0; | 924 | } else { |
939 | break; | 925 | CIO_CRW_EVENT(2, "chsc: scmc failed (rc=%04x)\n", |
940 | case 0x0003: /* Invalid block. */ | ||
941 | case 0x0007: /* Invalid format. */ | ||
942 | case 0x0008: /* Invalid bit combination. */ | ||
943 | CIO_CRW_EVENT(2, "Error in chsc request block!\n"); | ||
944 | ret = -EINVAL; | ||
945 | break; | ||
946 | case 0x0004: /* Command not provided. */ | ||
947 | CIO_CRW_EVENT(2, "Model does not provide scmc\n"); | ||
948 | ret = -EOPNOTSUPP; | ||
949 | break; | ||
950 | default: | ||
951 | CIO_CRW_EVENT(2, "Unknown CHSC response %d\n", | ||
952 | scmc_area->response.code); | 926 | scmc_area->response.code); |
953 | ret = -EIO; | ||
954 | } | 927 | } |
955 | out: | 928 | out: |
956 | free_page((unsigned long)scmc_area); | 929 | free_page((unsigned long)scmc_area); |
@@ -1002,21 +975,17 @@ chsc_enable_facility(int operation_code) | |||
1002 | ret = (ret == 3) ? -ENODEV : -EBUSY; | 975 | ret = (ret == 3) ? -ENODEV : -EBUSY; |
1003 | goto out; | 976 | goto out; |
1004 | } | 977 | } |
978 | |||
1005 | switch (sda_area->response.code) { | 979 | switch (sda_area->response.code) { |
1006 | case 0x0001: /* everything ok */ | 980 | case 0x0101: |
1007 | ret = 0; | ||
1008 | break; | ||
1009 | case 0x0003: /* invalid request block */ | ||
1010 | case 0x0007: | ||
1011 | ret = -EINVAL; | ||
1012 | break; | ||
1013 | case 0x0004: /* command not provided */ | ||
1014 | case 0x0101: /* facility not provided */ | ||
1015 | ret = -EOPNOTSUPP; | 981 | ret = -EOPNOTSUPP; |
1016 | break; | 982 | break; |
1017 | default: /* something went wrong */ | 983 | default: |
1018 | ret = -EIO; | 984 | ret = chsc_error_from_response(sda_area->response.code); |
1019 | } | 985 | } |
986 | if (ret != 0) | ||
987 | CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n", | ||
988 | operation_code, sda_area->response.code); | ||
1020 | out: | 989 | out: |
1021 | free_page((unsigned long)sda_area); | 990 | free_page((unsigned long)sda_area); |
1022 | return ret; | 991 | return ret; |
@@ -1041,33 +1010,27 @@ chsc_determine_css_characteristics(void) | |||
1041 | } __attribute__ ((packed)) *scsc_area; | 1010 | } __attribute__ ((packed)) *scsc_area; |
1042 | 1011 | ||
1043 | scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); | 1012 | scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); |
1044 | if (!scsc_area) { | 1013 | if (!scsc_area) |
1045 | CIO_MSG_EVENT(0, "Was not able to determine available " | ||
1046 | "CHSCs due to no memory.\n"); | ||
1047 | return -ENOMEM; | 1014 | return -ENOMEM; |
1048 | } | ||
1049 | 1015 | ||
1050 | scsc_area->request.length = 0x0010; | 1016 | scsc_area->request.length = 0x0010; |
1051 | scsc_area->request.code = 0x0010; | 1017 | scsc_area->request.code = 0x0010; |
1052 | 1018 | ||
1053 | result = chsc(scsc_area); | 1019 | result = chsc(scsc_area); |
1054 | if (result) { | 1020 | if (result) { |
1055 | CIO_MSG_EVENT(0, "Was not able to determine available CHSCs, " | 1021 | result = (result == 3) ? -ENODEV : -EBUSY; |
1056 | "cc=%i.\n", result); | ||
1057 | result = -EIO; | ||
1058 | goto exit; | 1022 | goto exit; |
1059 | } | 1023 | } |
1060 | 1024 | ||
1061 | if (scsc_area->response.code != 1) { | 1025 | result = chsc_error_from_response(scsc_area->response.code); |
1062 | CIO_MSG_EVENT(0, "Was not able to determine " | 1026 | if (result == 0) { |
1063 | "available CHSCs.\n"); | 1027 | memcpy(&css_general_characteristics, scsc_area->general_char, |
1064 | result = -EIO; | 1028 | sizeof(css_general_characteristics)); |
1065 | goto exit; | 1029 | memcpy(&css_chsc_characteristics, scsc_area->chsc_char, |
1066 | } | 1030 | sizeof(css_chsc_characteristics)); |
1067 | memcpy(&css_general_characteristics, scsc_area->general_char, | 1031 | } else |
1068 | sizeof(css_general_characteristics)); | 1032 | CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n", |
1069 | memcpy(&css_chsc_characteristics, scsc_area->chsc_char, | 1033 | scsc_area->response.code); |
1070 | sizeof(css_chsc_characteristics)); | ||
1071 | exit: | 1034 | exit: |
1072 | free_page ((unsigned long) scsc_area); | 1035 | free_page ((unsigned long) scsc_area); |
1073 | return result; | 1036 | return result; |
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index 918b8b89cf9a..dc4d87f77f6c 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c | |||
@@ -26,17 +26,18 @@ | |||
26 | #include "ioasm.h" | 26 | #include "ioasm.h" |
27 | #include "io_sch.h" | 27 | #include "io_sch.h" |
28 | 28 | ||
29 | /* | 29 | /** |
30 | * Input : | 30 | * vm_vdev_to_cu_type - Convert vm virtual device into control unit type |
31 | * devno - device number | 31 | * for certain devices. |
32 | * ps - pointer to sense ID data area | 32 | * @class: virtual device class |
33 | * Output : none | 33 | * @type: virtual device type |
34 | * | ||
35 | * Returns control unit type if a match was made or %0xffff otherwise. | ||
34 | */ | 36 | */ |
35 | static void | 37 | static int vm_vdev_to_cu_type(int class, int type) |
36 | VM_virtual_device_info (__u16 devno, struct senseid *ps) | ||
37 | { | 38 | { |
38 | static struct { | 39 | static struct { |
39 | int vrdcvcla, vrdcvtyp, cu_type; | 40 | int class, type, cu_type; |
40 | } vm_devices[] = { | 41 | } vm_devices[] = { |
41 | { 0x08, 0x01, 0x3480 }, | 42 | { 0x08, 0x01, 0x3480 }, |
42 | { 0x08, 0x02, 0x3430 }, | 43 | { 0x08, 0x02, 0x3430 }, |
@@ -68,8 +69,26 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps) | |||
68 | { 0x40, 0xc0, 0x5080 }, | 69 | { 0x40, 0xc0, 0x5080 }, |
69 | { 0x80, 0x00, 0x3215 }, | 70 | { 0x80, 0x00, 0x3215 }, |
70 | }; | 71 | }; |
72 | int i; | ||
73 | |||
74 | for (i = 0; i < ARRAY_SIZE(vm_devices); i++) | ||
75 | if (class == vm_devices[i].class && type == vm_devices[i].type) | ||
76 | return vm_devices[i].cu_type; | ||
77 | |||
78 | return 0xffff; | ||
79 | } | ||
80 | |||
81 | /** | ||
82 | * diag_get_dev_info - retrieve device information via DIAG X'210' | ||
83 | * @devno: device number | ||
84 | * @ps: pointer to sense ID data area | ||
85 | * | ||
86 | * Returns zero on success, non-zero otherwise. | ||
87 | */ | ||
88 | static int diag_get_dev_info(u16 devno, struct senseid *ps) | ||
89 | { | ||
71 | struct diag210 diag_data; | 90 | struct diag210 diag_data; |
72 | int ccode, i; | 91 | int ccode; |
73 | 92 | ||
74 | CIO_TRACE_EVENT (4, "VMvdinf"); | 93 | CIO_TRACE_EVENT (4, "VMvdinf"); |
75 | 94 | ||
@@ -79,21 +98,21 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps) | |||
79 | }; | 98 | }; |
80 | 99 | ||
81 | ccode = diag210 (&diag_data); | 100 | ccode = diag210 (&diag_data); |
82 | ps->reserved = 0xff; | 101 | if ((ccode == 0) || (ccode == 2)) { |
102 | ps->reserved = 0xff; | ||
83 | 103 | ||
84 | /* Special case for bloody osa devices. */ | 104 | /* Special case for osa devices. */ |
85 | if (diag_data.vrdcvcla == 0x02 && | 105 | if (diag_data.vrdcvcla == 0x02 && diag_data.vrdcvtyp == 0x20) { |
86 | diag_data.vrdcvtyp == 0x20) { | 106 | ps->cu_type = 0x3088; |
87 | ps->cu_type = 0x3088; | 107 | ps->cu_model = 0x60; |
88 | ps->cu_model = 0x60; | 108 | return 0; |
89 | return; | ||
90 | } | ||
91 | for (i = 0; i < ARRAY_SIZE(vm_devices); i++) | ||
92 | if (diag_data.vrdcvcla == vm_devices[i].vrdcvcla && | ||
93 | diag_data.vrdcvtyp == vm_devices[i].vrdcvtyp) { | ||
94 | ps->cu_type = vm_devices[i].cu_type; | ||
95 | return; | ||
96 | } | 109 | } |
110 | ps->cu_type = vm_vdev_to_cu_type(diag_data.vrdcvcla, | ||
111 | diag_data.vrdcvtyp); | ||
112 | if (ps->cu_type != 0xffff) | ||
113 | return 0; | ||
114 | } | ||
115 | |||
97 | CIO_MSG_EVENT(0, "DIAG X'210' for device %04X returned (cc = %d):" | 116 | CIO_MSG_EVENT(0, "DIAG X'210' for device %04X returned (cc = %d):" |
98 | "vdev class : %02X, vdev type : %04X \n ... " | 117 | "vdev class : %02X, vdev type : %04X \n ... " |
99 | "rdev class : %02X, rdev type : %04X, " | 118 | "rdev class : %02X, rdev type : %04X, " |
@@ -102,6 +121,8 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps) | |||
102 | diag_data.vrdcvcla, diag_data.vrdcvtyp, | 121 | diag_data.vrdcvcla, diag_data.vrdcvtyp, |
103 | diag_data.vrdcrccl, diag_data.vrdccrty, | 122 | diag_data.vrdcrccl, diag_data.vrdccrty, |
104 | diag_data.vrdccrmd); | 123 | diag_data.vrdccrmd); |
124 | |||
125 | return -ENODEV; | ||
105 | } | 126 | } |
106 | 127 | ||
107 | /* | 128 | /* |
@@ -130,6 +151,7 @@ __ccw_device_sense_id_start(struct ccw_device *cdev) | |||
130 | /* Try on every path. */ | 151 | /* Try on every path. */ |
131 | ret = -ENODEV; | 152 | ret = -ENODEV; |
132 | while (cdev->private->imask != 0) { | 153 | while (cdev->private->imask != 0) { |
154 | cdev->private->senseid.cu_type = 0xFFFF; | ||
133 | if ((sch->opm & cdev->private->imask) != 0 && | 155 | if ((sch->opm & cdev->private->imask) != 0 && |
134 | cdev->private->iretry > 0) { | 156 | cdev->private->iretry > 0) { |
135 | cdev->private->iretry--; | 157 | cdev->private->iretry--; |
@@ -153,7 +175,6 @@ ccw_device_sense_id_start(struct ccw_device *cdev) | |||
153 | int ret; | 175 | int ret; |
154 | 176 | ||
155 | memset (&cdev->private->senseid, 0, sizeof (struct senseid)); | 177 | memset (&cdev->private->senseid, 0, sizeof (struct senseid)); |
156 | cdev->private->senseid.cu_type = 0xFFFF; | ||
157 | cdev->private->imask = 0x80; | 178 | cdev->private->imask = 0x80; |
158 | cdev->private->iretry = 5; | 179 | cdev->private->iretry = 5; |
159 | ret = __ccw_device_sense_id_start(cdev); | 180 | ret = __ccw_device_sense_id_start(cdev); |
@@ -173,13 +194,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev) | |||
173 | 194 | ||
174 | sch = to_subchannel(cdev->dev.parent); | 195 | sch = to_subchannel(cdev->dev.parent); |
175 | irb = &cdev->private->irb; | 196 | irb = &cdev->private->irb; |
176 | /* Did we get a proper answer ? */ | 197 | |
177 | if (cdev->private->senseid.cu_type != 0xFFFF && | ||
178 | cdev->private->senseid.reserved == 0xFF) { | ||
179 | if (irb->scsw.count < sizeof (struct senseid) - 8) | ||
180 | cdev->private->flags.esid = 1; | ||
181 | return 0; /* Success */ | ||
182 | } | ||
183 | /* Check the error cases. */ | 198 | /* Check the error cases. */ |
184 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { | 199 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { |
185 | /* Retry Sense ID if requested. */ | 200 | /* Retry Sense ID if requested. */ |
@@ -231,6 +246,15 @@ ccw_device_check_sense_id(struct ccw_device *cdev) | |||
231 | sch->schid.ssid, sch->schid.sch_no); | 246 | sch->schid.ssid, sch->schid.sch_no); |
232 | return -EACCES; | 247 | return -EACCES; |
233 | } | 248 | } |
249 | |||
250 | /* Did we get a proper answer ? */ | ||
251 | if (irb->scsw.cc == 0 && cdev->private->senseid.cu_type != 0xFFFF && | ||
252 | cdev->private->senseid.reserved == 0xFF) { | ||
253 | if (irb->scsw.count < sizeof(struct senseid) - 8) | ||
254 | cdev->private->flags.esid = 1; | ||
255 | return 0; /* Success */ | ||
256 | } | ||
257 | |||
234 | /* Hmm, whatever happened, try again. */ | 258 | /* Hmm, whatever happened, try again. */ |
235 | CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on " | 259 | CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on " |
236 | "subchannel 0.%x.%04x returns status %02X%02X\n", | 260 | "subchannel 0.%x.%04x returns status %02X%02X\n", |
@@ -283,20 +307,17 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event) | |||
283 | break; | 307 | break; |
284 | /* fall through. */ | 308 | /* fall through. */ |
285 | default: /* Sense ID failed. Try asking VM. */ | 309 | default: /* Sense ID failed. Try asking VM. */ |
286 | if (MACHINE_IS_VM) { | 310 | if (MACHINE_IS_VM) |
287 | VM_virtual_device_info (cdev->private->dev_id.devno, | 311 | ret = diag_get_dev_info(cdev->private->dev_id.devno, |
288 | &cdev->private->senseid); | 312 | &cdev->private->senseid); |
289 | if (cdev->private->senseid.cu_type != 0xFFFF) { | 313 | else |
290 | /* Got the device information from VM. */ | 314 | /* |
291 | ccw_device_sense_id_done(cdev, 0); | 315 | * If we can't couldn't identify the device type we |
292 | return; | 316 | * consider the device "not operational". |
293 | } | 317 | */ |
294 | } | 318 | ret = -ENODEV; |
295 | /* | 319 | |
296 | * If we can't couldn't identify the device type we | 320 | ccw_device_sense_id_done(cdev, ret); |
297 | * consider the device "not operational". | ||
298 | */ | ||
299 | ccw_device_sense_id_done(cdev, -ENODEV); | ||
300 | break; | 321 | break; |
301 | } | 322 | } |
302 | } | 323 | } |