aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block/dasd_eckd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/block/dasd_eckd.c')
-rw-r--r--drivers/s390/block/dasd_eckd.c140
1 files changed, 110 insertions, 30 deletions
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 12257776e79b..0dfab30e8089 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -24,6 +24,7 @@
24#include <asm/io.h> 24#include <asm/io.h>
25#include <asm/todclk.h> 25#include <asm/todclk.h>
26#include <asm/uaccess.h> 26#include <asm/uaccess.h>
27#include <asm/cio.h>
27#include <asm/ccwdev.h> 28#include <asm/ccwdev.h>
28 29
29#include "dasd_int.h" 30#include "dasd_int.h"
@@ -89,17 +90,22 @@ dasd_eckd_probe (struct ccw_device *cdev)
89{ 90{
90 int ret; 91 int ret;
91 92
92 ret = dasd_generic_probe (cdev, &dasd_eckd_discipline); 93 /* set ECKD specific ccw-device options */
93 if (ret) 94 ret = ccw_device_set_options(cdev, CCWDEV_ALLOW_FORCE);
95 if (ret) {
96 printk(KERN_WARNING
97 "dasd_eckd_probe: could not set ccw-device options "
98 "for %s\n", cdev->dev.bus_id);
94 return ret; 99 return ret;
95 ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP | CCWDEV_ALLOW_FORCE); 100 }
96 return 0; 101 ret = dasd_generic_probe(cdev, &dasd_eckd_discipline);
102 return ret;
97} 103}
98 104
99static int 105static int
100dasd_eckd_set_online(struct ccw_device *cdev) 106dasd_eckd_set_online(struct ccw_device *cdev)
101{ 107{
102 return dasd_generic_set_online (cdev, &dasd_eckd_discipline); 108 return dasd_generic_set_online(cdev, &dasd_eckd_discipline);
103} 109}
104 110
105static struct ccw_driver dasd_eckd_driver = { 111static struct ccw_driver dasd_eckd_driver = {
@@ -541,6 +547,86 @@ dasd_eckd_read_conf(struct dasd_device *device)
541} 547}
542 548
543/* 549/*
550 * Build CP for Perform Subsystem Function - SSC.
551 */
552struct dasd_ccw_req *
553dasd_eckd_build_psf_ssc(struct dasd_device *device)
554{
555 struct dasd_ccw_req *cqr;
556 struct dasd_psf_ssc_data *psf_ssc_data;
557 struct ccw1 *ccw;
558
559 cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ ,
560 sizeof(struct dasd_psf_ssc_data),
561 device);
562
563 if (IS_ERR(cqr)) {
564 DEV_MESSAGE(KERN_WARNING, device, "%s",
565 "Could not allocate PSF-SSC request");
566 return cqr;
567 }
568 psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;
569 psf_ssc_data->order = PSF_ORDER_SSC;
570 psf_ssc_data->suborder = 0x08;
571
572 ccw = cqr->cpaddr;
573 ccw->cmd_code = DASD_ECKD_CCW_PSF;
574 ccw->cda = (__u32)(addr_t)psf_ssc_data;
575 ccw->count = 66;
576
577 cqr->device = device;
578 cqr->expires = 10*HZ;
579 cqr->buildclk = get_clock();
580 cqr->status = DASD_CQR_FILLED;
581 return cqr;
582}
583
584/*
585 * Perform Subsystem Function.
586 * It is necessary to trigger CIO for channel revalidation since this
587 * call might change behaviour of DASD devices.
588 */
589static int
590dasd_eckd_psf_ssc(struct dasd_device *device)
591{
592 struct dasd_ccw_req *cqr;
593 int rc;
594
595 cqr = dasd_eckd_build_psf_ssc(device);
596 if (IS_ERR(cqr))
597 return PTR_ERR(cqr);
598
599 rc = dasd_sleep_on(cqr);
600 if (!rc)
601 /* trigger CIO to reprobe devices */
602 css_schedule_reprobe();
603 dasd_sfree_request(cqr, cqr->device);
604 return rc;
605}
606
607/*
608 * Valide storage server of current device.
609 */
610static int
611dasd_eckd_validate_server(struct dasd_device *device)
612{
613 int rc;
614
615 /* Currently PAV is the only reason to 'validate' server on LPAR */
616 if (dasd_nopav || MACHINE_IS_VM)
617 return 0;
618
619 rc = dasd_eckd_psf_ssc(device);
620 if (rc)
621 /* may be requested feature is not available on server,
622 * therefore just report error and go ahead */
623 DEV_MESSAGE(KERN_INFO, device,
624 "Perform Subsystem Function returned rc=%d", rc);
625 /* RE-Read Configuration Data */
626 return dasd_eckd_read_conf(device);
627}
628
629/*
544 * Check device characteristics. 630 * Check device characteristics.
545 * If the device is accessible using ECKD discipline, the device is enabled. 631 * If the device is accessible using ECKD discipline, the device is enabled.
546 */ 632 */
@@ -570,16 +656,29 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
570 private->attrib.operation = DASD_NORMAL_CACHE; 656 private->attrib.operation = DASD_NORMAL_CACHE;
571 private->attrib.nr_cyl = 0; 657 private->attrib.nr_cyl = 0;
572 658
659 /* Read Configuration Data */
660 rc = dasd_eckd_read_conf(device);
661 if (rc)
662 return rc;
663
664 /* Generate device unique id and register in devmap */
665 rc = dasd_eckd_generate_uid(device, &uid);
666 if (rc)
667 return rc;
668 rc = dasd_set_uid(device->cdev, &uid);
669 if (rc == 1) /* new server found */
670 rc = dasd_eckd_validate_server(device);
671 if (rc)
672 return rc;
673
573 /* Read Device Characteristics */ 674 /* Read Device Characteristics */
574 rdc_data = (void *) &(private->rdc_data); 675 rdc_data = (void *) &(private->rdc_data);
575 memset(rdc_data, 0, sizeof(rdc_data)); 676 memset(rdc_data, 0, sizeof(rdc_data));
576 rc = read_dev_chars(device->cdev, &rdc_data, 64); 677 rc = read_dev_chars(device->cdev, &rdc_data, 64);
577 if (rc) { 678 if (rc)
578 DEV_MESSAGE(KERN_WARNING, device, 679 DEV_MESSAGE(KERN_WARNING, device,
579 "Read device characteristics returned error %d", 680 "Read device characteristics returned "
580 rc); 681 "rc=%d", rc);
581 return rc;
582 }
583 682
584 DEV_MESSAGE(KERN_INFO, device, 683 DEV_MESSAGE(KERN_INFO, device,
585 "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d", 684 "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d",
@@ -590,19 +689,6 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
590 private->rdc_data.no_cyl, 689 private->rdc_data.no_cyl,
591 private->rdc_data.trk_per_cyl, 690 private->rdc_data.trk_per_cyl,
592 private->rdc_data.sec_per_trk); 691 private->rdc_data.sec_per_trk);
593
594 /* Read Configuration Data */
595 rc = dasd_eckd_read_conf (device);
596 if (rc)
597 return rc;
598
599 /* Generate device unique id and register in devmap */
600 rc = dasd_eckd_generate_uid(device, &uid);
601 if (rc)
602 return rc;
603
604 rc = dasd_set_uid(device->cdev, &uid);
605
606 return rc; 692 return rc;
607} 693}
608 694
@@ -1687,14 +1773,8 @@ static struct dasd_discipline dasd_eckd_discipline = {
1687static int __init 1773static int __init
1688dasd_eckd_init(void) 1774dasd_eckd_init(void)
1689{ 1775{
1690 int ret;
1691
1692 ASCEBC(dasd_eckd_discipline.ebcname, 4); 1776 ASCEBC(dasd_eckd_discipline.ebcname, 4);
1693 1777 return ccw_driver_register(&dasd_eckd_driver);
1694 ret = ccw_driver_register(&dasd_eckd_driver);
1695 if (!ret)
1696 dasd_generic_auto_online(&dasd_eckd_driver);
1697 return ret;
1698} 1778}
1699 1779
1700static void __exit 1780static void __exit