aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-05 13:11:02 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-05 13:11:02 -0500
commit39ce941ec15032c0efc3632b9f00a6b2365e1870 (patch)
tree9ac548adf0444b8a74e31c984e5a49766fc2c385 /drivers
parent3d412f60b71e588544e7b75861084f12aa1d7acd (diff)
parentc5411dba58c28736d25cffef65da1e01ed7d1423 (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.c19
-rw-r--r--drivers/s390/block/dasd_3990_erp.c62
-rw-r--r--drivers/s390/block/dcssblk.c5
-rw-r--r--drivers/s390/char/sclp_tty.c2
-rw-r--r--drivers/s390/char/sclp_vt220.c2
-rw-r--r--drivers/s390/cio/ccwgroup.c12
-rw-r--r--drivers/s390/cio/chsc.c147
-rw-r--r--drivers/s390/cio/device_id.c107
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
2135static struct dasd_ccw_req *
2136dasd_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
394static 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
394static struct bus_type ccwgroup_bus_type = { 405static 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
27static void *sei_page; 27static void *sei_page;
28 28
29static 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
29struct chsc_ssd_area { 48struct 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 }
851out: 836out:
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 }
955out: 928out:
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));
1071exit: 1034exit:
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 */
35static void 37static int vm_vdev_to_cu_type(int class, int type)
36VM_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 */
88static 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}