diff options
author | Stefan Haberland <sth@linux.vnet.ibm.com> | 2016-08-08 09:53:54 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2016-12-12 06:04:37 -0500 |
commit | c93461515a1a16486f4e483cb34170366fa73ea1 (patch) | |
tree | ae5ea26b0f7046c63914277799c72f83a2da14d5 | |
parent | 7df11604592b579bce2762783c21569d02272332 (diff) |
s390/dasd: extend dasd path handling
Store flags and path_data per channel path.
Implement get/set functions for various path masks.
The patch does not add functional changes.
Signed-off-by: Stefan Haberland <sth@linux.vnet.ibm.com>
Reviewed-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | drivers/s390/block/dasd.c | 101 | ||||
-rw-r--r-- | drivers/s390/block/dasd_3990_erp.c | 6 | ||||
-rw-r--r-- | drivers/s390/block/dasd_devmap.c | 10 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 113 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.h | 3 | ||||
-rw-r--r-- | drivers/s390/block/dasd_erp.c | 2 | ||||
-rw-r--r-- | drivers/s390/block/dasd_fba.c | 2 | ||||
-rw-r--r-- | drivers/s390/block/dasd_int.h | 381 |
8 files changed, 475 insertions, 143 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index e21465ecb60f..13a337faef43 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -1448,9 +1448,9 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) | |||
1448 | cqr->starttime = jiffies; | 1448 | cqr->starttime = jiffies; |
1449 | cqr->retries--; | 1449 | cqr->retries--; |
1450 | if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) { | 1450 | if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) { |
1451 | cqr->lpm &= device->path_data.opm; | 1451 | cqr->lpm &= dasd_path_get_opm(device); |
1452 | if (!cqr->lpm) | 1452 | if (!cqr->lpm) |
1453 | cqr->lpm = device->path_data.opm; | 1453 | cqr->lpm = dasd_path_get_opm(device); |
1454 | } | 1454 | } |
1455 | if (cqr->cpmode == 1) { | 1455 | if (cqr->cpmode == 1) { |
1456 | rc = ccw_device_tm_start(device->cdev, cqr->cpaddr, | 1456 | rc = ccw_device_tm_start(device->cdev, cqr->cpaddr, |
@@ -1483,8 +1483,8 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) | |||
1483 | DBF_DEV_EVENT(DBF_WARNING, device, | 1483 | DBF_DEV_EVENT(DBF_WARNING, device, |
1484 | "start_IO: selected paths gone (%x)", | 1484 | "start_IO: selected paths gone (%x)", |
1485 | cqr->lpm); | 1485 | cqr->lpm); |
1486 | } else if (cqr->lpm != device->path_data.opm) { | 1486 | } else if (cqr->lpm != dasd_path_get_opm(device)) { |
1487 | cqr->lpm = device->path_data.opm; | 1487 | cqr->lpm = dasd_path_get_opm(device); |
1488 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", | 1488 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", |
1489 | "start_IO: selected paths gone," | 1489 | "start_IO: selected paths gone," |
1490 | " retry on all paths"); | 1490 | " retry on all paths"); |
@@ -1493,11 +1493,10 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) | |||
1493 | "start_IO: all paths in opm gone," | 1493 | "start_IO: all paths in opm gone," |
1494 | " do path verification"); | 1494 | " do path verification"); |
1495 | dasd_generic_last_path_gone(device); | 1495 | dasd_generic_last_path_gone(device); |
1496 | device->path_data.opm = 0; | 1496 | dasd_path_no_path(device); |
1497 | device->path_data.ppm = 0; | 1497 | dasd_path_set_tbvpm(device, |
1498 | device->path_data.npm = 0; | 1498 | ccw_device_get_path_mask( |
1499 | device->path_data.tbvpm = | 1499 | device->cdev)); |
1500 | ccw_device_get_path_mask(device->cdev); | ||
1501 | } | 1500 | } |
1502 | break; | 1501 | break; |
1503 | case -ENODEV: | 1502 | case -ENODEV: |
@@ -1642,7 +1641,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1642 | switch (PTR_ERR(irb)) { | 1641 | switch (PTR_ERR(irb)) { |
1643 | case -EIO: | 1642 | case -EIO: |
1644 | if (cqr && cqr->status == DASD_CQR_CLEAR_PENDING) { | 1643 | if (cqr && cqr->status == DASD_CQR_CLEAR_PENDING) { |
1645 | device = (struct dasd_device *) cqr->startdev; | 1644 | device = cqr->startdev; |
1646 | cqr->status = DASD_CQR_CLEARED; | 1645 | cqr->status = DASD_CQR_CLEARED; |
1647 | dasd_device_clear_timer(device); | 1646 | dasd_device_clear_timer(device); |
1648 | wake_up(&dasd_flush_wq); | 1647 | wake_up(&dasd_flush_wq); |
@@ -1755,13 +1754,13 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1755 | */ | 1754 | */ |
1756 | if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) && | 1755 | if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) && |
1757 | cqr->retries > 0) { | 1756 | cqr->retries > 0) { |
1758 | if (cqr->lpm == device->path_data.opm) | 1757 | if (cqr->lpm == dasd_path_get_opm(device)) |
1759 | DBF_DEV_EVENT(DBF_DEBUG, device, | 1758 | DBF_DEV_EVENT(DBF_DEBUG, device, |
1760 | "default ERP in fastpath " | 1759 | "default ERP in fastpath " |
1761 | "(%i retries left)", | 1760 | "(%i retries left)", |
1762 | cqr->retries); | 1761 | cqr->retries); |
1763 | if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) | 1762 | if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) |
1764 | cqr->lpm = device->path_data.opm; | 1763 | cqr->lpm = dasd_path_get_opm(device); |
1765 | cqr->status = DASD_CQR_QUEUED; | 1764 | cqr->status = DASD_CQR_QUEUED; |
1766 | next = cqr; | 1765 | next = cqr; |
1767 | } else | 1766 | } else |
@@ -2002,17 +2001,18 @@ static void __dasd_device_check_path_events(struct dasd_device *device) | |||
2002 | { | 2001 | { |
2003 | int rc; | 2002 | int rc; |
2004 | 2003 | ||
2005 | if (device->path_data.tbvpm) { | 2004 | if (!dasd_path_get_tbvpm(device)) |
2006 | if (device->stopped & ~(DASD_STOPPED_DC_WAIT | | 2005 | return; |
2007 | DASD_UNRESUMED_PM)) | 2006 | |
2008 | return; | 2007 | if (device->stopped & |
2009 | rc = device->discipline->verify_path( | 2008 | ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM)) |
2010 | device, device->path_data.tbvpm); | 2009 | return; |
2011 | if (rc) | 2010 | rc = device->discipline->verify_path(device, |
2012 | dasd_device_set_timer(device, 50); | 2011 | dasd_path_get_tbvpm(device)); |
2013 | else | 2012 | if (rc) |
2014 | device->path_data.tbvpm = 0; | 2013 | dasd_device_set_timer(device, 50); |
2015 | } | 2014 | else |
2015 | dasd_path_clear_all_verify(device); | ||
2016 | }; | 2016 | }; |
2017 | 2017 | ||
2018 | /* | 2018 | /* |
@@ -3684,14 +3684,12 @@ int dasd_generic_notify(struct ccw_device *cdev, int event) | |||
3684 | case CIO_GONE: | 3684 | case CIO_GONE: |
3685 | case CIO_BOXED: | 3685 | case CIO_BOXED: |
3686 | case CIO_NO_PATH: | 3686 | case CIO_NO_PATH: |
3687 | device->path_data.opm = 0; | 3687 | dasd_path_no_path(device); |
3688 | device->path_data.ppm = 0; | ||
3689 | device->path_data.npm = 0; | ||
3690 | ret = dasd_generic_last_path_gone(device); | 3688 | ret = dasd_generic_last_path_gone(device); |
3691 | break; | 3689 | break; |
3692 | case CIO_OPER: | 3690 | case CIO_OPER: |
3693 | ret = 1; | 3691 | ret = 1; |
3694 | if (device->path_data.opm) | 3692 | if (dasd_path_get_opm(device)) |
3695 | ret = dasd_generic_path_operational(device); | 3693 | ret = dasd_generic_path_operational(device); |
3696 | break; | 3694 | break; |
3697 | } | 3695 | } |
@@ -3702,48 +3700,32 @@ EXPORT_SYMBOL_GPL(dasd_generic_notify); | |||
3702 | 3700 | ||
3703 | void dasd_generic_path_event(struct ccw_device *cdev, int *path_event) | 3701 | void dasd_generic_path_event(struct ccw_device *cdev, int *path_event) |
3704 | { | 3702 | { |
3705 | int chp; | ||
3706 | __u8 oldopm, eventlpm; | ||
3707 | struct dasd_device *device; | 3703 | struct dasd_device *device; |
3704 | int chp, oldopm; | ||
3708 | 3705 | ||
3709 | device = dasd_device_from_cdev_locked(cdev); | 3706 | device = dasd_device_from_cdev_locked(cdev); |
3710 | if (IS_ERR(device)) | 3707 | if (IS_ERR(device)) |
3711 | return; | 3708 | return; |
3709 | |||
3710 | oldopm = dasd_path_get_opm(device); | ||
3712 | for (chp = 0; chp < 8; chp++) { | 3711 | for (chp = 0; chp < 8; chp++) { |
3713 | eventlpm = 0x80 >> chp; | ||
3714 | if (path_event[chp] & PE_PATH_GONE) { | 3712 | if (path_event[chp] & PE_PATH_GONE) { |
3715 | oldopm = device->path_data.opm; | 3713 | dasd_path_notoper(device, chp); |
3716 | device->path_data.opm &= ~eventlpm; | ||
3717 | device->path_data.ppm &= ~eventlpm; | ||
3718 | device->path_data.npm &= ~eventlpm; | ||
3719 | if (oldopm && !device->path_data.opm) { | ||
3720 | dev_warn(&device->cdev->dev, | ||
3721 | "No verified channel paths remain " | ||
3722 | "for the device\n"); | ||
3723 | DBF_DEV_EVENT(DBF_WARNING, device, | ||
3724 | "%s", "last verified path gone"); | ||
3725 | dasd_eer_write(device, NULL, DASD_EER_NOPATH); | ||
3726 | dasd_device_set_stop_bits(device, | ||
3727 | DASD_STOPPED_DC_WAIT); | ||
3728 | } | ||
3729 | } | 3714 | } |
3730 | if (path_event[chp] & PE_PATH_AVAILABLE) { | 3715 | if (path_event[chp] & PE_PATH_AVAILABLE) { |
3731 | device->path_data.opm &= ~eventlpm; | 3716 | dasd_path_available(device, chp); |
3732 | device->path_data.ppm &= ~eventlpm; | ||
3733 | device->path_data.npm &= ~eventlpm; | ||
3734 | device->path_data.tbvpm |= eventlpm; | ||
3735 | dasd_schedule_device_bh(device); | 3717 | dasd_schedule_device_bh(device); |
3736 | } | 3718 | } |
3737 | if (path_event[chp] & PE_PATHGROUP_ESTABLISHED) { | 3719 | if (path_event[chp] & PE_PATHGROUP_ESTABLISHED) { |
3738 | if (!(device->path_data.opm & eventlpm) && | 3720 | if (!dasd_path_is_operational(device, chp) && |
3739 | !(device->path_data.tbvpm & eventlpm)) { | 3721 | !dasd_path_need_verify(device, chp)) { |
3740 | /* | 3722 | /* |
3741 | * we can not establish a pathgroup on an | 3723 | * we can not establish a pathgroup on an |
3742 | * unavailable path, so trigger a path | 3724 | * unavailable path, so trigger a path |
3743 | * verification first | 3725 | * verification first |
3744 | */ | 3726 | */ |
3745 | device->path_data.tbvpm |= eventlpm; | 3727 | dasd_path_available(device, chp); |
3746 | dasd_schedule_device_bh(device); | 3728 | dasd_schedule_device_bh(device); |
3747 | } | 3729 | } |
3748 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", | 3730 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", |
3749 | "Pathgroup re-established\n"); | 3731 | "Pathgroup re-established\n"); |
@@ -3751,17 +3733,26 @@ void dasd_generic_path_event(struct ccw_device *cdev, int *path_event) | |||
3751 | device->discipline->kick_validate(device); | 3733 | device->discipline->kick_validate(device); |
3752 | } | 3734 | } |
3753 | } | 3735 | } |
3736 | if (oldopm && !dasd_path_get_opm(device)) { | ||
3737 | dev_warn(&device->cdev->dev, | ||
3738 | "No verified channel paths remain for the device\n"); | ||
3739 | DBF_DEV_EVENT(DBF_WARNING, device, | ||
3740 | "%s", "last verified path gone"); | ||
3741 | dasd_eer_write(device, NULL, DASD_EER_NOPATH); | ||
3742 | dasd_device_set_stop_bits(device, | ||
3743 | DASD_STOPPED_DC_WAIT); | ||
3744 | } | ||
3754 | dasd_put_device(device); | 3745 | dasd_put_device(device); |
3755 | } | 3746 | } |
3756 | EXPORT_SYMBOL_GPL(dasd_generic_path_event); | 3747 | EXPORT_SYMBOL_GPL(dasd_generic_path_event); |
3757 | 3748 | ||
3758 | int dasd_generic_verify_path(struct dasd_device *device, __u8 lpm) | 3749 | int dasd_generic_verify_path(struct dasd_device *device, __u8 lpm) |
3759 | { | 3750 | { |
3760 | if (!device->path_data.opm && lpm) { | 3751 | if (!dasd_path_get_opm(device) && lpm) { |
3761 | device->path_data.opm = lpm; | 3752 | dasd_path_set_opm(device, lpm); |
3762 | dasd_generic_path_operational(device); | 3753 | dasd_generic_path_operational(device); |
3763 | } else | 3754 | } else |
3764 | device->path_data.opm |= lpm; | 3755 | dasd_path_add_opm(device, lpm); |
3765 | return 0; | 3756 | return 0; |
3766 | } | 3757 | } |
3767 | EXPORT_SYMBOL_GPL(dasd_generic_verify_path); | 3758 | EXPORT_SYMBOL_GPL(dasd_generic_verify_path); |
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 8305ab688d57..9236e2c0c3d9 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c | |||
@@ -152,7 +152,7 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp) | |||
152 | opm = ccw_device_get_path_mask(device->cdev); | 152 | opm = ccw_device_get_path_mask(device->cdev); |
153 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | 153 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); |
154 | if (erp->lpm == 0) | 154 | if (erp->lpm == 0) |
155 | erp->lpm = device->path_data.opm & | 155 | erp->lpm = dasd_path_get_opm(device) & |
156 | ~(erp->irb.esw.esw0.sublog.lpum); | 156 | ~(erp->irb.esw.esw0.sublog.lpum); |
157 | else | 157 | else |
158 | erp->lpm &= ~(erp->irb.esw.esw0.sublog.lpum); | 158 | erp->lpm &= ~(erp->irb.esw.esw0.sublog.lpum); |
@@ -273,7 +273,7 @@ static struct dasd_ccw_req *dasd_3990_erp_action_1(struct dasd_ccw_req *erp) | |||
273 | !test_bit(DASD_CQR_VERIFY_PATH, &erp->flags)) { | 273 | !test_bit(DASD_CQR_VERIFY_PATH, &erp->flags)) { |
274 | erp->status = DASD_CQR_FILLED; | 274 | erp->status = DASD_CQR_FILLED; |
275 | erp->retries = 10; | 275 | erp->retries = 10; |
276 | erp->lpm = erp->startdev->path_data.opm; | 276 | erp->lpm = dasd_path_get_opm(erp->startdev); |
277 | erp->function = dasd_3990_erp_action_1_sec; | 277 | erp->function = dasd_3990_erp_action_1_sec; |
278 | } | 278 | } |
279 | return erp; | 279 | return erp; |
@@ -1926,7 +1926,7 @@ dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense) | |||
1926 | !test_bit(DASD_CQR_VERIFY_PATH, &erp->flags)) { | 1926 | !test_bit(DASD_CQR_VERIFY_PATH, &erp->flags)) { |
1927 | /* reset the lpm and the status to be able to | 1927 | /* reset the lpm and the status to be able to |
1928 | * try further actions. */ | 1928 | * try further actions. */ |
1929 | erp->lpm = erp->startdev->path_data.opm; | 1929 | erp->lpm = dasd_path_get_opm(erp->startdev); |
1930 | erp->status = DASD_CQR_NEED_ERP; | 1930 | erp->status = DASD_CQR_NEED_ERP; |
1931 | } | 1931 | } |
1932 | } | 1932 | } |
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index cbae6ab448b8..4101ab000c16 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
@@ -1438,11 +1438,11 @@ static ssize_t dasd_pm_show(struct device *dev, | |||
1438 | if (IS_ERR(device)) | 1438 | if (IS_ERR(device)) |
1439 | return sprintf(buf, "0\n"); | 1439 | return sprintf(buf, "0\n"); |
1440 | 1440 | ||
1441 | opm = device->path_data.opm; | 1441 | opm = dasd_path_get_opm(device); |
1442 | nppm = device->path_data.npm; | 1442 | nppm = dasd_path_get_nppm(device); |
1443 | cablepm = device->path_data.cablepm; | 1443 | cablepm = dasd_path_get_cablepm(device); |
1444 | cuirpm = device->path_data.cuirpm; | 1444 | cuirpm = dasd_path_get_cuirpm(device); |
1445 | hpfpm = device->path_data.hpfpm; | 1445 | hpfpm = dasd_path_get_hpfpm(device); |
1446 | dasd_put_device(device); | 1446 | dasd_put_device(device); |
1447 | 1447 | ||
1448 | return sprintf(buf, "%02x %02x %02x %02x %02x\n", opm, nppm, | 1448 | return sprintf(buf, "%02x %02x %02x %02x %02x\n", opm, nppm, |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index a7a88476e215..51fdf31aa8eb 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -1042,8 +1042,8 @@ static void dasd_eckd_clear_conf_data(struct dasd_device *device) | |||
1042 | private->conf_data = NULL; | 1042 | private->conf_data = NULL; |
1043 | private->conf_len = 0; | 1043 | private->conf_len = 0; |
1044 | for (i = 0; i < 8; i++) { | 1044 | for (i = 0; i < 8; i++) { |
1045 | kfree(private->path_conf_data[i]); | 1045 | kfree(device->path[i].conf_data); |
1046 | private->path_conf_data[i] = NULL; | 1046 | device->path[i].conf_data = NULL; |
1047 | } | 1047 | } |
1048 | } | 1048 | } |
1049 | 1049 | ||
@@ -1055,12 +1055,10 @@ static int dasd_eckd_read_conf(struct dasd_device *device) | |||
1055 | int rc, path_err, pos; | 1055 | int rc, path_err, pos; |
1056 | __u8 lpm, opm; | 1056 | __u8 lpm, opm; |
1057 | struct dasd_eckd_private *private, path_private; | 1057 | struct dasd_eckd_private *private, path_private; |
1058 | struct dasd_path *path_data; | ||
1059 | struct dasd_uid *uid; | 1058 | struct dasd_uid *uid; |
1060 | char print_path_uid[60], print_device_uid[60]; | 1059 | char print_path_uid[60], print_device_uid[60]; |
1061 | 1060 | ||
1062 | private = device->private; | 1061 | private = device->private; |
1063 | path_data = &device->path_data; | ||
1064 | opm = ccw_device_get_path_mask(device->cdev); | 1062 | opm = ccw_device_get_path_mask(device->cdev); |
1065 | conf_data_saved = 0; | 1063 | conf_data_saved = 0; |
1066 | path_err = 0; | 1064 | path_err = 0; |
@@ -1081,7 +1079,7 @@ static int dasd_eckd_read_conf(struct dasd_device *device) | |||
1081 | "No configuration data " | 1079 | "No configuration data " |
1082 | "retrieved"); | 1080 | "retrieved"); |
1083 | /* no further analysis possible */ | 1081 | /* no further analysis possible */ |
1084 | path_data->opm |= lpm; | 1082 | dasd_path_add_opm(device, opm); |
1085 | continue; /* no error */ | 1083 | continue; /* no error */ |
1086 | } | 1084 | } |
1087 | /* save first valid configuration data */ | 1085 | /* save first valid configuration data */ |
@@ -1098,8 +1096,7 @@ static int dasd_eckd_read_conf(struct dasd_device *device) | |||
1098 | } | 1096 | } |
1099 | pos = pathmask_to_pos(lpm); | 1097 | pos = pathmask_to_pos(lpm); |
1100 | /* store per path conf_data */ | 1098 | /* store per path conf_data */ |
1101 | private->path_conf_data[pos] = | 1099 | device->path[pos].conf_data = conf_data; |
1102 | (struct dasd_conf_data *) conf_data; | ||
1103 | /* | 1100 | /* |
1104 | * build device UID that other path data | 1101 | * build device UID that other path data |
1105 | * can be compared to it | 1102 | * can be compared to it |
@@ -1154,37 +1151,29 @@ static int dasd_eckd_read_conf(struct dasd_device *device) | |||
1154 | "device %s instead of %s\n", lpm, | 1151 | "device %s instead of %s\n", lpm, |
1155 | print_path_uid, print_device_uid); | 1152 | print_path_uid, print_device_uid); |
1156 | path_err = -EINVAL; | 1153 | path_err = -EINVAL; |
1157 | path_data->cablepm |= lpm; | 1154 | dasd_path_add_cablepm(device, lpm); |
1158 | continue; | 1155 | continue; |
1159 | } | 1156 | } |
1160 | pos = pathmask_to_pos(lpm); | 1157 | pos = pathmask_to_pos(lpm); |
1161 | /* store per path conf_data */ | 1158 | /* store per path conf_data */ |
1162 | private->path_conf_data[pos] = | 1159 | device->path[pos].conf_data = conf_data; |
1163 | (struct dasd_conf_data *) conf_data; | ||
1164 | path_private.conf_data = NULL; | 1160 | path_private.conf_data = NULL; |
1165 | path_private.conf_len = 0; | 1161 | path_private.conf_len = 0; |
1166 | } | 1162 | } |
1167 | switch (dasd_eckd_path_access(conf_data, conf_len)) { | 1163 | switch (dasd_eckd_path_access(conf_data, conf_len)) { |
1168 | case 0x02: | 1164 | case 0x02: |
1169 | path_data->npm |= lpm; | 1165 | dasd_path_add_nppm(device, lpm); |
1170 | break; | 1166 | break; |
1171 | case 0x03: | 1167 | case 0x03: |
1172 | path_data->ppm |= lpm; | 1168 | dasd_path_add_ppm(device, lpm); |
1173 | break; | 1169 | break; |
1174 | } | 1170 | } |
1175 | if (!path_data->opm) { | 1171 | if (!dasd_path_get_opm(device)) { |
1176 | path_data->opm = lpm; | 1172 | dasd_path_set_opm(device, lpm); |
1177 | dasd_generic_path_operational(device); | 1173 | dasd_generic_path_operational(device); |
1178 | } else { | 1174 | } else { |
1179 | path_data->opm |= lpm; | 1175 | dasd_path_add_opm(device, lpm); |
1180 | } | 1176 | } |
1181 | /* | ||
1182 | * if the path is used | ||
1183 | * it should not be in one of the negative lists | ||
1184 | */ | ||
1185 | path_data->cablepm &= ~lpm; | ||
1186 | path_data->hpfpm &= ~lpm; | ||
1187 | path_data->cuirpm &= ~lpm; | ||
1188 | } | 1177 | } |
1189 | 1178 | ||
1190 | return path_err; | 1179 | return path_err; |
@@ -1222,8 +1211,7 @@ static int rebuild_device_uid(struct dasd_device *device, | |||
1222 | struct path_verification_work_data *data) | 1211 | struct path_verification_work_data *data) |
1223 | { | 1212 | { |
1224 | struct dasd_eckd_private *private = device->private; | 1213 | struct dasd_eckd_private *private = device->private; |
1225 | struct dasd_path *path_data = &device->path_data; | 1214 | __u8 lpm, opm = dasd_path_get_opm(device); |
1226 | __u8 lpm, opm = path_data->opm; | ||
1227 | int rc = -ENODEV; | 1215 | int rc = -ENODEV; |
1228 | 1216 | ||
1229 | for (lpm = 0x80; lpm; lpm >>= 1) { | 1217 | for (lpm = 0x80; lpm; lpm >>= 1) { |
@@ -1356,7 +1344,7 @@ static void do_path_verification_work(struct work_struct *work) | |||
1356 | * in other case the device UID may have changed and | 1344 | * in other case the device UID may have changed and |
1357 | * the first working path UID will be used as device UID | 1345 | * the first working path UID will be used as device UID |
1358 | */ | 1346 | */ |
1359 | if (device->path_data.opm && | 1347 | if (dasd_path_get_opm(device) && |
1360 | dasd_eckd_compare_path_uid(device, &path_private)) { | 1348 | dasd_eckd_compare_path_uid(device, &path_private)) { |
1361 | /* | 1349 | /* |
1362 | * the comparison was not successful | 1350 | * the comparison was not successful |
@@ -1406,23 +1394,17 @@ static void do_path_verification_work(struct work_struct *work) | |||
1406 | * situation in dasd_start_IO. | 1394 | * situation in dasd_start_IO. |
1407 | */ | 1395 | */ |
1408 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | 1396 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); |
1409 | if (!device->path_data.opm && opm) { | 1397 | if (!dasd_path_get_opm(device) && opm) { |
1410 | device->path_data.opm = opm; | 1398 | dasd_path_set_opm(device, opm); |
1411 | device->path_data.cablepm &= ~opm; | ||
1412 | device->path_data.cuirpm &= ~opm; | ||
1413 | device->path_data.hpfpm &= ~opm; | ||
1414 | dasd_generic_path_operational(device); | 1399 | dasd_generic_path_operational(device); |
1415 | } else { | 1400 | } else { |
1416 | device->path_data.opm |= opm; | 1401 | dasd_path_add_opm(device, opm); |
1417 | device->path_data.cablepm &= ~opm; | ||
1418 | device->path_data.cuirpm &= ~opm; | ||
1419 | device->path_data.hpfpm &= ~opm; | ||
1420 | } | 1402 | } |
1421 | device->path_data.npm |= npm; | 1403 | dasd_path_add_nppm(device, npm); |
1422 | device->path_data.ppm |= ppm; | 1404 | dasd_path_add_ppm(device, ppm); |
1423 | device->path_data.tbvpm |= epm; | 1405 | dasd_path_add_tbvpm(device, epm); |
1424 | device->path_data.cablepm |= cablepm; | 1406 | dasd_path_add_cablepm(device, cablepm); |
1425 | device->path_data.hpfpm |= hpfpm; | 1407 | dasd_path_add_nohpfpm(device, hpfpm); |
1426 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | 1408 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); |
1427 | } | 1409 | } |
1428 | clear_bit(DASD_FLAG_PATH_VERIFY, &device->flags); | 1410 | clear_bit(DASD_FLAG_PATH_VERIFY, &device->flags); |
@@ -1839,13 +1821,13 @@ static void dasd_eckd_uncheck_device(struct dasd_device *device) | |||
1839 | private->gneq = NULL; | 1821 | private->gneq = NULL; |
1840 | private->conf_len = 0; | 1822 | private->conf_len = 0; |
1841 | for (i = 0; i < 8; i++) { | 1823 | for (i = 0; i < 8; i++) { |
1842 | kfree(private->path_conf_data[i]); | 1824 | kfree(device->path[i].conf_data); |
1843 | if ((__u8 *)private->path_conf_data[i] == | 1825 | if ((__u8 *)device->path[i].conf_data == |
1844 | private->conf_data) { | 1826 | private->conf_data) { |
1845 | private->conf_data = NULL; | 1827 | private->conf_data = NULL; |
1846 | private->conf_len = 0; | 1828 | private->conf_len = 0; |
1847 | } | 1829 | } |
1848 | private->path_conf_data[i] = NULL; | 1830 | device->path[i].conf_data = NULL; |
1849 | } | 1831 | } |
1850 | kfree(private->conf_data); | 1832 | kfree(private->conf_data); |
1851 | private->conf_data = NULL; | 1833 | private->conf_data = NULL; |
@@ -2966,7 +2948,7 @@ static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr) | |||
2966 | if (cqr->block && (cqr->startdev != cqr->block->base)) { | 2948 | if (cqr->block && (cqr->startdev != cqr->block->base)) { |
2967 | dasd_eckd_reset_ccw_to_base_io(cqr); | 2949 | dasd_eckd_reset_ccw_to_base_io(cqr); |
2968 | cqr->startdev = cqr->block->base; | 2950 | cqr->startdev = cqr->block->base; |
2969 | cqr->lpm = cqr->block->base->path_data.opm; | 2951 | cqr->lpm = dasd_path_get_opm(cqr->block->base); |
2970 | } | 2952 | } |
2971 | }; | 2953 | }; |
2972 | 2954 | ||
@@ -3251,7 +3233,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( | |||
3251 | cqr->memdev = startdev; | 3233 | cqr->memdev = startdev; |
3252 | cqr->block = block; | 3234 | cqr->block = block; |
3253 | cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ | 3235 | cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ |
3254 | cqr->lpm = startdev->path_data.ppm; | 3236 | cqr->lpm = dasd_path_get_ppm(startdev); |
3255 | cqr->retries = startdev->default_retries; | 3237 | cqr->retries = startdev->default_retries; |
3256 | cqr->buildclk = get_tod_clock(); | 3238 | cqr->buildclk = get_tod_clock(); |
3257 | cqr->status = DASD_CQR_FILLED; | 3239 | cqr->status = DASD_CQR_FILLED; |
@@ -3426,7 +3408,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( | |||
3426 | cqr->memdev = startdev; | 3408 | cqr->memdev = startdev; |
3427 | cqr->block = block; | 3409 | cqr->block = block; |
3428 | cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ | 3410 | cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ |
3429 | cqr->lpm = startdev->path_data.ppm; | 3411 | cqr->lpm = dasd_path_get_ppm(startdev); |
3430 | cqr->retries = startdev->default_retries; | 3412 | cqr->retries = startdev->default_retries; |
3431 | cqr->buildclk = get_tod_clock(); | 3413 | cqr->buildclk = get_tod_clock(); |
3432 | cqr->status = DASD_CQR_FILLED; | 3414 | cqr->status = DASD_CQR_FILLED; |
@@ -3735,7 +3717,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( | |||
3735 | cqr->memdev = startdev; | 3717 | cqr->memdev = startdev; |
3736 | cqr->block = block; | 3718 | cqr->block = block; |
3737 | cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ | 3719 | cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ |
3738 | cqr->lpm = startdev->path_data.ppm; | 3720 | cqr->lpm = dasd_path_get_ppm(startdev); |
3739 | cqr->retries = startdev->default_retries; | 3721 | cqr->retries = startdev->default_retries; |
3740 | cqr->buildclk = get_tod_clock(); | 3722 | cqr->buildclk = get_tod_clock(); |
3741 | cqr->status = DASD_CQR_FILLED; | 3723 | cqr->status = DASD_CQR_FILLED; |
@@ -3962,7 +3944,7 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev, | |||
3962 | cqr->memdev = startdev; | 3944 | cqr->memdev = startdev; |
3963 | cqr->block = block; | 3945 | cqr->block = block; |
3964 | cqr->expires = startdev->default_expires * HZ; | 3946 | cqr->expires = startdev->default_expires * HZ; |
3965 | cqr->lpm = startdev->path_data.ppm; | 3947 | cqr->lpm = dasd_path_get_ppm(startdev); |
3966 | cqr->retries = startdev->default_retries; | 3948 | cqr->retries = startdev->default_retries; |
3967 | cqr->buildclk = get_tod_clock(); | 3949 | cqr->buildclk = get_tod_clock(); |
3968 | cqr->status = DASD_CQR_FILLED; | 3950 | cqr->status = DASD_CQR_FILLED; |
@@ -5363,20 +5345,19 @@ static struct dasd_conf_data *dasd_eckd_get_ref_conf(struct dasd_device *device, | |||
5363 | __u8 lpum, | 5345 | __u8 lpum, |
5364 | struct dasd_cuir_message *cuir) | 5346 | struct dasd_cuir_message *cuir) |
5365 | { | 5347 | { |
5366 | struct dasd_eckd_private *private = device->private; | ||
5367 | struct dasd_conf_data *conf_data; | 5348 | struct dasd_conf_data *conf_data; |
5368 | int path, pos; | 5349 | int path, pos; |
5369 | 5350 | ||
5370 | if (cuir->record_selector == 0) | 5351 | if (cuir->record_selector == 0) |
5371 | goto out; | 5352 | goto out; |
5372 | for (path = 0x80, pos = 0; path; path >>= 1, pos++) { | 5353 | for (path = 0x80, pos = 0; path; path >>= 1, pos++) { |
5373 | conf_data = private->path_conf_data[pos]; | 5354 | conf_data = device->path[pos].conf_data; |
5374 | if (conf_data->gneq.record_selector == | 5355 | if (conf_data->gneq.record_selector == |
5375 | cuir->record_selector) | 5356 | cuir->record_selector) |
5376 | return conf_data; | 5357 | return conf_data; |
5377 | } | 5358 | } |
5378 | out: | 5359 | out: |
5379 | return private->path_conf_data[pathmask_to_pos(lpum)]; | 5360 | return device->path[pathmask_to_pos(lpum)].conf_data; |
5380 | } | 5361 | } |
5381 | 5362 | ||
5382 | /* | 5363 | /* |
@@ -5391,7 +5372,6 @@ out: | |||
5391 | static int dasd_eckd_cuir_scope(struct dasd_device *device, __u8 lpum, | 5372 | static int dasd_eckd_cuir_scope(struct dasd_device *device, __u8 lpum, |
5392 | struct dasd_cuir_message *cuir) | 5373 | struct dasd_cuir_message *cuir) |
5393 | { | 5374 | { |
5394 | struct dasd_eckd_private *private = device->private; | ||
5395 | struct dasd_conf_data *ref_conf_data; | 5375 | struct dasd_conf_data *ref_conf_data; |
5396 | unsigned long bitmask = 0, mask = 0; | 5376 | unsigned long bitmask = 0, mask = 0; |
5397 | struct dasd_conf_data *conf_data; | 5377 | struct dasd_conf_data *conf_data; |
@@ -5417,11 +5397,10 @@ static int dasd_eckd_cuir_scope(struct dasd_device *device, __u8 lpum, | |||
5417 | mask |= cuir->neq_map[1] << 8; | 5397 | mask |= cuir->neq_map[1] << 8; |
5418 | mask |= cuir->neq_map[0] << 16; | 5398 | mask |= cuir->neq_map[0] << 16; |
5419 | 5399 | ||
5420 | for (path = 0x80; path; path >>= 1) { | 5400 | for (path = 0; path < 8; path++) { |
5421 | /* initialise data per path */ | 5401 | /* initialise data per path */ |
5422 | bitmask = mask; | 5402 | bitmask = mask; |
5423 | pos = pathmask_to_pos(path); | 5403 | conf_data = device->path[path].conf_data; |
5424 | conf_data = private->path_conf_data[pos]; | ||
5425 | pos = 8 - ffs(cuir->ned_map); | 5404 | pos = 8 - ffs(cuir->ned_map); |
5426 | ned = (char *) &conf_data->neds[pos]; | 5405 | ned = (char *) &conf_data->neds[pos]; |
5427 | /* compare reference ned and per path ned */ | 5406 | /* compare reference ned and per path ned */ |
@@ -5442,7 +5421,7 @@ static int dasd_eckd_cuir_scope(struct dasd_device *device, __u8 lpum, | |||
5442 | continue; | 5421 | continue; |
5443 | /* device and path match the reference values | 5422 | /* device and path match the reference values |
5444 | add path to CUIR scope */ | 5423 | add path to CUIR scope */ |
5445 | tbcpm |= path; | 5424 | tbcpm |= 0x80 >> path; |
5446 | } | 5425 | } |
5447 | return tbcpm; | 5426 | return tbcpm; |
5448 | } | 5427 | } |
@@ -5479,16 +5458,16 @@ static int dasd_eckd_cuir_remove_path(struct dasd_device *device, __u8 lpum, | |||
5479 | 5458 | ||
5480 | tbcpm = dasd_eckd_cuir_scope(device, lpum, cuir); | 5459 | tbcpm = dasd_eckd_cuir_scope(device, lpum, cuir); |
5481 | /* nothing to do if path is not in use */ | 5460 | /* nothing to do if path is not in use */ |
5482 | if (!(device->path_data.opm & tbcpm)) | 5461 | if (!(dasd_path_get_opm(device) & tbcpm)) |
5483 | return 0; | 5462 | return 0; |
5484 | if (!(device->path_data.opm & ~tbcpm)) { | 5463 | if (!(dasd_path_get_opm(device) & ~tbcpm)) { |
5485 | /* no path would be left if the CUIR action is taken | 5464 | /* no path would be left if the CUIR action is taken |
5486 | return error */ | 5465 | return error */ |
5487 | return -EINVAL; | 5466 | return -EINVAL; |
5488 | } | 5467 | } |
5489 | /* remove device from operational path mask */ | 5468 | /* remove device from operational path mask */ |
5490 | device->path_data.opm &= ~tbcpm; | 5469 | dasd_path_remove_opm(device, tbcpm); |
5491 | device->path_data.cuirpm |= tbcpm; | 5470 | dasd_path_add_cuirpm(device, tbcpm); |
5492 | return tbcpm; | 5471 | return tbcpm; |
5493 | } | 5472 | } |
5494 | 5473 | ||
@@ -5581,8 +5560,8 @@ static int dasd_eckd_cuir_resume(struct dasd_device *device, __u8 lpum, | |||
5581 | alias_list) { | 5560 | alias_list) { |
5582 | tbcpm = dasd_eckd_cuir_scope(dev, lpum, cuir); | 5561 | tbcpm = dasd_eckd_cuir_scope(dev, lpum, cuir); |
5583 | paths |= tbcpm; | 5562 | paths |= tbcpm; |
5584 | if (!(dev->path_data.opm & tbcpm)) { | 5563 | if (!(dasd_path_get_opm(dev) & tbcpm)) { |
5585 | dev->path_data.tbvpm |= tbcpm; | 5564 | dasd_path_add_tbvpm(dev, tbcpm); |
5586 | dasd_schedule_device_bh(dev); | 5565 | dasd_schedule_device_bh(dev); |
5587 | } | 5566 | } |
5588 | } | 5567 | } |
@@ -5591,8 +5570,8 @@ static int dasd_eckd_cuir_resume(struct dasd_device *device, __u8 lpum, | |||
5591 | alias_list) { | 5570 | alias_list) { |
5592 | tbcpm = dasd_eckd_cuir_scope(dev, lpum, cuir); | 5571 | tbcpm = dasd_eckd_cuir_scope(dev, lpum, cuir); |
5593 | paths |= tbcpm; | 5572 | paths |= tbcpm; |
5594 | if (!(dev->path_data.opm & tbcpm)) { | 5573 | if (!(dasd_path_get_opm(dev) & tbcpm)) { |
5595 | dev->path_data.tbvpm |= tbcpm; | 5574 | dasd_path_add_tbvpm(dev, tbcpm); |
5596 | dasd_schedule_device_bh(dev); | 5575 | dasd_schedule_device_bh(dev); |
5597 | } | 5576 | } |
5598 | } | 5577 | } |
@@ -5605,8 +5584,8 @@ static int dasd_eckd_cuir_resume(struct dasd_device *device, __u8 lpum, | |||
5605 | alias_list) { | 5584 | alias_list) { |
5606 | tbcpm = dasd_eckd_cuir_scope(dev, lpum, cuir); | 5585 | tbcpm = dasd_eckd_cuir_scope(dev, lpum, cuir); |
5607 | paths |= tbcpm; | 5586 | paths |= tbcpm; |
5608 | if (!(dev->path_data.opm & tbcpm)) { | 5587 | if (!(dasd_path_get_opm(dev) & tbcpm)) { |
5609 | dev->path_data.tbvpm |= tbcpm; | 5588 | dasd_path_add_tbvpm(dev, tbcpm); |
5610 | dasd_schedule_device_bh(dev); | 5589 | dasd_schedule_device_bh(dev); |
5611 | } | 5590 | } |
5612 | } | 5591 | } |
@@ -5615,8 +5594,8 @@ static int dasd_eckd_cuir_resume(struct dasd_device *device, __u8 lpum, | |||
5615 | alias_list) { | 5594 | alias_list) { |
5616 | tbcpm = dasd_eckd_cuir_scope(dev, lpum, cuir); | 5595 | tbcpm = dasd_eckd_cuir_scope(dev, lpum, cuir); |
5617 | paths |= tbcpm; | 5596 | paths |= tbcpm; |
5618 | if (!(dev->path_data.opm & tbcpm)) { | 5597 | if (!(dasd_path_get_opm(dev) & tbcpm)) { |
5619 | dev->path_data.tbvpm |= tbcpm; | 5598 | dasd_path_add_tbvpm(dev, tbcpm); |
5620 | dasd_schedule_device_bh(dev); | 5599 | dasd_schedule_device_bh(dev); |
5621 | } | 5600 | } |
5622 | } | 5601 | } |
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index 59803626ea36..e491f4416e40 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h | |||
@@ -535,8 +535,7 @@ struct dasd_eckd_private { | |||
535 | struct dasd_eckd_characteristics rdc_data; | 535 | struct dasd_eckd_characteristics rdc_data; |
536 | u8 *conf_data; | 536 | u8 *conf_data; |
537 | int conf_len; | 537 | int conf_len; |
538 | /* per path configuration data */ | 538 | |
539 | struct dasd_conf_data *path_conf_data[8]; | ||
540 | /* pointers to specific parts in the conf_data */ | 539 | /* pointers to specific parts in the conf_data */ |
541 | struct dasd_ned *ned; | 540 | struct dasd_ned *ned; |
542 | struct dasd_sneq *sneq; | 541 | struct dasd_sneq *sneq; |
diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c index d138d0116734..113c1c1fa1af 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c | |||
@@ -96,7 +96,7 @@ dasd_default_erp_action(struct dasd_ccw_req *cqr) | |||
96 | "default ERP called (%i retries left)", | 96 | "default ERP called (%i retries left)", |
97 | cqr->retries); | 97 | cqr->retries); |
98 | if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) | 98 | if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) |
99 | cqr->lpm = device->path_data.opm; | 99 | cqr->lpm = dasd_path_get_opm(device); |
100 | cqr->status = DASD_CQR_FILLED; | 100 | cqr->status = DASD_CQR_FILLED; |
101 | } else { | 101 | } else { |
102 | pr_err("%s: default ERP has run out of retries and failed\n", | 102 | pr_err("%s: default ERP has run out of retries and failed\n", |
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index d7b5b550364b..462cab5d4302 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c | |||
@@ -168,7 +168,7 @@ dasd_fba_check_characteristics(struct dasd_device *device) | |||
168 | 168 | ||
169 | device->default_expires = DASD_EXPIRES; | 169 | device->default_expires = DASD_EXPIRES; |
170 | device->default_retries = FBA_DEFAULT_RETRIES; | 170 | device->default_retries = FBA_DEFAULT_RETRIES; |
171 | device->path_data.opm = LPM_ANYPATH; | 171 | dasd_path_set_opm(device, LPM_ANYPATH); |
172 | 172 | ||
173 | readonly = dasd_device_is_ro(device); | 173 | readonly = dasd_device_is_ro(device); |
174 | if (readonly) | 174 | if (readonly) |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 87ff6cef872f..d75f996884d9 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
@@ -55,6 +55,7 @@ | |||
55 | #include <asm/debug.h> | 55 | #include <asm/debug.h> |
56 | #include <asm/dasd.h> | 56 | #include <asm/dasd.h> |
57 | #include <asm/idals.h> | 57 | #include <asm/idals.h> |
58 | #include <linux/bitops.h> | ||
58 | 59 | ||
59 | /* DASD discipline magic */ | 60 | /* DASD discipline magic */ |
60 | #define DASD_ECKD_MAGIC 0xC5C3D2C4 | 61 | #define DASD_ECKD_MAGIC 0xC5C3D2C4 |
@@ -397,17 +398,23 @@ extern struct dasd_discipline *dasd_diag_discipline_pointer; | |||
397 | #define DASD_EER_STATECHANGE 3 | 398 | #define DASD_EER_STATECHANGE 3 |
398 | #define DASD_EER_PPRCSUSPEND 4 | 399 | #define DASD_EER_PPRCSUSPEND 4 |
399 | 400 | ||
401 | /* DASD path handling */ | ||
402 | |||
403 | #define DASD_PATH_OPERATIONAL 1 | ||
404 | #define DASD_PATH_TBV 2 | ||
405 | #define DASD_PATH_PP 3 | ||
406 | #define DASD_PATH_NPP 4 | ||
407 | #define DASD_PATH_MISCABLED 5 | ||
408 | #define DASD_PATH_NOHPF 6 | ||
409 | #define DASD_PATH_CUIR 7 | ||
410 | |||
411 | |||
400 | struct dasd_path { | 412 | struct dasd_path { |
401 | __u8 opm; | 413 | unsigned long flags; |
402 | __u8 tbvpm; | 414 | struct dasd_conf_data *conf_data; |
403 | __u8 ppm; | ||
404 | __u8 npm; | ||
405 | /* paths that are not used because of a special condition */ | ||
406 | __u8 cablepm; /* miss-cabled */ | ||
407 | __u8 hpfpm; /* the HPF requirements of the other paths are not met */ | ||
408 | __u8 cuirpm; /* CUIR varied offline */ | ||
409 | }; | 415 | }; |
410 | 416 | ||
417 | |||
411 | struct dasd_profile_info { | 418 | struct dasd_profile_info { |
412 | /* legacy part of profile data, as in dasd_profile_info_t */ | 419 | /* legacy part of profile data, as in dasd_profile_info_t */ |
413 | unsigned int dasd_io_reqs; /* number of requests processed */ | 420 | unsigned int dasd_io_reqs; /* number of requests processed */ |
@@ -458,7 +465,8 @@ struct dasd_device { | |||
458 | struct dasd_discipline *discipline; | 465 | struct dasd_discipline *discipline; |
459 | struct dasd_discipline *base_discipline; | 466 | struct dasd_discipline *base_discipline; |
460 | void *private; | 467 | void *private; |
461 | struct dasd_path path_data; | 468 | struct dasd_path path[8]; |
469 | __u8 opm; | ||
462 | 470 | ||
463 | /* Device state and target state. */ | 471 | /* Device state and target state. */ |
464 | int state, target; | 472 | int state, target; |
@@ -835,4 +843,359 @@ static inline int dasd_eer_enabled(struct dasd_device *device) | |||
835 | #define dasd_eer_enabled(d) (0) | 843 | #define dasd_eer_enabled(d) (0) |
836 | #endif /* CONFIG_DASD_ERR */ | 844 | #endif /* CONFIG_DASD_ERR */ |
837 | 845 | ||
846 | |||
847 | /* DASD path handling functions */ | ||
848 | |||
849 | /* | ||
850 | * helper functions to modify bit masks for a given channel path for a device | ||
851 | */ | ||
852 | static inline int dasd_path_is_operational(struct dasd_device *device, int chp) | ||
853 | { | ||
854 | return test_bit(DASD_PATH_OPERATIONAL, &device->path[chp].flags); | ||
855 | } | ||
856 | |||
857 | static inline int dasd_path_need_verify(struct dasd_device *device, int chp) | ||
858 | { | ||
859 | return test_bit(DASD_PATH_TBV, &device->path[chp].flags); | ||
860 | } | ||
861 | |||
862 | static inline void dasd_path_verify(struct dasd_device *device, int chp) | ||
863 | { | ||
864 | __set_bit(DASD_PATH_TBV, &device->path[chp].flags); | ||
865 | } | ||
866 | |||
867 | static inline void dasd_path_clear_verify(struct dasd_device *device, int chp) | ||
868 | { | ||
869 | __clear_bit(DASD_PATH_TBV, &device->path[chp].flags); | ||
870 | } | ||
871 | |||
872 | static inline void dasd_path_clear_all_verify(struct dasd_device *device) | ||
873 | { | ||
874 | int chp; | ||
875 | |||
876 | for (chp = 0; chp < 8; chp++) | ||
877 | dasd_path_clear_verify(device, chp); | ||
878 | } | ||
879 | |||
880 | static inline void dasd_path_operational(struct dasd_device *device, int chp) | ||
881 | { | ||
882 | __set_bit(DASD_PATH_OPERATIONAL, &device->path[chp].flags); | ||
883 | device->opm |= (0x80 >> chp); | ||
884 | } | ||
885 | |||
886 | static inline void dasd_path_nonpreferred(struct dasd_device *device, int chp) | ||
887 | { | ||
888 | __set_bit(DASD_PATH_NPP, &device->path[chp].flags); | ||
889 | } | ||
890 | |||
891 | static inline int dasd_path_is_nonpreferred(struct dasd_device *device, int chp) | ||
892 | { | ||
893 | return test_bit(DASD_PATH_NPP, &device->path[chp].flags); | ||
894 | } | ||
895 | |||
896 | static inline void dasd_path_clear_nonpreferred(struct dasd_device *device, | ||
897 | int chp) | ||
898 | { | ||
899 | __clear_bit(DASD_PATH_NPP, &device->path[chp].flags); | ||
900 | } | ||
901 | |||
902 | static inline void dasd_path_preferred(struct dasd_device *device, int chp) | ||
903 | { | ||
904 | __set_bit(DASD_PATH_PP, &device->path[chp].flags); | ||
905 | } | ||
906 | |||
907 | static inline int dasd_path_is_preferred(struct dasd_device *device, int chp) | ||
908 | { | ||
909 | return test_bit(DASD_PATH_PP, &device->path[chp].flags); | ||
910 | } | ||
911 | |||
912 | static inline void dasd_path_clear_preferred(struct dasd_device *device, | ||
913 | int chp) | ||
914 | { | ||
915 | __clear_bit(DASD_PATH_PP, &device->path[chp].flags); | ||
916 | } | ||
917 | |||
918 | static inline void dasd_path_clear_oper(struct dasd_device *device, int chp) | ||
919 | { | ||
920 | __clear_bit(DASD_PATH_OPERATIONAL, &device->path[chp].flags); | ||
921 | device->opm &= ~(0x80 >> chp); | ||
922 | } | ||
923 | |||
924 | static inline void dasd_path_clear_cable(struct dasd_device *device, int chp) | ||
925 | { | ||
926 | __clear_bit(DASD_PATH_MISCABLED, &device->path[chp].flags); | ||
927 | } | ||
928 | |||
929 | static inline void dasd_path_cuir(struct dasd_device *device, int chp) | ||
930 | { | ||
931 | __set_bit(DASD_PATH_CUIR, &device->path[chp].flags); | ||
932 | } | ||
933 | |||
934 | static inline int dasd_path_is_cuir(struct dasd_device *device, int chp) | ||
935 | { | ||
936 | return test_bit(DASD_PATH_CUIR, &device->path[chp].flags); | ||
937 | } | ||
938 | |||
939 | static inline void dasd_path_clear_cuir(struct dasd_device *device, int chp) | ||
940 | { | ||
941 | __clear_bit(DASD_PATH_CUIR, &device->path[chp].flags); | ||
942 | } | ||
943 | |||
944 | static inline void dasd_path_clear_nohpf(struct dasd_device *device, int chp) | ||
945 | { | ||
946 | __clear_bit(DASD_PATH_NOHPF, &device->path[chp].flags); | ||
947 | } | ||
948 | |||
949 | static inline void dasd_path_miscabled(struct dasd_device *device, int chp) | ||
950 | { | ||
951 | __set_bit(DASD_PATH_MISCABLED, &device->path[chp].flags); | ||
952 | } | ||
953 | |||
954 | static inline int dasd_path_is_miscabled(struct dasd_device *device, int chp) | ||
955 | { | ||
956 | return test_bit(DASD_PATH_MISCABLED, &device->path[chp].flags); | ||
957 | } | ||
958 | |||
959 | static inline void dasd_path_nohpf(struct dasd_device *device, int chp) | ||
960 | { | ||
961 | __set_bit(DASD_PATH_NOHPF, &device->path[chp].flags); | ||
962 | } | ||
963 | |||
964 | static inline int dasd_path_is_nohpf(struct dasd_device *device, int chp) | ||
965 | { | ||
966 | return test_bit(DASD_PATH_NOHPF, &device->path[chp].flags); | ||
967 | } | ||
968 | |||
969 | /* | ||
970 | * get functions for path masks | ||
971 | * will return a path masks for the given device | ||
972 | */ | ||
973 | |||
974 | static inline __u8 dasd_path_get_opm(struct dasd_device *device) | ||
975 | { | ||
976 | return device->opm; | ||
977 | } | ||
978 | |||
979 | static inline __u8 dasd_path_get_tbvpm(struct dasd_device *device) | ||
980 | { | ||
981 | int chp; | ||
982 | __u8 tbvpm = 0x00; | ||
983 | |||
984 | for (chp = 0; chp < 8; chp++) | ||
985 | if (dasd_path_need_verify(device, chp)) | ||
986 | tbvpm |= 0x80 >> chp; | ||
987 | return tbvpm; | ||
988 | } | ||
989 | |||
990 | static inline __u8 dasd_path_get_nppm(struct dasd_device *device) | ||
991 | { | ||
992 | int chp; | ||
993 | __u8 npm = 0x00; | ||
994 | |||
995 | for (chp = 0; chp < 8; chp++) { | ||
996 | if (dasd_path_is_nonpreferred(device, chp)) | ||
997 | npm |= 0x80 >> chp; | ||
998 | } | ||
999 | return npm; | ||
1000 | } | ||
1001 | |||
1002 | static inline __u8 dasd_path_get_ppm(struct dasd_device *device) | ||
1003 | { | ||
1004 | int chp; | ||
1005 | __u8 ppm = 0x00; | ||
1006 | |||
1007 | for (chp = 0; chp < 8; chp++) | ||
1008 | if (dasd_path_is_preferred(device, chp)) | ||
1009 | ppm |= 0x80 >> chp; | ||
1010 | return ppm; | ||
1011 | } | ||
1012 | |||
1013 | static inline __u8 dasd_path_get_cablepm(struct dasd_device *device) | ||
1014 | { | ||
1015 | int chp; | ||
1016 | __u8 cablepm = 0x00; | ||
1017 | |||
1018 | for (chp = 0; chp < 8; chp++) | ||
1019 | if (dasd_path_is_miscabled(device, chp)) | ||
1020 | cablepm |= 0x80 >> chp; | ||
1021 | return cablepm; | ||
1022 | } | ||
1023 | |||
1024 | static inline __u8 dasd_path_get_cuirpm(struct dasd_device *device) | ||
1025 | { | ||
1026 | int chp; | ||
1027 | __u8 cuirpm = 0x00; | ||
1028 | |||
1029 | for (chp = 0; chp < 8; chp++) | ||
1030 | if (dasd_path_is_cuir(device, chp)) | ||
1031 | cuirpm |= 0x80 >> chp; | ||
1032 | return cuirpm; | ||
1033 | } | ||
1034 | |||
1035 | static inline __u8 dasd_path_get_hpfpm(struct dasd_device *device) | ||
1036 | { | ||
1037 | int chp; | ||
1038 | __u8 hpfpm = 0x00; | ||
1039 | |||
1040 | for (chp = 0; chp < 8; chp++) | ||
1041 | if (dasd_path_is_nohpf(device, chp)) | ||
1042 | hpfpm |= 0x80 >> chp; | ||
1043 | return hpfpm; | ||
1044 | } | ||
1045 | |||
1046 | /* | ||
1047 | * add functions for path masks | ||
1048 | * the existing path mask will be extended by the given path mask | ||
1049 | */ | ||
1050 | static inline void dasd_path_add_tbvpm(struct dasd_device *device, __u8 pm) | ||
1051 | { | ||
1052 | int chp; | ||
1053 | |||
1054 | for (chp = 0; chp < 8; chp++) | ||
1055 | if (pm & (0x80 >> chp)) | ||
1056 | dasd_path_verify(device, chp); | ||
1057 | } | ||
1058 | |||
1059 | static inline void dasd_path_add_opm(struct dasd_device *device, __u8 pm) | ||
1060 | { | ||
1061 | int chp; | ||
1062 | |||
1063 | for (chp = 0; chp < 8; chp++) | ||
1064 | if (pm & (0x80 >> chp)) { | ||
1065 | dasd_path_operational(device, chp); | ||
1066 | /* | ||
1067 | * if the path is used | ||
1068 | * it should not be in one of the negative lists | ||
1069 | */ | ||
1070 | dasd_path_clear_nohpf(device, chp); | ||
1071 | dasd_path_clear_cuir(device, chp); | ||
1072 | dasd_path_clear_cable(device, chp); | ||
1073 | } | ||
1074 | } | ||
1075 | |||
1076 | static inline void dasd_path_add_cablepm(struct dasd_device *device, __u8 pm) | ||
1077 | { | ||
1078 | int chp; | ||
1079 | |||
1080 | for (chp = 0; chp < 8; chp++) | ||
1081 | if (pm & (0x80 >> chp)) | ||
1082 | dasd_path_miscabled(device, chp); | ||
1083 | } | ||
1084 | |||
1085 | static inline void dasd_path_add_cuirpm(struct dasd_device *device, __u8 pm) | ||
1086 | { | ||
1087 | int chp; | ||
1088 | |||
1089 | for (chp = 0; chp < 8; chp++) | ||
1090 | if (pm & (0x80 >> chp)) | ||
1091 | dasd_path_cuir(device, chp); | ||
1092 | } | ||
1093 | |||
1094 | static inline void dasd_path_add_nppm(struct dasd_device *device, __u8 pm) | ||
1095 | { | ||
1096 | int chp; | ||
1097 | |||
1098 | for (chp = 0; chp < 8; chp++) | ||
1099 | if (pm & (0x80 >> chp)) | ||
1100 | dasd_path_nonpreferred(device, chp); | ||
1101 | } | ||
1102 | |||
1103 | static inline void dasd_path_add_nohpfpm(struct dasd_device *device, __u8 pm) | ||
1104 | { | ||
1105 | int chp; | ||
1106 | |||
1107 | for (chp = 0; chp < 8; chp++) | ||
1108 | if (pm & (0x80 >> chp)) | ||
1109 | dasd_path_nohpf(device, chp); | ||
1110 | } | ||
1111 | |||
1112 | static inline void dasd_path_add_ppm(struct dasd_device *device, __u8 pm) | ||
1113 | { | ||
1114 | int chp; | ||
1115 | |||
1116 | for (chp = 0; chp < 8; chp++) | ||
1117 | if (pm & (0x80 >> chp)) | ||
1118 | dasd_path_preferred(device, chp); | ||
1119 | } | ||
1120 | |||
1121 | /* | ||
1122 | * set functions for path masks | ||
1123 | * the existing path mask will be replaced by the given path mask | ||
1124 | */ | ||
1125 | static inline void dasd_path_set_tbvpm(struct dasd_device *device, __u8 pm) | ||
1126 | { | ||
1127 | int chp; | ||
1128 | |||
1129 | for (chp = 0; chp < 8; chp++) | ||
1130 | if (pm & (0x80 >> chp)) | ||
1131 | dasd_path_verify(device, chp); | ||
1132 | else | ||
1133 | dasd_path_clear_verify(device, chp); | ||
1134 | } | ||
1135 | |||
1136 | static inline void dasd_path_set_opm(struct dasd_device *device, __u8 pm) | ||
1137 | { | ||
1138 | int chp; | ||
1139 | |||
1140 | for (chp = 0; chp < 8; chp++) { | ||
1141 | dasd_path_clear_oper(device, chp); | ||
1142 | if (pm & (0x80 >> chp)) { | ||
1143 | dasd_path_operational(device, chp); | ||
1144 | /* | ||
1145 | * if the path is used | ||
1146 | * it should not be in one of the negative lists | ||
1147 | */ | ||
1148 | dasd_path_clear_nohpf(device, chp); | ||
1149 | dasd_path_clear_cuir(device, chp); | ||
1150 | dasd_path_clear_cable(device, chp); | ||
1151 | } | ||
1152 | } | ||
1153 | } | ||
1154 | |||
1155 | /* | ||
1156 | * remove functions for path masks | ||
1157 | * the existing path mask will be cleared with the given path mask | ||
1158 | */ | ||
1159 | static inline void dasd_path_remove_opm(struct dasd_device *device, __u8 pm) | ||
1160 | { | ||
1161 | int chp; | ||
1162 | |||
1163 | for (chp = 0; chp < 8; chp++) { | ||
1164 | if (pm & (0x80 >> chp)) | ||
1165 | dasd_path_clear_oper(device, chp); | ||
1166 | } | ||
1167 | } | ||
1168 | |||
1169 | /* | ||
1170 | * add the newly available path to the to be verified pm and remove it from | ||
1171 | * normal operation until it is verified | ||
1172 | */ | ||
1173 | static inline void dasd_path_available(struct dasd_device *device, int chp) | ||
1174 | { | ||
1175 | dasd_path_clear_oper(device, chp); | ||
1176 | dasd_path_verify(device, chp); | ||
1177 | } | ||
1178 | |||
1179 | static inline void dasd_path_notoper(struct dasd_device *device, int chp) | ||
1180 | { | ||
1181 | dasd_path_clear_oper(device, chp); | ||
1182 | dasd_path_clear_preferred(device, chp); | ||
1183 | dasd_path_clear_nonpreferred(device, chp); | ||
1184 | } | ||
1185 | |||
1186 | /* | ||
1187 | * remove all paths from normal operation | ||
1188 | */ | ||
1189 | static inline void dasd_path_no_path(struct dasd_device *device) | ||
1190 | { | ||
1191 | int chp; | ||
1192 | |||
1193 | for (chp = 0; chp < 8; chp++) | ||
1194 | dasd_path_notoper(device, chp); | ||
1195 | |||
1196 | dasd_path_clear_all_verify(device); | ||
1197 | } | ||
1198 | |||
1199 | /* end - path handling */ | ||
1200 | |||
838 | #endif /* DASD_H */ | 1201 | #endif /* DASD_H */ |