aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/block')
-rw-r--r--drivers/s390/block/dasd.c33
-rw-r--r--drivers/s390/block/dasd_devmap.c24
-rw-r--r--drivers/s390/block/dasd_eckd.c372
-rw-r--r--drivers/s390/block/dasd_eckd.h63
-rw-r--r--drivers/s390/block/dasd_int.h10
5 files changed, 487 insertions, 15 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 5df05f26b7d9..329db997ee66 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -1660,6 +1660,14 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
1660 device->discipline->check_for_device_change(device, cqr, irb); 1660 device->discipline->check_for_device_change(device, cqr, irb);
1661 dasd_put_device(device); 1661 dasd_put_device(device);
1662 } 1662 }
1663
1664 /* check for for attention message */
1665 if (scsw_dstat(&irb->scsw) & DEV_STAT_ATTENTION) {
1666 device = dasd_device_from_cdev_locked(cdev);
1667 device->discipline->check_attention(device, irb->esw.esw1.lpum);
1668 dasd_put_device(device);
1669 }
1670
1663 if (!cqr) 1671 if (!cqr)
1664 return; 1672 return;
1665 1673
@@ -2261,8 +2269,8 @@ static inline int _wait_for_wakeup_queue(struct list_head *ccw_queue)
2261static int _dasd_sleep_on_queue(struct list_head *ccw_queue, int interruptible) 2269static int _dasd_sleep_on_queue(struct list_head *ccw_queue, int interruptible)
2262{ 2270{
2263 struct dasd_device *device; 2271 struct dasd_device *device;
2264 int rc;
2265 struct dasd_ccw_req *cqr, *n; 2272 struct dasd_ccw_req *cqr, *n;
2273 int rc;
2266 2274
2267retry: 2275retry:
2268 list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) { 2276 list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) {
@@ -2310,21 +2318,26 @@ retry:
2310 /* 2318 /*
2311 * for alias devices simplify error recovery and 2319 * for alias devices simplify error recovery and
2312 * return to upper layer 2320 * return to upper layer
2321 * do not skip ERP requests
2313 */ 2322 */
2314 if (cqr->startdev != cqr->basedev && 2323 if (cqr->startdev != cqr->basedev && !cqr->refers &&
2315 (cqr->status == DASD_CQR_TERMINATED || 2324 (cqr->status == DASD_CQR_TERMINATED ||
2316 cqr->status == DASD_CQR_NEED_ERP)) 2325 cqr->status == DASD_CQR_NEED_ERP))
2317 return -EAGAIN; 2326 return -EAGAIN;
2318 else { 2327
2319 /* normal recovery for basedev IO */ 2328 /* normal recovery for basedev IO */
2320 if (__dasd_sleep_on_erp(cqr)) { 2329 if (__dasd_sleep_on_erp(cqr)) {
2321 if (!cqr->status == DASD_CQR_TERMINATED && 2330 goto retry;
2322 !cqr->status == DASD_CQR_NEED_ERP) 2331 /* remember that ERP was needed */
2323 break; 2332 rc = 1;
2324 rc = 1; 2333 /* skip processing for active cqr */
2325 } 2334 if (cqr->status != DASD_CQR_TERMINATED &&
2335 cqr->status != DASD_CQR_NEED_ERP)
2336 break;
2326 } 2337 }
2327 } 2338 }
2339
2340 /* start ERP requests in upper loop */
2328 if (rc) 2341 if (rc)
2329 goto retry; 2342 goto retry;
2330 2343
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 14ba80bfa571..8286f742436b 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -1432,6 +1432,29 @@ static ssize_t dasd_reservation_state_store(struct device *dev,
1432static DEVICE_ATTR(last_known_reservation_state, 0644, 1432static DEVICE_ATTR(last_known_reservation_state, 0644,
1433 dasd_reservation_state_show, dasd_reservation_state_store); 1433 dasd_reservation_state_show, dasd_reservation_state_store);
1434 1434
1435static ssize_t dasd_pm_show(struct device *dev,
1436 struct device_attribute *attr, char *buf)
1437{
1438 struct dasd_device *device;
1439 u8 opm, nppm, cablepm, cuirpm, hpfpm;
1440
1441 device = dasd_device_from_cdev(to_ccwdev(dev));
1442 if (IS_ERR(device))
1443 return sprintf(buf, "0\n");
1444
1445 opm = device->path_data.opm;
1446 nppm = device->path_data.npm;
1447 cablepm = device->path_data.cablepm;
1448 cuirpm = device->path_data.cuirpm;
1449 hpfpm = device->path_data.hpfpm;
1450 dasd_put_device(device);
1451
1452 return sprintf(buf, "%02x %02x %02x %02x %02x\n", opm, nppm,
1453 cablepm, cuirpm, hpfpm);
1454}
1455
1456static DEVICE_ATTR(path_masks, 0444, dasd_pm_show, NULL);
1457
1435static struct attribute * dasd_attrs[] = { 1458static struct attribute * dasd_attrs[] = {
1436 &dev_attr_readonly.attr, 1459 &dev_attr_readonly.attr,
1437 &dev_attr_discipline.attr, 1460 &dev_attr_discipline.attr,
@@ -1450,6 +1473,7 @@ static struct attribute * dasd_attrs[] = {
1450 &dev_attr_reservation_policy.attr, 1473 &dev_attr_reservation_policy.attr,
1451 &dev_attr_last_known_reservation_state.attr, 1474 &dev_attr_last_known_reservation_state.attr,
1452 &dev_attr_safe_offline.attr, 1475 &dev_attr_safe_offline.attr,
1476 &dev_attr_path_masks.attr,
1453 NULL, 1477 NULL,
1454}; 1478};
1455 1479
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 51dea7baf02c..d47f5b99623a 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -29,6 +29,8 @@
29#include <asm/cio.h> 29#include <asm/cio.h>
30#include <asm/ccwdev.h> 30#include <asm/ccwdev.h>
31#include <asm/itcw.h> 31#include <asm/itcw.h>
32#include <asm/schid.h>
33#include <asm/chpid.h>
32 34
33#include "dasd_int.h" 35#include "dasd_int.h"
34#include "dasd_eckd.h" 36#include "dasd_eckd.h"
@@ -112,6 +114,12 @@ struct path_verification_work_data {
112static struct path_verification_work_data *path_verification_worker; 114static struct path_verification_work_data *path_verification_worker;
113static DEFINE_MUTEX(dasd_path_verification_mutex); 115static DEFINE_MUTEX(dasd_path_verification_mutex);
114 116
117struct check_attention_work_data {
118 struct work_struct worker;
119 struct dasd_device *device;
120 __u8 lpum;
121};
122
115/* initial attempt at a probe function. this can be simplified once 123/* initial attempt at a probe function. this can be simplified once
116 * the other detection code is gone */ 124 * the other detection code is gone */
117static int 125static int
@@ -1126,6 +1134,7 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
1126 "device %s instead of %s\n", lpm, 1134 "device %s instead of %s\n", lpm,
1127 print_path_uid, print_device_uid); 1135 print_path_uid, print_device_uid);
1128 path_err = -EINVAL; 1136 path_err = -EINVAL;
1137 path_data->cablepm |= lpm;
1129 continue; 1138 continue;
1130 } 1139 }
1131 1140
@@ -1141,6 +1150,13 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
1141 break; 1150 break;
1142 } 1151 }
1143 path_data->opm |= lpm; 1152 path_data->opm |= lpm;
1153 /*
1154 * if the path is used
1155 * it should not be in one of the negative lists
1156 */
1157 path_data->cablepm &= ~lpm;
1158 path_data->hpfpm &= ~lpm;
1159 path_data->cuirpm &= ~lpm;
1144 1160
1145 if (conf_data != private->conf_data) 1161 if (conf_data != private->conf_data)
1146 kfree(conf_data); 1162 kfree(conf_data);
@@ -1230,7 +1246,7 @@ static void do_path_verification_work(struct work_struct *work)
1230 struct dasd_eckd_private path_private; 1246 struct dasd_eckd_private path_private;
1231 struct dasd_uid *uid; 1247 struct dasd_uid *uid;
1232 __u8 path_rcd_buf[DASD_ECKD_RCD_DATA_SIZE]; 1248 __u8 path_rcd_buf[DASD_ECKD_RCD_DATA_SIZE];
1233 __u8 lpm, opm, npm, ppm, epm; 1249 __u8 lpm, opm, npm, ppm, epm, hpfpm, cablepm;
1234 unsigned long flags; 1250 unsigned long flags;
1235 char print_uid[60]; 1251 char print_uid[60];
1236 int rc; 1252 int rc;
@@ -1248,6 +1264,9 @@ static void do_path_verification_work(struct work_struct *work)
1248 npm = 0; 1264 npm = 0;
1249 ppm = 0; 1265 ppm = 0;
1250 epm = 0; 1266 epm = 0;
1267 hpfpm = 0;
1268 cablepm = 0;
1269
1251 for (lpm = 0x80; lpm; lpm >>= 1) { 1270 for (lpm = 0x80; lpm; lpm >>= 1) {
1252 if (!(lpm & data->tbvpm)) 1271 if (!(lpm & data->tbvpm))
1253 continue; 1272 continue;
@@ -1289,6 +1308,7 @@ static void do_path_verification_work(struct work_struct *work)
1289 opm &= ~lpm; 1308 opm &= ~lpm;
1290 npm &= ~lpm; 1309 npm &= ~lpm;
1291 ppm &= ~lpm; 1310 ppm &= ~lpm;
1311 hpfpm |= lpm;
1292 continue; 1312 continue;
1293 } 1313 }
1294 1314
@@ -1350,6 +1370,7 @@ static void do_path_verification_work(struct work_struct *work)
1350 opm &= ~lpm; 1370 opm &= ~lpm;
1351 npm &= ~lpm; 1371 npm &= ~lpm;
1352 ppm &= ~lpm; 1372 ppm &= ~lpm;
1373 cablepm |= lpm;
1353 continue; 1374 continue;
1354 } 1375 }
1355 } 1376 }
@@ -1364,12 +1385,21 @@ static void do_path_verification_work(struct work_struct *work)
1364 spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); 1385 spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
1365 if (!device->path_data.opm && opm) { 1386 if (!device->path_data.opm && opm) {
1366 device->path_data.opm = opm; 1387 device->path_data.opm = opm;
1388 device->path_data.cablepm &= ~opm;
1389 device->path_data.cuirpm &= ~opm;
1390 device->path_data.hpfpm &= ~opm;
1367 dasd_generic_path_operational(device); 1391 dasd_generic_path_operational(device);
1368 } else 1392 } else {
1369 device->path_data.opm |= opm; 1393 device->path_data.opm |= opm;
1394 device->path_data.cablepm &= ~opm;
1395 device->path_data.cuirpm &= ~opm;
1396 device->path_data.hpfpm &= ~opm;
1397 }
1370 device->path_data.npm |= npm; 1398 device->path_data.npm |= npm;
1371 device->path_data.ppm |= ppm; 1399 device->path_data.ppm |= ppm;
1372 device->path_data.tbvpm |= epm; 1400 device->path_data.tbvpm |= epm;
1401 device->path_data.cablepm |= cablepm;
1402 device->path_data.hpfpm |= hpfpm;
1373 spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); 1403 spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
1374 } 1404 }
1375 1405
@@ -4475,6 +4505,343 @@ out_err:
4475 return -1; 4505 return -1;
4476} 4506}
4477 4507
4508static int dasd_eckd_read_message_buffer(struct dasd_device *device,
4509 struct dasd_rssd_messages *messages,
4510 __u8 lpum)
4511{
4512 struct dasd_rssd_messages *message_buf;
4513 struct dasd_psf_prssd_data *prssdp;
4514 struct dasd_eckd_private *private;
4515 struct dasd_ccw_req *cqr;
4516 struct ccw1 *ccw;
4517 int rc;
4518
4519 private = (struct dasd_eckd_private *) device->private;
4520 cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */,
4521 (sizeof(struct dasd_psf_prssd_data) +
4522 sizeof(struct dasd_rssd_messages)),
4523 device);
4524 if (IS_ERR(cqr)) {
4525 DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
4526 "Could not allocate read message buffer request");
4527 return PTR_ERR(cqr);
4528 }
4529
4530 cqr->startdev = device;
4531 cqr->memdev = device;
4532 cqr->block = NULL;
4533 cqr->retries = 256;
4534 cqr->expires = 10 * HZ;
4535
4536 /* we need to check for messages on exactly this path */
4537 set_bit(DASD_CQR_VERIFY_PATH, &cqr->flags);
4538 cqr->lpm = lpum;
4539
4540 /* Prepare for Read Subsystem Data */
4541 prssdp = (struct dasd_psf_prssd_data *) cqr->data;
4542 memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));
4543 prssdp->order = PSF_ORDER_PRSSD;
4544 prssdp->suborder = 0x03; /* Message Buffer */
4545 /* all other bytes of prssdp must be zero */
4546
4547 ccw = cqr->cpaddr;
4548 ccw->cmd_code = DASD_ECKD_CCW_PSF;
4549 ccw->count = sizeof(struct dasd_psf_prssd_data);
4550 ccw->flags |= CCW_FLAG_CC;
4551 ccw->flags |= CCW_FLAG_SLI;
4552 ccw->cda = (__u32)(addr_t) prssdp;
4553
4554 /* Read Subsystem Data - message buffer */
4555 message_buf = (struct dasd_rssd_messages *) (prssdp + 1);
4556 memset(message_buf, 0, sizeof(struct dasd_rssd_messages));
4557
4558 ccw++;
4559 ccw->cmd_code = DASD_ECKD_CCW_RSSD;
4560 ccw->count = sizeof(struct dasd_rssd_messages);
4561 ccw->flags |= CCW_FLAG_SLI;
4562 ccw->cda = (__u32)(addr_t) message_buf;
4563
4564 cqr->buildclk = get_tod_clock();
4565 cqr->status = DASD_CQR_FILLED;
4566 rc = dasd_sleep_on_immediatly(cqr);
4567 if (rc == 0) {
4568 prssdp = (struct dasd_psf_prssd_data *) cqr->data;
4569 message_buf = (struct dasd_rssd_messages *)
4570 (prssdp + 1);
4571 memcpy(messages, message_buf,
4572 sizeof(struct dasd_rssd_messages));
4573 } else
4574 DBF_EVENT_DEVID(DBF_WARNING, device->cdev,
4575 "Reading messages failed with rc=%d\n"
4576 , rc);
4577 dasd_sfree_request(cqr, cqr->memdev);
4578 return rc;
4579}
4580
4581/*
4582 * Perform Subsystem Function - CUIR response
4583 */
4584static int
4585dasd_eckd_psf_cuir_response(struct dasd_device *device, int response,
4586 __u32 message_id,
4587 struct channel_path_desc *desc,
4588 struct subchannel_id sch_id)
4589{
4590 struct dasd_psf_cuir_response *psf_cuir;
4591 struct dasd_ccw_req *cqr;
4592 struct ccw1 *ccw;
4593 int rc;
4594
4595 cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ ,
4596 sizeof(struct dasd_psf_cuir_response),
4597 device);
4598
4599 if (IS_ERR(cqr)) {
4600 DBF_DEV_EVENT(DBF_WARNING, device, "%s",
4601 "Could not allocate PSF-CUIR request");
4602 return PTR_ERR(cqr);
4603 }
4604
4605 psf_cuir = (struct dasd_psf_cuir_response *)cqr->data;
4606 psf_cuir->order = PSF_ORDER_CUIR_RESPONSE;
4607 psf_cuir->cc = response;
4608 if (desc)
4609 psf_cuir->chpid = desc->chpid;
4610 psf_cuir->message_id = message_id;
4611 psf_cuir->cssid = sch_id.cssid;
4612 psf_cuir->ssid = sch_id.ssid;
4613
4614 ccw = cqr->cpaddr;
4615 ccw->cmd_code = DASD_ECKD_CCW_PSF;
4616 ccw->cda = (__u32)(addr_t)psf_cuir;
4617 ccw->count = sizeof(struct dasd_psf_cuir_response);
4618
4619 cqr->startdev = device;
4620 cqr->memdev = device;
4621 cqr->block = NULL;
4622 cqr->retries = 256;
4623 cqr->expires = 10*HZ;
4624 cqr->buildclk = get_tod_clock();
4625 cqr->status = DASD_CQR_FILLED;
4626
4627 rc = dasd_sleep_on(cqr);
4628
4629 dasd_sfree_request(cqr, cqr->memdev);
4630 return rc;
4631}
4632
4633static int dasd_eckd_cuir_change_state(struct dasd_device *device, __u8 lpum)
4634{
4635 unsigned long flags;
4636 __u8 tbcpm;
4637
4638 spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
4639 tbcpm = device->path_data.opm & ~lpum;
4640 if (tbcpm) {
4641 device->path_data.opm = tbcpm;
4642 device->path_data.cuirpm |= lpum;
4643 }
4644 spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
4645 return tbcpm ? 0 : PSF_CUIR_LAST_PATH;
4646}
4647
4648/*
4649 * walk through all devices and quiesce them
4650 * if it is the last path return error
4651 *
4652 * if only part of the devices are quiesced and an error
4653 * occurs no onlining necessary, the storage server will
4654 * notify the already set offline devices again
4655 */
4656static int dasd_eckd_cuir_quiesce(struct dasd_device *device, __u8 lpum,
4657 struct channel_path_desc *desc,
4658 struct subchannel_id sch_id)
4659{
4660 struct alias_pav_group *pavgroup, *tempgroup;
4661 struct dasd_eckd_private *private;
4662 struct dasd_device *dev, *n;
4663 int rc;
4664
4665 private = (struct dasd_eckd_private *) device->private;
4666 rc = 0;
4667
4668 /* active devices */
4669 list_for_each_entry_safe(dev, n,
4670 &private->lcu->active_devices,
4671 alias_list) {
4672 rc = dasd_eckd_cuir_change_state(dev, lpum);
4673 if (rc)
4674 goto out;
4675 }
4676
4677 /* inactive devices */
4678 list_for_each_entry_safe(dev, n,
4679 &private->lcu->inactive_devices,
4680 alias_list) {
4681 rc = dasd_eckd_cuir_change_state(dev, lpum);
4682 if (rc)
4683 goto out;
4684 }
4685
4686 /* devices in PAV groups */
4687 list_for_each_entry_safe(pavgroup, tempgroup,
4688 &private->lcu->grouplist, group) {
4689 list_for_each_entry_safe(dev, n, &pavgroup->baselist,
4690 alias_list) {
4691 rc = dasd_eckd_cuir_change_state(dev, lpum);
4692 if (rc)
4693 goto out;
4694 }
4695 list_for_each_entry_safe(dev, n, &pavgroup->aliaslist,
4696 alias_list) {
4697 rc = dasd_eckd_cuir_change_state(dev, lpum);
4698 if (rc)
4699 goto out;
4700 }
4701 }
4702
4703 pr_warn("Service on the storage server caused path %x.%02x to go offline",
4704 sch_id.cssid, desc ? desc->chpid : 0);
4705 rc = PSF_CUIR_COMPLETED;
4706out:
4707 return rc;
4708}
4709
4710static int dasd_eckd_cuir_resume(struct dasd_device *device, __u8 lpum,
4711 struct channel_path_desc *desc,
4712 struct subchannel_id sch_id)
4713{
4714 struct alias_pav_group *pavgroup, *tempgroup;
4715 struct dasd_eckd_private *private;
4716 struct dasd_device *dev, *n;
4717
4718 pr_info("Path %x.%02x is back online after service on the storage server",
4719 sch_id.cssid, desc ? desc->chpid : 0);
4720 private = (struct dasd_eckd_private *) device->private;
4721
4722 /*
4723 * the path may have been added through a generic path event before
4724 * only trigger path verification if the path is not already in use
4725 */
4726
4727 list_for_each_entry_safe(dev, n,
4728 &private->lcu->active_devices,
4729 alias_list) {
4730 if (!(dev->path_data.opm & lpum)) {
4731 dev->path_data.tbvpm |= lpum;
4732 dasd_schedule_device_bh(dev);
4733 }
4734 }
4735
4736 list_for_each_entry_safe(dev, n,
4737 &private->lcu->inactive_devices,
4738 alias_list) {
4739 if (!(dev->path_data.opm & lpum)) {
4740 dev->path_data.tbvpm |= lpum;
4741 dasd_schedule_device_bh(dev);
4742 }
4743 }
4744
4745 /* devices in PAV groups */
4746 list_for_each_entry_safe(pavgroup, tempgroup,
4747 &private->lcu->grouplist,
4748 group) {
4749 list_for_each_entry_safe(dev, n,
4750 &pavgroup->baselist,
4751 alias_list) {
4752 if (!(dev->path_data.opm & lpum)) {
4753 dev->path_data.tbvpm |= lpum;
4754 dasd_schedule_device_bh(dev);
4755 }
4756 }
4757 list_for_each_entry_safe(dev, n,
4758 &pavgroup->aliaslist,
4759 alias_list) {
4760 if (!(dev->path_data.opm & lpum)) {
4761 dev->path_data.tbvpm |= lpum;
4762 dasd_schedule_device_bh(dev);
4763 }
4764 }
4765 }
4766 return PSF_CUIR_COMPLETED;
4767}
4768
4769static void dasd_eckd_handle_cuir(struct dasd_device *device, void *messages,
4770 __u8 lpum)
4771{
4772 struct dasd_cuir_message *cuir = messages;
4773 struct channel_path_desc *desc;
4774 struct subchannel_id sch_id;
4775 int pos, response;
4776 ccw_device_get_schid(device->cdev, &sch_id);
4777
4778 /* get position of path in mask */
4779 pos = 8 - ffs(lpum);
4780 /* get channel path descriptor from this position */
4781 desc = ccw_device_get_chp_desc(device->cdev, pos);
4782
4783 if (cuir->code == CUIR_QUIESCE) {
4784 /* quiesce */
4785 response = dasd_eckd_cuir_quiesce(device, lpum, desc, sch_id);
4786 } else if (cuir->code == CUIR_RESUME) {
4787 /* resume */
4788 response = dasd_eckd_cuir_resume(device, lpum, desc, sch_id);
4789 } else
4790 response = PSF_CUIR_NOT_SUPPORTED;
4791
4792 dasd_eckd_psf_cuir_response(device, response, cuir->message_id,
4793 desc, sch_id);
4794
4795 /* free descriptor copy */
4796 kfree(desc);
4797}
4798
4799static void dasd_eckd_check_attention_work(struct work_struct *work)
4800{
4801 struct check_attention_work_data *data;
4802 struct dasd_rssd_messages *messages;
4803 struct dasd_device *device;
4804 int rc;
4805
4806 data = container_of(work, struct check_attention_work_data, worker);
4807 device = data->device;
4808
4809 messages = kzalloc(sizeof(*messages), GFP_KERNEL);
4810 if (!messages) {
4811 DBF_DEV_EVENT(DBF_WARNING, device, "%s",
4812 "Could not allocate attention message buffer");
4813 goto out;
4814 }
4815
4816 rc = dasd_eckd_read_message_buffer(device, messages, data->lpum);
4817 if (rc)
4818 goto out;
4819
4820 if (messages->length == ATTENTION_LENGTH_CUIR &&
4821 messages->format == ATTENTION_FORMAT_CUIR)
4822 dasd_eckd_handle_cuir(device, messages, data->lpum);
4823
4824out:
4825 dasd_put_device(device);
4826 kfree(messages);
4827 kfree(data);
4828}
4829
4830static int dasd_eckd_check_attention(struct dasd_device *device, __u8 lpum)
4831{
4832 struct check_attention_work_data *data;
4833
4834 data = kzalloc(sizeof(*data), GFP_ATOMIC);
4835 if (!data)
4836 return -ENOMEM;
4837 INIT_WORK(&data->worker, dasd_eckd_check_attention_work);
4838 dasd_get_device(device);
4839 data->device = device;
4840 data->lpum = lpum;
4841 schedule_work(&data->worker);
4842 return 0;
4843}
4844
4478static struct ccw_driver dasd_eckd_driver = { 4845static struct ccw_driver dasd_eckd_driver = {
4479 .driver = { 4846 .driver = {
4480 .name = "dasd-eckd", 4847 .name = "dasd-eckd",
@@ -4539,6 +4906,7 @@ static struct dasd_discipline dasd_eckd_discipline = {
4539 .reload = dasd_eckd_reload_device, 4906 .reload = dasd_eckd_reload_device,
4540 .get_uid = dasd_eckd_get_uid, 4907 .get_uid = dasd_eckd_get_uid,
4541 .kick_validate = dasd_eckd_kick_validate_server, 4908 .kick_validate = dasd_eckd_kick_validate_server,
4909 .check_attention = dasd_eckd_check_attention,
4542}; 4910};
4543 4911
4544static int __init 4912static int __init
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index 2555e494591f..ddab7df36e25 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -51,8 +51,35 @@
51/* 51/*
52 * Perform Subsystem Function / Sub-Orders 52 * Perform Subsystem Function / Sub-Orders
53 */ 53 */
54#define PSF_ORDER_PRSSD 0x18 54#define PSF_ORDER_PRSSD 0x18
55#define PSF_ORDER_SSC 0x1D 55#define PSF_ORDER_CUIR_RESPONSE 0x1A
56#define PSF_ORDER_SSC 0x1D
57
58/*
59 * CUIR response condition codes
60 */
61#define PSF_CUIR_INVALID 0x00
62#define PSF_CUIR_COMPLETED 0x01
63#define PSF_CUIR_NOT_SUPPORTED 0x02
64#define PSF_CUIR_ERROR_IN_REQ 0x03
65#define PSF_CUIR_DENIED 0x04
66#define PSF_CUIR_LAST_PATH 0x05
67#define PSF_CUIR_DEVICE_ONLINE 0x06
68#define PSF_CUIR_VARY_FAILURE 0x07
69#define PSF_CUIR_SOFTWARE_FAILURE 0x08
70#define PSF_CUIR_NOT_RECOGNIZED 0x09
71
72/*
73 * CUIR codes
74 */
75#define CUIR_QUIESCE 0x01
76#define CUIR_RESUME 0x02
77
78/*
79 * attention message definitions
80 */
81#define ATTENTION_LENGTH_CUIR 0x0e
82#define ATTENTION_FORMAT_CUIR 0x01
56 83
57/* 84/*
58 * Size that is reportet for large volumes in the old 16-bit no_cyl field 85 * Size that is reportet for large volumes in the old 16-bit no_cyl field
@@ -342,6 +369,38 @@ struct dasd_rssd_features {
342 char feature[256]; 369 char feature[256];
343} __attribute__((packed)); 370} __attribute__((packed));
344 371
372struct dasd_rssd_messages {
373 __u16 length;
374 __u8 format;
375 __u8 code;
376 __u32 message_id;
377 __u8 flags;
378 char messages[4087];
379} __packed;
380
381struct dasd_cuir_message {
382 __u16 length;
383 __u8 format;
384 __u8 code;
385 __u32 message_id;
386 __u8 flags;
387 __u8 neq_map[3];
388 __u8 ned_map;
389 __u8 record_selector;
390} __packed;
391
392struct dasd_psf_cuir_response {
393 __u8 order;
394 __u8 flags;
395 __u8 cc;
396 __u8 chpid;
397 __u16 device_nr;
398 __u16 reserved;
399 __u32 message_id;
400 __u64 system_id;
401 __u8 cssid;
402 __u8 ssid;
403} __packed;
345 404
346/* 405/*
347 * Perform Subsystem Function - Prepare for Read Subsystem Data 406 * Perform Subsystem Function - Prepare for Read Subsystem Data
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index c20170166909..8b5d4100abf7 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -357,6 +357,7 @@ struct dasd_discipline {
357 357
358 int (*get_uid) (struct dasd_device *, struct dasd_uid *); 358 int (*get_uid) (struct dasd_device *, struct dasd_uid *);
359 void (*kick_validate) (struct dasd_device *); 359 void (*kick_validate) (struct dasd_device *);
360 int (*check_attention)(struct dasd_device *, __u8);
360}; 361};
361 362
362extern struct dasd_discipline *dasd_diag_discipline_pointer; 363extern struct dasd_discipline *dasd_diag_discipline_pointer;
@@ -382,6 +383,10 @@ struct dasd_path {
382 __u8 tbvpm; 383 __u8 tbvpm;
383 __u8 ppm; 384 __u8 ppm;
384 __u8 npm; 385 __u8 npm;
386 /* paths that are not used because of a special condition */
387 __u8 cablepm; /* miss-cabled */
388 __u8 hpfpm; /* the HPF requirements of the other paths are not met */
389 __u8 cuirpm; /* CUIR varied offline */
385}; 390};
386 391
387struct dasd_profile_info { 392struct dasd_profile_info {
@@ -501,7 +506,10 @@ struct dasd_block {
501 struct dasd_profile profile; 506 struct dasd_profile profile;
502}; 507};
503 508
504 509struct dasd_attention_data {
510 struct dasd_device *device;
511 __u8 lpum;
512};
505 513
506/* reasons why device (ccw_device_start) was stopped */ 514/* reasons why device (ccw_device_start) was stopped */
507#define DASD_STOPPED_NOT_ACC 1 /* not accessible */ 515#define DASD_STOPPED_NOT_ACC 1 /* not accessible */