aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorStefan Haberland <stefan.haberland@de.ibm.com>2016-03-18 04:42:13 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2016-04-15 12:16:37 -0400
commit5a3b7b112884f80ff19b18028fabeb4f9c035518 (patch)
treeb1b743c481c829d26fdb97043f446f9f0d682b4f /drivers/s390
parent2fd92273646abad21766ddfbfa00b6f927362308 (diff)
s390/dasd: add query host access to volume support
With this feature, applications can query if a DASD volume is online to another operating system instances by checking the online status of all attached hosts from the storage server. Reviewed-by: Sebastian Ott <sebott@linux.vnet.ibm.com> Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Stefan Haberland <stefan.haberland@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/block/dasd.c56
-rw-r--r--drivers/s390/block/dasd_devmap.c27
-rw-r--r--drivers/s390/block/dasd_eckd.c164
-rw-r--r--drivers/s390/block/dasd_eckd.h33
-rw-r--r--drivers/s390/block/dasd_int.h3
5 files changed, 282 insertions, 1 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index c78db05e75b1..4adb6d14d562 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -75,6 +75,8 @@ static void dasd_block_timeout(unsigned long);
75static void __dasd_process_erp(struct dasd_device *, struct dasd_ccw_req *); 75static void __dasd_process_erp(struct dasd_device *, struct dasd_ccw_req *);
76static void dasd_profile_init(struct dasd_profile *, struct dentry *); 76static void dasd_profile_init(struct dasd_profile *, struct dentry *);
77static void dasd_profile_exit(struct dasd_profile *); 77static void dasd_profile_exit(struct dasd_profile *);
78static void dasd_hosts_init(struct dentry *, struct dasd_device *);
79static void dasd_hosts_exit(struct dasd_device *);
78 80
79/* 81/*
80 * SECTION: Operations on the device structure. 82 * SECTION: Operations on the device structure.
@@ -267,6 +269,7 @@ static int dasd_state_known_to_basic(struct dasd_device *device)
267 dasd_debugfs_setup(dev_name(&device->cdev->dev), 269 dasd_debugfs_setup(dev_name(&device->cdev->dev),
268 dasd_debugfs_root_entry); 270 dasd_debugfs_root_entry);
269 dasd_profile_init(&device->profile, device->debugfs_dentry); 271 dasd_profile_init(&device->profile, device->debugfs_dentry);
272 dasd_hosts_init(device->debugfs_dentry, device);
270 273
271 /* register 'device' debug area, used for all DBF_DEV_XXX calls */ 274 /* register 'device' debug area, used for all DBF_DEV_XXX calls */
272 device->debug_area = debug_register(dev_name(&device->cdev->dev), 4, 1, 275 device->debug_area = debug_register(dev_name(&device->cdev->dev), 4, 1,
@@ -304,6 +307,7 @@ static int dasd_state_basic_to_known(struct dasd_device *device)
304 return rc; 307 return rc;
305 dasd_device_clear_timer(device); 308 dasd_device_clear_timer(device);
306 dasd_profile_exit(&device->profile); 309 dasd_profile_exit(&device->profile);
310 dasd_hosts_exit(device);
307 debugfs_remove(device->debugfs_dentry); 311 debugfs_remove(device->debugfs_dentry);
308 DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device); 312 DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device);
309 if (device->debug_area != NULL) { 313 if (device->debug_area != NULL) {
@@ -1150,6 +1154,58 @@ int dasd_profile_on(struct dasd_profile *profile)
1150 1154
1151#endif /* CONFIG_DASD_PROFILE */ 1155#endif /* CONFIG_DASD_PROFILE */
1152 1156
1157static int dasd_hosts_show(struct seq_file *m, void *v)
1158{
1159 struct dasd_device *device;
1160 int rc = -EOPNOTSUPP;
1161
1162 device = m->private;
1163 dasd_get_device(device);
1164
1165 if (device->discipline->hosts_print)
1166 rc = device->discipline->hosts_print(device, m);
1167
1168 dasd_put_device(device);
1169 return rc;
1170}
1171
1172static int dasd_hosts_open(struct inode *inode, struct file *file)
1173{
1174 struct dasd_device *device = inode->i_private;
1175
1176 return single_open(file, dasd_hosts_show, device);
1177}
1178
1179static const struct file_operations dasd_hosts_fops = {
1180 .owner = THIS_MODULE,
1181 .open = dasd_hosts_open,
1182 .read = seq_read,
1183 .llseek = seq_lseek,
1184 .release = single_release,
1185};
1186
1187static void dasd_hosts_exit(struct dasd_device *device)
1188{
1189 debugfs_remove(device->hosts_dentry);
1190 device->hosts_dentry = NULL;
1191}
1192
1193static void dasd_hosts_init(struct dentry *base_dentry,
1194 struct dasd_device *device)
1195{
1196 struct dentry *pde;
1197 umode_t mode;
1198
1199 if (!base_dentry)
1200 return;
1201
1202 mode = S_IRUSR | S_IFREG;
1203 pde = debugfs_create_file("host_access_list", mode, base_dentry,
1204 device, &dasd_hosts_fops);
1205 if (pde && !IS_ERR(pde))
1206 device->hosts_dentry = pde;
1207}
1208
1153/* 1209/*
1154 * Allocate memory for a channel program with 'cplength' channel 1210 * Allocate memory for a channel program with 'cplength' channel
1155 * command words and 'datasize' additional space. There are two 1211 * command words and 'datasize' additional space. There are two
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 2f18f61092b5..3cdbce45e464 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -982,6 +982,32 @@ out:
982static DEVICE_ATTR(safe_offline, 0200, NULL, dasd_safe_offline_store); 982static DEVICE_ATTR(safe_offline, 0200, NULL, dasd_safe_offline_store);
983 983
984static ssize_t 984static ssize_t
985dasd_access_show(struct device *dev, struct device_attribute *attr,
986 char *buf)
987{
988 struct ccw_device *cdev = to_ccwdev(dev);
989 struct dasd_device *device;
990 int count;
991
992 device = dasd_device_from_cdev(cdev);
993 if (IS_ERR(device))
994 return PTR_ERR(device);
995
996 if (device->discipline->host_access_count)
997 count = device->discipline->host_access_count(device);
998 else
999 count = -EOPNOTSUPP;
1000
1001 dasd_put_device(device);
1002 if (count < 0)
1003 return count;
1004
1005 return sprintf(buf, "%d\n", count);
1006}
1007
1008static DEVICE_ATTR(host_access_count, 0444, dasd_access_show, NULL);
1009
1010static ssize_t
985dasd_discipline_show(struct device *dev, struct device_attribute *attr, 1011dasd_discipline_show(struct device *dev, struct device_attribute *attr,
986 char *buf) 1012 char *buf)
987{ 1013{
@@ -1471,6 +1497,7 @@ static struct attribute * dasd_attrs[] = {
1471 &dev_attr_reservation_policy.attr, 1497 &dev_attr_reservation_policy.attr,
1472 &dev_attr_last_known_reservation_state.attr, 1498 &dev_attr_last_known_reservation_state.attr,
1473 &dev_attr_safe_offline.attr, 1499 &dev_attr_safe_offline.attr,
1500 &dev_attr_host_access_count.attr,
1474 &dev_attr_path_masks.attr, 1501 &dev_attr_path_masks.attr,
1475 NULL, 1502 NULL,
1476}; 1503};
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index c1b4ae55e129..3b70d378d1c1 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -19,6 +19,7 @@
19#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/compat.h> 20#include <linux/compat.h>
21#include <linux/init.h> 21#include <linux/init.h>
22#include <linux/seq_file.h>
22 23
23#include <asm/css_chars.h> 24#include <asm/css_chars.h>
24#include <asm/debug.h> 25#include <asm/debug.h>
@@ -4627,6 +4628,167 @@ static int dasd_eckd_read_message_buffer(struct dasd_device *device,
4627 return rc; 4628 return rc;
4628} 4629}
4629 4630
4631static int dasd_eckd_query_host_access(struct dasd_device *device,
4632 struct dasd_psf_query_host_access *data)
4633{
4634 struct dasd_eckd_private *private = device->private;
4635 struct dasd_psf_query_host_access *host_access;
4636 struct dasd_psf_prssd_data *prssdp;
4637 struct dasd_ccw_req *cqr;
4638 struct ccw1 *ccw;
4639 int rc;
4640
4641 /* not available for HYPER PAV alias devices */
4642 if (!device->block && private->lcu->pav == HYPER_PAV)
4643 return -EOPNOTSUPP;
4644
4645 cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */,
4646 sizeof(struct dasd_psf_prssd_data) + 1,
4647 device);
4648 if (IS_ERR(cqr)) {
4649 DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
4650 "Could not allocate read message buffer request");
4651 return PTR_ERR(cqr);
4652 }
4653 host_access = kzalloc(sizeof(*host_access), GFP_KERNEL | GFP_DMA);
4654 if (!host_access) {
4655 dasd_sfree_request(cqr, device);
4656 DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
4657 "Could not allocate host_access buffer");
4658 return -ENOMEM;
4659 }
4660 cqr->startdev = device;
4661 cqr->memdev = device;
4662 cqr->block = NULL;
4663 cqr->retries = 256;
4664 cqr->expires = 10 * HZ;
4665
4666 /* Prepare for Read Subsystem Data */
4667 prssdp = (struct dasd_psf_prssd_data *) cqr->data;
4668 memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));
4669 prssdp->order = PSF_ORDER_PRSSD;
4670 prssdp->suborder = PSF_SUBORDER_QHA; /* query host access */
4671 /* LSS and Volume that will be queried */
4672 prssdp->lss = private->ned->ID;
4673 prssdp->volume = private->ned->unit_addr;
4674 /* all other bytes of prssdp must be zero */
4675
4676 ccw = cqr->cpaddr;
4677 ccw->cmd_code = DASD_ECKD_CCW_PSF;
4678 ccw->count = sizeof(struct dasd_psf_prssd_data);
4679 ccw->flags |= CCW_FLAG_CC;
4680 ccw->flags |= CCW_FLAG_SLI;
4681 ccw->cda = (__u32)(addr_t) prssdp;
4682
4683 /* Read Subsystem Data - query host access */
4684 ccw++;
4685 ccw->cmd_code = DASD_ECKD_CCW_RSSD;
4686 ccw->count = sizeof(struct dasd_psf_query_host_access);
4687 ccw->flags |= CCW_FLAG_SLI;
4688 ccw->cda = (__u32)(addr_t) host_access;
4689
4690 cqr->buildclk = get_tod_clock();
4691 cqr->status = DASD_CQR_FILLED;
4692 rc = dasd_sleep_on(cqr);
4693 if (rc == 0) {
4694 *data = *host_access;
4695 } else {
4696 DBF_EVENT_DEVID(DBF_WARNING, device->cdev,
4697 "Reading host access data failed with rc=%d\n",
4698 rc);
4699 rc = -EOPNOTSUPP;
4700 }
4701
4702 dasd_sfree_request(cqr, cqr->memdev);
4703 kfree(host_access);
4704 return rc;
4705}
4706/*
4707 * return number of grouped devices
4708 */
4709static int dasd_eckd_host_access_count(struct dasd_device *device)
4710{
4711 struct dasd_psf_query_host_access *access;
4712 struct dasd_ckd_path_group_entry *entry;
4713 struct dasd_ckd_host_information *info;
4714 int count = 0;
4715 int rc, i;
4716
4717 access = kzalloc(sizeof(*access), GFP_NOIO);
4718 if (!access) {
4719 DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
4720 "Could not allocate access buffer");
4721 return -ENOMEM;
4722 }
4723 rc = dasd_eckd_query_host_access(device, access);
4724 if (rc) {
4725 kfree(access);
4726 return rc;
4727 }
4728
4729 info = (struct dasd_ckd_host_information *)
4730 access->host_access_information;
4731 for (i = 0; i < info->entry_count; i++) {
4732 entry = (struct dasd_ckd_path_group_entry *)
4733 (info->entry + i * info->entry_size);
4734 if (entry->status_flags & DASD_ECKD_PG_GROUPED)
4735 count++;
4736 }
4737
4738 kfree(access);
4739 return count;
4740}
4741
4742/*
4743 * write host access information to a sequential file
4744 */
4745static int dasd_hosts_print(struct dasd_device *device, struct seq_file *m)
4746{
4747 struct dasd_psf_query_host_access *access;
4748 struct dasd_ckd_path_group_entry *entry;
4749 struct dasd_ckd_host_information *info;
4750 char sysplex[9] = "";
4751 int rc, i, j;
4752
4753 access = kzalloc(sizeof(*access), GFP_NOIO);
4754 if (!access) {
4755 DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
4756 "Could not allocate access buffer");
4757 return -ENOMEM;
4758 }
4759 rc = dasd_eckd_query_host_access(device, access);
4760 if (rc) {
4761 kfree(access);
4762 return rc;
4763 }
4764
4765 info = (struct dasd_ckd_host_information *)
4766 access->host_access_information;
4767 for (i = 0; i < info->entry_count; i++) {
4768 entry = (struct dasd_ckd_path_group_entry *)
4769 (info->entry + i * info->entry_size);
4770 /* PGID */
4771 seq_puts(m, "pgid ");
4772 for (j = 0; j < 11; j++)
4773 seq_printf(m, "%02x", entry->pgid[j]);
4774 seq_putc(m, '\n');
4775 /* FLAGS */
4776 seq_printf(m, "status_flags %02x\n", entry->status_flags);
4777 /* SYSPLEX NAME */
4778 memcpy(&sysplex, &entry->sysplex_name, sizeof(sysplex) - 1);
4779 EBCASC(sysplex, sizeof(sysplex));
4780 seq_printf(m, "sysplex_name %8s\n", sysplex);
4781 /* SUPPORTED CYLINDER */
4782 seq_printf(m, "supported_cylinder %d\n", entry->cylinder);
4783 /* TIMESTAMP */
4784 seq_printf(m, "timestamp %lu\n", (unsigned long)
4785 entry->timestamp);
4786 }
4787 kfree(access);
4788
4789 return 0;
4790}
4791
4630/* 4792/*
4631 * Perform Subsystem Function - CUIR response 4793 * Perform Subsystem Function - CUIR response
4632 */ 4794 */
@@ -5099,6 +5261,8 @@ static struct dasd_discipline dasd_eckd_discipline = {
5099 .get_uid = dasd_eckd_get_uid, 5261 .get_uid = dasd_eckd_get_uid,
5100 .kick_validate = dasd_eckd_kick_validate_server, 5262 .kick_validate = dasd_eckd_kick_validate_server,
5101 .check_attention = dasd_eckd_check_attention, 5263 .check_attention = dasd_eckd_check_attention,
5264 .host_access_count = dasd_eckd_host_access_count,
5265 .hosts_print = dasd_hosts_print,
5102}; 5266};
5103 5267
5104static int __init 5268static int __init
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index 6d9a6d3517cd..862ee4291abd 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -53,6 +53,7 @@
53 */ 53 */
54#define PSF_ORDER_PRSSD 0x18 54#define PSF_ORDER_PRSSD 0x18
55#define PSF_ORDER_CUIR_RESPONSE 0x1A 55#define PSF_ORDER_CUIR_RESPONSE 0x1A
56#define PSF_SUBORDER_QHA 0x1C
56#define PSF_ORDER_SSC 0x1D 57#define PSF_ORDER_SSC 0x1D
57 58
58/* 59/*
@@ -81,6 +82,8 @@
81#define ATTENTION_LENGTH_CUIR 0x0e 82#define ATTENTION_LENGTH_CUIR 0x0e
82#define ATTENTION_FORMAT_CUIR 0x01 83#define ATTENTION_FORMAT_CUIR 0x01
83 84
85#define DASD_ECKD_PG_GROUPED 0x10
86
84/* 87/*
85 * Size that is reportet for large volumes in the old 16-bit no_cyl field 88 * Size that is reportet for large volumes in the old 16-bit no_cyl field
86 */ 89 */
@@ -403,13 +406,41 @@ struct dasd_psf_cuir_response {
403 __u8 ssid; 406 __u8 ssid;
404} __packed; 407} __packed;
405 408
409struct dasd_ckd_path_group_entry {
410 __u8 status_flags;
411 __u8 pgid[11];
412 __u8 sysplex_name[8];
413 __u32 timestamp;
414 __u32 cylinder;
415 __u8 reserved[4];
416} __packed;
417
418struct dasd_ckd_host_information {
419 __u8 access_flags;
420 __u8 entry_size;
421 __u16 entry_count;
422 __u8 entry[16390];
423} __packed;
424
425struct dasd_psf_query_host_access {
426 __u8 access_flag;
427 __u8 version;
428 __u16 CKD_length;
429 __u16 SCSI_length;
430 __u8 unused[10];
431 __u8 host_access_information[16394];
432} __packed;
433
406/* 434/*
407 * Perform Subsystem Function - Prepare for Read Subsystem Data 435 * Perform Subsystem Function - Prepare for Read Subsystem Data
408 */ 436 */
409struct dasd_psf_prssd_data { 437struct dasd_psf_prssd_data {
410 unsigned char order; 438 unsigned char order;
411 unsigned char flags; 439 unsigned char flags;
412 unsigned char reserved[4]; 440 unsigned char reserved1;
441 unsigned char reserved2;
442 unsigned char lss;
443 unsigned char volume;
413 unsigned char suborder; 444 unsigned char suborder;
414 unsigned char varies[5]; 445 unsigned char varies[5];
415} __attribute__ ((packed)); 446} __attribute__ ((packed));
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 0f0add932e7a..6132733bcd95 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -365,6 +365,8 @@ struct dasd_discipline {
365 int (*get_uid) (struct dasd_device *, struct dasd_uid *); 365 int (*get_uid) (struct dasd_device *, struct dasd_uid *);
366 void (*kick_validate) (struct dasd_device *); 366 void (*kick_validate) (struct dasd_device *);
367 int (*check_attention)(struct dasd_device *, __u8); 367 int (*check_attention)(struct dasd_device *, __u8);
368 int (*host_access_count)(struct dasd_device *);
369 int (*hosts_print)(struct dasd_device *, struct seq_file *);
368}; 370};
369 371
370extern struct dasd_discipline *dasd_diag_discipline_pointer; 372extern struct dasd_discipline *dasd_diag_discipline_pointer;
@@ -487,6 +489,7 @@ struct dasd_device {
487 unsigned long blk_timeout; 489 unsigned long blk_timeout;
488 490
489 struct dentry *debugfs_dentry; 491 struct dentry *debugfs_dentry;
492 struct dentry *hosts_dentry;
490 struct dasd_profile profile; 493 struct dasd_profile profile;
491}; 494};
492 495