xref: /linux/drivers/s390/block/dasd_ioctl.c (revision a23e1966932464e1c5226cb9ac4ce1d5fc10ba22)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
4  *		    Horst Hummel <Horst.Hummel@de.ibm.com>
5  *		    Carsten Otte <Cotte@de.ibm.com>
6  *		    Martin Schwidefsky <schwidefsky@de.ibm.com>
7  * Bugreports.to..: <Linux390@de.ibm.com>
8  * Copyright IBM Corp. 1999, 2001
9  *
10  * i/o controls for the dasd driver.
11  */
12 
13 #include <linux/interrupt.h>
14 #include <linux/compat.h>
15 #include <linux/major.h>
16 #include <linux/fs.h>
17 #include <linux/blkpg.h>
18 #include <linux/slab.h>
19 #include <asm/ccwdev.h>
20 #include <asm/schid.h>
21 #include <asm/cmb.h>
22 #include <linux/uaccess.h>
23 #include <linux/dasd_mod.h>
24 
25 #include "dasd_int.h"
26 
27 static int
28 dasd_ioctl_api_version(void __user *argp)
29 {
30 	int ver = DASD_API_VERSION;
31 	return put_user(ver, (int __user *)argp);
32 }
33 
34 /*
35  * Enable device.
36  * used by dasdfmt after BIODASDDISABLE to retrigger blocksize detection
37  */
38 static int
39 dasd_ioctl_enable(struct block_device *bdev)
40 {
41 	struct dasd_device *base;
42 
43 	if (!capable(CAP_SYS_ADMIN))
44 		return -EACCES;
45 
46 	base = dasd_device_from_gendisk(bdev->bd_disk);
47 	if (!base)
48 		return -ENODEV;
49 
50 	dasd_enable_device(base);
51 	dasd_put_device(base);
52 	return 0;
53 }
54 
55 /*
56  * Disable device.
57  * Used by dasdfmt. Disable I/O operations but allow ioctls.
58  */
59 static int
60 dasd_ioctl_disable(struct block_device *bdev)
61 {
62 	struct dasd_device *base;
63 
64 	if (!capable(CAP_SYS_ADMIN))
65 		return -EACCES;
66 
67 	base = dasd_device_from_gendisk(bdev->bd_disk);
68 	if (!base)
69 		return -ENODEV;
70 	/*
71 	 * Man this is sick. We don't do a real disable but only downgrade
72 	 * the device to DASD_STATE_BASIC. The reason is that dasdfmt uses
73 	 * BIODASDDISABLE to disable accesses to the device via the block
74 	 * device layer but it still wants to do i/o on the device by
75 	 * using the BIODASDFMT ioctl. Therefore the correct state for the
76 	 * device is DASD_STATE_BASIC that allows to do basic i/o.
77 	 */
78 	dasd_set_target_state(base, DASD_STATE_BASIC);
79 	/*
80 	 * Set i_size to zero, since read, write, etc. check against this
81 	 * value.
82 	 */
83 	set_capacity(bdev->bd_disk, 0);
84 	dasd_put_device(base);
85 	return 0;
86 }
87 
88 /*
89  * Quiesce device.
90  */
91 static int dasd_ioctl_quiesce(struct dasd_block *block)
92 {
93 	unsigned long flags;
94 	struct dasd_device *base;
95 
96 	base = block->base;
97 	if (!capable (CAP_SYS_ADMIN))
98 		return -EACCES;
99 
100 	pr_info("%s: The DASD has been put in the quiesce "
101 		"state\n", dev_name(&base->cdev->dev));
102 	spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
103 	dasd_device_set_stop_bits(base, DASD_STOPPED_QUIESCE);
104 	spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
105 	return 0;
106 }
107 
108 
109 /*
110  * Resume device.
111  */
112 static int dasd_ioctl_resume(struct dasd_block *block)
113 {
114 	unsigned long flags;
115 	struct dasd_device *base;
116 
117 	base = block->base;
118 	if (!capable (CAP_SYS_ADMIN))
119 		return -EACCES;
120 
121 	pr_info("%s: I/O operations have been resumed "
122 		"on the DASD\n", dev_name(&base->cdev->dev));
123 	spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
124 	dasd_device_remove_stop_bits(base, DASD_STOPPED_QUIESCE);
125 	spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
126 
127 	dasd_schedule_block_bh(block);
128 	dasd_schedule_device_bh(base);
129 	return 0;
130 }
131 
132 /*
133  * Abort all failfast I/O on a device.
134  */
135 static int dasd_ioctl_abortio(struct dasd_block *block)
136 {
137 	unsigned long flags;
138 	struct dasd_device *base;
139 	struct dasd_ccw_req *cqr, *n;
140 
141 	base = block->base;
142 	if (!capable(CAP_SYS_ADMIN))
143 		return -EACCES;
144 
145 	if (test_and_set_bit(DASD_FLAG_ABORTALL, &base->flags))
146 		return 0;
147 	DBF_DEV_EVENT(DBF_NOTICE, base, "%s", "abortall flag set");
148 
149 	spin_lock_irqsave(&block->request_queue_lock, flags);
150 	spin_lock(&block->queue_lock);
151 	list_for_each_entry_safe(cqr, n, &block->ccw_queue, blocklist) {
152 		if (test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
153 		    cqr->callback_data &&
154 		    cqr->callback_data != DASD_SLEEPON_START_TAG &&
155 		    cqr->callback_data != DASD_SLEEPON_END_TAG) {
156 			spin_unlock(&block->queue_lock);
157 			blk_abort_request(cqr->callback_data);
158 			spin_lock(&block->queue_lock);
159 		}
160 	}
161 	spin_unlock(&block->queue_lock);
162 	spin_unlock_irqrestore(&block->request_queue_lock, flags);
163 
164 	dasd_schedule_block_bh(block);
165 	return 0;
166 }
167 
168 /*
169  * Allow I/O on a device
170  */
171 static int dasd_ioctl_allowio(struct dasd_block *block)
172 {
173 	struct dasd_device *base;
174 
175 	base = block->base;
176 	if (!capable(CAP_SYS_ADMIN))
177 		return -EACCES;
178 
179 	if (test_and_clear_bit(DASD_FLAG_ABORTALL, &base->flags))
180 		DBF_DEV_EVENT(DBF_NOTICE, base, "%s", "abortall flag unset");
181 
182 	return 0;
183 }
184 
185 /*
186  * performs formatting of _device_ according to _fdata_
187  * Note: The discipline's format_function is assumed to deliver formatting
188  * commands to format multiple units of the device. In terms of the ECKD
189  * devices this means CCWs are generated to format multiple tracks.
190  */
191 static int
192 dasd_format(struct dasd_block *block, struct format_data_t *fdata)
193 {
194 	struct dasd_device *base;
195 	int rc;
196 
197 	base = block->base;
198 	if (base->discipline->format_device == NULL)
199 		return -EPERM;
200 
201 	if (base->state != DASD_STATE_BASIC) {
202 		pr_warn("%s: The DASD cannot be formatted while it is enabled\n",
203 			dev_name(&base->cdev->dev));
204 		return -EBUSY;
205 	}
206 
207 	DBF_DEV_EVENT(DBF_NOTICE, base,
208 		      "formatting units %u to %u (%u B blocks) flags %u",
209 		      fdata->start_unit,
210 		      fdata->stop_unit, fdata->blksize, fdata->intensity);
211 
212 	/* Since dasdfmt keeps the device open after it was disabled,
213 	 * there still exists an inode for this device.
214 	 * We must update i_blkbits, otherwise we might get errors when
215 	 * enabling the device later.
216 	 */
217 	if (fdata->start_unit == 0) {
218 		block->gdp->part0->bd_inode->i_blkbits =
219 			blksize_bits(fdata->blksize);
220 	}
221 
222 	rc = base->discipline->format_device(base, fdata, 1);
223 	if (rc == -EAGAIN)
224 		rc = base->discipline->format_device(base, fdata, 0);
225 
226 	return rc;
227 }
228 
229 static int dasd_check_format(struct dasd_block *block,
230 			     struct format_check_t *cdata)
231 {
232 	struct dasd_device *base;
233 	int rc;
234 
235 	base = block->base;
236 	if (!base->discipline->check_device_format)
237 		return -ENOTTY;
238 
239 	rc = base->discipline->check_device_format(base, cdata, 1);
240 	if (rc == -EAGAIN)
241 		rc = base->discipline->check_device_format(base, cdata, 0);
242 
243 	return rc;
244 }
245 
246 /*
247  * Format device.
248  */
249 static int
250 dasd_ioctl_format(struct block_device *bdev, void __user *argp)
251 {
252 	struct dasd_device *base;
253 	struct format_data_t fdata;
254 	int rc;
255 
256 	if (!capable(CAP_SYS_ADMIN))
257 		return -EACCES;
258 	if (!argp)
259 		return -EINVAL;
260 	base = dasd_device_from_gendisk(bdev->bd_disk);
261 	if (!base)
262 		return -ENODEV;
263 	if (base->features & DASD_FEATURE_READONLY ||
264 	    test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) {
265 		dasd_put_device(base);
266 		return -EROFS;
267 	}
268 	if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) {
269 		dasd_put_device(base);
270 		return -EFAULT;
271 	}
272 	if (bdev_is_partition(bdev)) {
273 		pr_warn("%s: The specified DASD is a partition and cannot be formatted\n",
274 			dev_name(&base->cdev->dev));
275 		dasd_put_device(base);
276 		return -EINVAL;
277 	}
278 	rc = dasd_format(base->block, &fdata);
279 	dasd_put_device(base);
280 
281 	return rc;
282 }
283 
284 /*
285  * Check device format
286  */
287 static int dasd_ioctl_check_format(struct block_device *bdev, void __user *argp)
288 {
289 	struct format_check_t cdata;
290 	struct dasd_device *base;
291 	int rc = 0;
292 
293 	if (!argp)
294 		return -EINVAL;
295 
296 	base = dasd_device_from_gendisk(bdev->bd_disk);
297 	if (!base)
298 		return -ENODEV;
299 	if (bdev_is_partition(bdev)) {
300 		pr_warn("%s: The specified DASD is a partition and cannot be checked\n",
301 			dev_name(&base->cdev->dev));
302 		rc = -EINVAL;
303 		goto out_err;
304 	}
305 
306 	if (copy_from_user(&cdata, argp, sizeof(cdata))) {
307 		rc = -EFAULT;
308 		goto out_err;
309 	}
310 
311 	rc = dasd_check_format(base->block, &cdata);
312 	if (rc)
313 		goto out_err;
314 
315 	if (copy_to_user(argp, &cdata, sizeof(cdata)))
316 		rc = -EFAULT;
317 
318 out_err:
319 	dasd_put_device(base);
320 
321 	return rc;
322 }
323 
324 static int dasd_release_space(struct dasd_device *device,
325 			      struct format_data_t *rdata)
326 {
327 	if (!device->discipline->is_ese && !device->discipline->is_ese(device))
328 		return -ENOTSUPP;
329 	if (!device->discipline->release_space)
330 		return -ENOTSUPP;
331 
332 	return device->discipline->release_space(device, rdata);
333 }
334 
335 /*
336  * Release allocated space
337  */
338 static int dasd_ioctl_release_space(struct block_device *bdev, void __user *argp)
339 {
340 	struct format_data_t rdata;
341 	struct dasd_device *base;
342 	int rc = 0;
343 
344 	if (!capable(CAP_SYS_ADMIN))
345 		return -EACCES;
346 	if (!argp)
347 		return -EINVAL;
348 
349 	base = dasd_device_from_gendisk(bdev->bd_disk);
350 	if (!base)
351 		return -ENODEV;
352 	if (base->features & DASD_FEATURE_READONLY ||
353 	    test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) {
354 		rc = -EROFS;
355 		goto out_err;
356 	}
357 	if (bdev_is_partition(bdev)) {
358 		pr_warn("%s: The specified DASD is a partition and tracks cannot be released\n",
359 			dev_name(&base->cdev->dev));
360 		rc = -EINVAL;
361 		goto out_err;
362 	}
363 
364 	if (copy_from_user(&rdata, argp, sizeof(rdata))) {
365 		rc = -EFAULT;
366 		goto out_err;
367 	}
368 
369 	rc = dasd_release_space(base, &rdata);
370 
371 out_err:
372 	dasd_put_device(base);
373 
374 	return rc;
375 }
376 
377 /*
378  * Swap driver iternal copy relation.
379  */
380 static int
381 dasd_ioctl_copy_pair_swap(struct block_device *bdev, void __user *argp)
382 {
383 	struct dasd_copypair_swap_data_t data;
384 	struct dasd_device *device;
385 	int rc;
386 
387 	if (!capable(CAP_SYS_ADMIN))
388 		return -EACCES;
389 
390 	device = dasd_device_from_gendisk(bdev->bd_disk);
391 	if (!device)
392 		return -ENODEV;
393 
394 	if (copy_from_user(&data, argp, sizeof(struct dasd_copypair_swap_data_t))) {
395 		dasd_put_device(device);
396 		return -EFAULT;
397 	}
398 	if (memchr_inv(data.reserved, 0, sizeof(data.reserved))) {
399 		pr_warn("%s: Invalid swap data specified\n",
400 			dev_name(&device->cdev->dev));
401 		dasd_put_device(device);
402 		return DASD_COPYPAIRSWAP_INVALID;
403 	}
404 	if (bdev_is_partition(bdev)) {
405 		pr_warn("%s: The specified DASD is a partition and cannot be swapped\n",
406 			dev_name(&device->cdev->dev));
407 		dasd_put_device(device);
408 		return DASD_COPYPAIRSWAP_INVALID;
409 	}
410 	if (!device->copy) {
411 		pr_warn("%s: The specified DASD has no copy pair set up\n",
412 			dev_name(&device->cdev->dev));
413 		dasd_put_device(device);
414 		return -ENODEV;
415 	}
416 	if (!device->discipline->copy_pair_swap) {
417 		dasd_put_device(device);
418 		return -EOPNOTSUPP;
419 	}
420 	rc = device->discipline->copy_pair_swap(device, data.primary,
421 						data.secondary);
422 	dasd_put_device(device);
423 
424 	return rc;
425 }
426 
427 #ifdef CONFIG_DASD_PROFILE
428 /*
429  * Reset device profile information
430  */
431 static int dasd_ioctl_reset_profile(struct dasd_block *block)
432 {
433 	dasd_profile_reset(&block->profile);
434 	return 0;
435 }
436 
437 /*
438  * Return device profile information
439  */
440 static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
441 {
442 	struct dasd_profile_info_t *data;
443 	int rc = 0;
444 
445 	data = kmalloc(sizeof(*data), GFP_KERNEL);
446 	if (!data)
447 		return -ENOMEM;
448 
449 	spin_lock_bh(&block->profile.lock);
450 	if (block->profile.data) {
451 		data->dasd_io_reqs = block->profile.data->dasd_io_reqs;
452 		data->dasd_io_sects = block->profile.data->dasd_io_sects;
453 		memcpy(data->dasd_io_secs, block->profile.data->dasd_io_secs,
454 		       sizeof(data->dasd_io_secs));
455 		memcpy(data->dasd_io_times, block->profile.data->dasd_io_times,
456 		       sizeof(data->dasd_io_times));
457 		memcpy(data->dasd_io_timps, block->profile.data->dasd_io_timps,
458 		       sizeof(data->dasd_io_timps));
459 		memcpy(data->dasd_io_time1, block->profile.data->dasd_io_time1,
460 		       sizeof(data->dasd_io_time1));
461 		memcpy(data->dasd_io_time2, block->profile.data->dasd_io_time2,
462 		       sizeof(data->dasd_io_time2));
463 		memcpy(data->dasd_io_time2ps,
464 		       block->profile.data->dasd_io_time2ps,
465 		       sizeof(data->dasd_io_time2ps));
466 		memcpy(data->dasd_io_time3, block->profile.data->dasd_io_time3,
467 		       sizeof(data->dasd_io_time3));
468 		memcpy(data->dasd_io_nr_req,
469 		       block->profile.data->dasd_io_nr_req,
470 		       sizeof(data->dasd_io_nr_req));
471 		spin_unlock_bh(&block->profile.lock);
472 	} else {
473 		spin_unlock_bh(&block->profile.lock);
474 		rc = -EIO;
475 		goto out;
476 	}
477 	if (copy_to_user(argp, data, sizeof(*data)))
478 		rc = -EFAULT;
479 out:
480 	kfree(data);
481 	return rc;
482 }
483 #else
484 static int dasd_ioctl_reset_profile(struct dasd_block *block)
485 {
486 	return -ENOTTY;
487 }
488 
489 static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
490 {
491 	return -ENOTTY;
492 }
493 #endif
494 
495 /*
496  * Return dasd information. Used for BIODASDINFO and BIODASDINFO2.
497  */
498 static int __dasd_ioctl_information(struct dasd_block *block,
499 		struct dasd_information2_t *dasd_info)
500 {
501 	struct subchannel_id sch_id;
502 	struct ccw_dev_id dev_id;
503 	struct dasd_device *base;
504 	struct ccw_device *cdev;
505 	struct list_head *l;
506 	unsigned long flags;
507 	int rc;
508 
509 	base = block->base;
510 	if (!base->discipline || !base->discipline->fill_info)
511 		return -EINVAL;
512 
513 	rc = base->discipline->fill_info(base, dasd_info);
514 	if (rc)
515 		return rc;
516 
517 	cdev = base->cdev;
518 	ccw_device_get_id(cdev, &dev_id);
519 	ccw_device_get_schid(cdev, &sch_id);
520 
521 	dasd_info->devno = dev_id.devno;
522 	dasd_info->schid = sch_id.sch_no;
523 	dasd_info->cu_type = cdev->id.cu_type;
524 	dasd_info->cu_model = cdev->id.cu_model;
525 	dasd_info->dev_type = cdev->id.dev_type;
526 	dasd_info->dev_model = cdev->id.dev_model;
527 	dasd_info->status = base->state;
528 	/*
529 	 * The open_count is increased for every opener, that includes
530 	 * the blkdev_get in dasd_scan_partitions.
531 	 * This must be hidden from user-space.
532 	 */
533 	dasd_info->open_count = atomic_read(&block->open_count);
534 	if (!block->bdev_file)
535 		dasd_info->open_count++;
536 
537 	/*
538 	 * check if device is really formatted
539 	 * LDL / CDL was returned by 'fill_info'
540 	 */
541 	if ((base->state < DASD_STATE_READY) ||
542 	    (dasd_check_blocksize(block->bp_block)))
543 		dasd_info->format = DASD_FORMAT_NONE;
544 
545 	dasd_info->features |=
546 		((base->features & DASD_FEATURE_READONLY) != 0);
547 
548 	memcpy(dasd_info->type, base->discipline->name, 4);
549 
550 	spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
551 	list_for_each(l, &base->ccw_queue)
552 		dasd_info->chanq_len++;
553 	spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
554 	return 0;
555 }
556 
557 static int dasd_ioctl_information(struct dasd_block *block, void __user *argp,
558 		size_t copy_size)
559 {
560 	struct dasd_information2_t *dasd_info;
561 	int error;
562 
563 	dasd_info = kzalloc(sizeof(*dasd_info), GFP_KERNEL);
564 	if (!dasd_info)
565 		return -ENOMEM;
566 
567 	error = __dasd_ioctl_information(block, dasd_info);
568 	if (!error && copy_to_user(argp, dasd_info, copy_size))
569 		error = -EFAULT;
570 	kfree(dasd_info);
571 	return error;
572 }
573 
574 /*
575  * Set read only
576  */
577 int dasd_set_read_only(struct block_device *bdev, bool ro)
578 {
579 	struct dasd_device *base;
580 	int rc;
581 
582 	/* do not manipulate hardware state for partitions */
583 	if (bdev_is_partition(bdev))
584 		return 0;
585 
586 	base = dasd_device_from_gendisk(bdev->bd_disk);
587 	if (!base)
588 		return -ENODEV;
589 	if (!ro && test_bit(DASD_FLAG_DEVICE_RO, &base->flags))
590 		rc = -EROFS;
591 	else
592 		rc = dasd_set_feature(base->cdev, DASD_FEATURE_READONLY, ro);
593 	dasd_put_device(base);
594 	return rc;
595 }
596 
597 static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd,
598 				  struct cmbdata __user *argp)
599 {
600 	size_t size = _IOC_SIZE(cmd);
601 	struct cmbdata data;
602 	int ret;
603 
604 	ret = cmf_readall(block->base->cdev, &data);
605 	if (!ret && copy_to_user(argp, &data, min(size, sizeof(*argp))))
606 		return -EFAULT;
607 	return ret;
608 }
609 
610 int dasd_ioctl(struct block_device *bdev, blk_mode_t mode,
611 	       unsigned int cmd, unsigned long arg)
612 {
613 	struct dasd_block *block;
614 	struct dasd_device *base;
615 	void __user *argp;
616 	int rc;
617 
618 	if (is_compat_task())
619 		argp = compat_ptr(arg);
620 	else
621 		argp = (void __user *)arg;
622 
623 	if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg)
624 		return -EINVAL;
625 
626 	base = dasd_device_from_gendisk(bdev->bd_disk);
627 	if (!base)
628 		return -ENODEV;
629 	block = base->block;
630 	rc = 0;
631 	switch (cmd) {
632 	case BIODASDDISABLE:
633 		rc = dasd_ioctl_disable(bdev);
634 		break;
635 	case BIODASDENABLE:
636 		rc = dasd_ioctl_enable(bdev);
637 		break;
638 	case BIODASDQUIESCE:
639 		rc = dasd_ioctl_quiesce(block);
640 		break;
641 	case BIODASDRESUME:
642 		rc = dasd_ioctl_resume(block);
643 		break;
644 	case BIODASDABORTIO:
645 		rc = dasd_ioctl_abortio(block);
646 		break;
647 	case BIODASDALLOWIO:
648 		rc = dasd_ioctl_allowio(block);
649 		break;
650 	case BIODASDFMT:
651 		rc = dasd_ioctl_format(bdev, argp);
652 		break;
653 	case BIODASDCHECKFMT:
654 		rc = dasd_ioctl_check_format(bdev, argp);
655 		break;
656 	case BIODASDINFO:
657 		rc = dasd_ioctl_information(block, argp,
658 				sizeof(struct dasd_information_t));
659 		break;
660 	case BIODASDINFO2:
661 		rc = dasd_ioctl_information(block, argp,
662 				sizeof(struct dasd_information2_t));
663 		break;
664 	case BIODASDPRRD:
665 		rc = dasd_ioctl_read_profile(block, argp);
666 		break;
667 	case BIODASDPRRST:
668 		rc = dasd_ioctl_reset_profile(block);
669 		break;
670 	case DASDAPIVER:
671 		rc = dasd_ioctl_api_version(argp);
672 		break;
673 	case BIODASDCMFENABLE:
674 		rc = enable_cmf(base->cdev);
675 		break;
676 	case BIODASDCMFDISABLE:
677 		rc = disable_cmf(base->cdev);
678 		break;
679 	case BIODASDREADALLCMB:
680 		rc = dasd_ioctl_readall_cmb(block, cmd, argp);
681 		break;
682 	case BIODASDRAS:
683 		rc = dasd_ioctl_release_space(bdev, argp);
684 		break;
685 	case BIODASDCOPYPAIRSWAP:
686 		rc = dasd_ioctl_copy_pair_swap(bdev, argp);
687 		break;
688 	default:
689 		/* if the discipline has an ioctl method try it. */
690 		rc = -ENOTTY;
691 		if (base->discipline->ioctl)
692 			rc = base->discipline->ioctl(block, cmd, argp);
693 	}
694 	dasd_put_device(base);
695 	return rc;
696 }
697 
698 
699 /**
700  * dasd_biodasdinfo() - fill out the dasd information structure
701  * @disk: [in] pointer to gendisk structure that references a DASD
702  * @info: [out] pointer to the dasd_information2_t structure
703  *
704  * Provide access to DASD specific information.
705  * The gendisk structure is checked if it belongs to the DASD driver by
706  * comparing the gendisk->fops pointer.
707  * If it does not belong to the DASD driver -EINVAL is returned.
708  * Otherwise the provided dasd_information2_t structure is filled out.
709  *
710  * Returns:
711  *   %0 on success and a negative error value on failure.
712  */
713 int dasd_biodasdinfo(struct gendisk *disk, struct dasd_information2_t *info)
714 {
715 	struct dasd_device *base;
716 	int error;
717 
718 	if (disk->fops != &dasd_device_operations)
719 		return -EINVAL;
720 
721 	base = dasd_device_from_gendisk(disk);
722 	if (!base)
723 		return -ENODEV;
724 	error = __dasd_ioctl_information(base->block, info);
725 	dasd_put_device(base);
726 	return error;
727 }
728 /* export that symbol_get in partition detection is possible */
729 EXPORT_SYMBOL_GPL(dasd_biodasdinfo);
730