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