diff options
| author | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2008-10-10 16:39:38 -0400 |
|---|---|---|
| committer | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2008-10-10 16:39:38 -0400 |
| commit | 0127854d7c96612a454bed6de242e28f8021fa7f (patch) | |
| tree | 32aef08c4908b511c732d32f50a688ef14a4d0a2 /drivers | |
| parent | 49cac39e71bd6bbcf934c6ba837e21503902c088 (diff) | |
ide-floppy: move floppy ioctls handling to ide-floppy_ioctl.c
While at it:
- idefloppy_create_read_capacity_cmd() -> ide_floppy_create_read_capacity_cmd()
- idefloppy_create_mode_sense_cmd() -> ide_floppy_create_mode_sense_cmd()
- idefloppy_create_request_sense_cmd() -> ide_floppy_create_request_sense_cmd()
- idefloppy_create_format_unit_cmd() -> ide_floppy_create_format_unit_cmd()
- idefloppy_get_sfrp_bit() -> ide_floppy_get_sfrp_bit()
Acked-by: Borislav Petkov <petkovbb@gmail.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/ide/Makefile | 3 | ||||
| -rw-r--r-- | drivers/ide/ide-floppy.c | 296 | ||||
| -rw-r--r-- | drivers/ide/ide-floppy.h | 63 | ||||
| -rw-r--r-- | drivers/ide/ide-floppy_ioctl.c | 243 |
4 files changed, 317 insertions, 288 deletions
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index 76a30d763384..308b8a12f314 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile | |||
| @@ -37,11 +37,12 @@ obj-$(CONFIG_IDE_GENERIC) += ide-generic.o | |||
| 37 | obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o | 37 | obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o |
| 38 | 38 | ||
| 39 | ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o | 39 | ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o |
| 40 | ide-floppy_mod-y += ide-floppy.o ide-floppy_ioctl.o | ||
| 40 | 41 | ||
| 41 | obj-$(CONFIG_BLK_DEV_IDEDISK) += ide-disk.o | 42 | obj-$(CONFIG_BLK_DEV_IDEDISK) += ide-disk.o |
| 42 | obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd_mod.o | 43 | obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd_mod.o |
| 44 | obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy_mod.o | ||
| 43 | obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o | 45 | obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o |
| 44 | obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o | ||
| 45 | 46 | ||
| 46 | ifeq ($(CONFIG_BLK_DEV_IDECS), y) | 47 | ifeq ($(CONFIG_BLK_DEV_IDECS), y) |
| 47 | ide-cs-core-y += legacy/ide-cs.o | 48 | ide-cs-core-y += legacy/ide-cs.o |
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 78d92835a3c1..ca12a230d9a6 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c | |||
| @@ -46,6 +46,8 @@ | |||
| 46 | #include <linux/io.h> | 46 | #include <linux/io.h> |
| 47 | #include <asm/unaligned.h> | 47 | #include <asm/unaligned.h> |
| 48 | 48 | ||
| 49 | #include "ide-floppy.h" | ||
| 50 | |||
| 49 | /* define to see debug info */ | 51 | /* define to see debug info */ |
| 50 | #define IDEFLOPPY_DEBUG_LOG 0 | 52 | #define IDEFLOPPY_DEBUG_LOG 0 |
| 51 | 53 | ||
| @@ -75,61 +77,11 @@ | |||
| 75 | #define CAPACITY_CURRENT 0x02 | 77 | #define CAPACITY_CURRENT 0x02 |
| 76 | #define CAPACITY_NO_CARTRIDGE 0x03 | 78 | #define CAPACITY_NO_CARTRIDGE 0x03 |
| 77 | 79 | ||
| 78 | /* | ||
| 79 | * Most of our global data which we need to save even as we leave the driver | ||
| 80 | * due to an interrupt or a timer event is stored in a variable of type | ||
| 81 | * idefloppy_floppy_t, defined below. | ||
| 82 | */ | ||
| 83 | typedef struct ide_floppy_obj { | ||
| 84 | ide_drive_t *drive; | ||
| 85 | ide_driver_t *driver; | ||
| 86 | struct gendisk *disk; | ||
| 87 | struct kref kref; | ||
| 88 | unsigned int openers; /* protected by BKL for now */ | ||
| 89 | |||
| 90 | /* Current packet command */ | ||
| 91 | struct ide_atapi_pc *pc; | ||
| 92 | /* Last failed packet command */ | ||
| 93 | struct ide_atapi_pc *failed_pc; | ||
| 94 | /* used for blk_{fs,pc}_request() requests */ | ||
| 95 | struct ide_atapi_pc queued_pc; | ||
| 96 | |||
| 97 | struct ide_atapi_pc request_sense_pc; | ||
| 98 | struct request request_sense_rq; | ||
| 99 | |||
| 100 | /* Last error information */ | ||
| 101 | u8 sense_key, asc, ascq; | ||
| 102 | /* delay this long before sending packet command */ | ||
| 103 | u8 ticks; | ||
| 104 | int progress_indication; | ||
| 105 | |||
| 106 | /* Device information */ | ||
| 107 | /* Current format */ | ||
| 108 | int blocks, block_size, bs_factor; | ||
| 109 | /* Last format capacity descriptor */ | ||
| 110 | u8 cap_desc[8]; | ||
| 111 | /* Copy of the flexible disk page */ | ||
| 112 | u8 flexible_disk_page[32]; | ||
| 113 | } idefloppy_floppy_t; | ||
| 114 | |||
| 115 | #define IDEFLOPPY_TICKS_DELAY HZ/20 /* default delay for ZIP 100 (50ms) */ | 80 | #define IDEFLOPPY_TICKS_DELAY HZ/20 /* default delay for ZIP 100 (50ms) */ |
| 116 | 81 | ||
| 117 | /* IOCTLs used in low-level formatting. */ | ||
| 118 | #define IDEFLOPPY_IOCTL_FORMAT_SUPPORTED 0x4600 | ||
| 119 | #define IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY 0x4601 | ||
| 120 | #define IDEFLOPPY_IOCTL_FORMAT_START 0x4602 | ||
| 121 | #define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS 0x4603 | ||
| 122 | |||
| 123 | /* Error code returned in rq->errors to the higher part of the driver. */ | 82 | /* Error code returned in rq->errors to the higher part of the driver. */ |
| 124 | #define IDEFLOPPY_ERROR_GENERAL 101 | 83 | #define IDEFLOPPY_ERROR_GENERAL 101 |
| 125 | 84 | ||
| 126 | /* | ||
| 127 | * Pages of the SELECT SENSE / MODE SENSE packet commands. | ||
| 128 | * See SFF-8070i spec. | ||
| 129 | */ | ||
| 130 | #define IDEFLOPPY_CAPABILITIES_PAGE 0x1b | ||
| 131 | #define IDEFLOPPY_FLEXIBLE_DISK_PAGE 0x05 | ||
| 132 | |||
| 133 | static DEFINE_MUTEX(idefloppy_ref_mutex); | 85 | static DEFINE_MUTEX(idefloppy_ref_mutex); |
| 134 | 86 | ||
| 135 | #define to_ide_floppy(obj) container_of(obj, struct ide_floppy_obj, kref) | 87 | #define to_ide_floppy(obj) container_of(obj, struct ide_floppy_obj, kref) |
| @@ -245,7 +197,7 @@ static void ide_floppy_callback(ide_drive_t *drive) | |||
| 245 | idefloppy_end_request(drive, uptodate, 0); | 197 | idefloppy_end_request(drive, uptodate, 0); |
| 246 | } | 198 | } |
| 247 | 199 | ||
| 248 | static void idefloppy_create_request_sense_cmd(struct ide_atapi_pc *pc) | 200 | void ide_floppy_create_request_sense_cmd(struct ide_atapi_pc *pc) |
| 249 | { | 201 | { |
| 250 | ide_init_pc(pc); | 202 | ide_init_pc(pc); |
| 251 | pc->c[0] = GPCMD_REQUEST_SENSE; | 203 | pc->c[0] = GPCMD_REQUEST_SENSE; |
| @@ -264,7 +216,7 @@ static void idefloppy_retry_pc(ide_drive_t *drive) | |||
| 264 | struct ide_atapi_pc *pc = &floppy->request_sense_pc; | 216 | struct ide_atapi_pc *pc = &floppy->request_sense_pc; |
| 265 | 217 | ||
| 266 | (void)ide_read_error(drive); | 218 | (void)ide_read_error(drive); |
| 267 | idefloppy_create_request_sense_cmd(pc); | 219 | ide_floppy_create_request_sense_cmd(pc); |
| 268 | ide_queue_pc_head(drive, floppy->disk, pc, rq); | 220 | ide_queue_pc_head(drive, floppy->disk, pc, rq); |
| 269 | } | 221 | } |
| 270 | 222 | ||
| @@ -382,7 +334,7 @@ static void idefloppy_create_prevent_cmd(struct ide_atapi_pc *pc, int prevent) | |||
| 382 | pc->c[4] = prevent; | 334 | pc->c[4] = prevent; |
| 383 | } | 335 | } |
| 384 | 336 | ||
| 385 | static void idefloppy_create_read_capacity_cmd(struct ide_atapi_pc *pc) | 337 | void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *pc) |
| 386 | { | 338 | { |
| 387 | ide_init_pc(pc); | 339 | ide_init_pc(pc); |
| 388 | pc->c[0] = GPCMD_READ_FORMAT_CAPACITIES; | 340 | pc->c[0] = GPCMD_READ_FORMAT_CAPACITIES; |
| @@ -391,30 +343,8 @@ static void idefloppy_create_read_capacity_cmd(struct ide_atapi_pc *pc) | |||
| 391 | pc->req_xfer = 255; | 343 | pc->req_xfer = 255; |
| 392 | } | 344 | } |
| 393 | 345 | ||
| 394 | static void idefloppy_create_format_unit_cmd(struct ide_atapi_pc *pc, int b, | ||
| 395 | int l, int flags) | ||
| 396 | { | ||
| 397 | ide_init_pc(pc); | ||
| 398 | pc->c[0] = GPCMD_FORMAT_UNIT; | ||
| 399 | pc->c[1] = 0x17; | ||
| 400 | |||
| 401 | memset(pc->buf, 0, 12); | ||
| 402 | pc->buf[1] = 0xA2; | ||
| 403 | /* Default format list header, u8 1: FOV/DCRT/IMM bits set */ | ||
| 404 | |||
| 405 | if (flags & 1) /* Verify bit on... */ | ||
| 406 | pc->buf[1] ^= 0x20; /* ... turn off DCRT bit */ | ||
| 407 | pc->buf[3] = 8; | ||
| 408 | |||
| 409 | put_unaligned(cpu_to_be32(b), (unsigned int *)(&pc->buf[4])); | ||
| 410 | put_unaligned(cpu_to_be32(l), (unsigned int *)(&pc->buf[8])); | ||
| 411 | pc->buf_size = 12; | ||
| 412 | pc->flags |= PC_FLAG_WRITING; | ||
| 413 | } | ||
| 414 | |||
| 415 | /* A mode sense command is used to "sense" floppy parameters. */ | 346 | /* A mode sense command is used to "sense" floppy parameters. */ |
| 416 | static void idefloppy_create_mode_sense_cmd(struct ide_atapi_pc *pc, | 347 | void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code) |
| 417 | u8 page_code) | ||
| 418 | { | 348 | { |
| 419 | u16 length = 8; /* sizeof(Mode Parameter Header) = 8 Bytes */ | 349 | u16 length = 8; /* sizeof(Mode Parameter Header) = 8 Bytes */ |
| 420 | 350 | ||
| @@ -563,7 +493,7 @@ static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive) | |||
| 563 | u16 transfer_rate, sector_size, cyls, rpm; | 493 | u16 transfer_rate, sector_size, cyls, rpm; |
| 564 | u8 heads, sectors; | 494 | u8 heads, sectors; |
| 565 | 495 | ||
| 566 | idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE); | 496 | ide_floppy_create_mode_sense_cmd(&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE); |
| 567 | 497 | ||
| 568 | if (ide_queue_pc_tail(drive, disk, &pc)) { | 498 | if (ide_queue_pc_tail(drive, disk, &pc)) { |
| 569 | printk(KERN_ERR "ide-floppy: Can't get flexible disk page" | 499 | printk(KERN_ERR "ide-floppy: Can't get flexible disk page" |
| @@ -611,25 +541,6 @@ static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive) | |||
| 611 | return 0; | 541 | return 0; |
| 612 | } | 542 | } |
| 613 | 543 | ||
| 614 | static int idefloppy_get_sfrp_bit(ide_drive_t *drive) | ||
| 615 | { | ||
| 616 | idefloppy_floppy_t *floppy = drive->driver_data; | ||
| 617 | struct ide_atapi_pc pc; | ||
| 618 | |||
| 619 | drive->atapi_flags &= ~IDE_AFLAG_SRFP; | ||
| 620 | |||
| 621 | idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_CAPABILITIES_PAGE); | ||
| 622 | pc.flags |= PC_FLAG_SUPPRESS_ERROR; | ||
| 623 | |||
| 624 | if (ide_queue_pc_tail(drive, floppy->disk, &pc)) | ||
| 625 | return 1; | ||
| 626 | |||
| 627 | if (pc.buf[8 + 2] & 0x40) | ||
| 628 | drive->atapi_flags |= IDE_AFLAG_SRFP; | ||
| 629 | |||
| 630 | return 0; | ||
| 631 | } | ||
| 632 | |||
| 633 | /* | 544 | /* |
| 634 | * Determine if a media is present in the floppy drive, and if so, its LBA | 545 | * Determine if a media is present in the floppy drive, and if so, its LBA |
| 635 | * capacity. | 546 | * capacity. |
| @@ -649,7 +560,7 @@ static int ide_floppy_get_capacity(ide_drive_t *drive) | |||
| 649 | floppy->bs_factor = 1; | 560 | floppy->bs_factor = 1; |
| 650 | set_capacity(floppy->disk, 0); | 561 | set_capacity(floppy->disk, 0); |
| 651 | 562 | ||
| 652 | idefloppy_create_read_capacity_cmd(&pc); | 563 | ide_floppy_create_read_capacity_cmd(&pc); |
| 653 | if (ide_queue_pc_tail(drive, disk, &pc)) { | 564 | if (ide_queue_pc_tail(drive, disk, &pc)) { |
| 654 | printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n"); | 565 | printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n"); |
| 655 | return 1; | 566 | return 1; |
| @@ -730,129 +641,6 @@ static int ide_floppy_get_capacity(ide_drive_t *drive) | |||
| 730 | return rc; | 641 | return rc; |
| 731 | } | 642 | } |
| 732 | 643 | ||
| 733 | /* | ||
| 734 | * Obtain the list of formattable capacities. | ||
| 735 | * Very similar to ide_floppy_get_capacity, except that we push the capacity | ||
| 736 | * descriptors to userland, instead of our own structures. | ||
| 737 | * | ||
| 738 | * Userland gives us the following structure: | ||
| 739 | * | ||
| 740 | * struct idefloppy_format_capacities { | ||
| 741 | * int nformats; | ||
| 742 | * struct { | ||
| 743 | * int nblocks; | ||
| 744 | * int blocksize; | ||
| 745 | * } formats[]; | ||
| 746 | * }; | ||
| 747 | * | ||
| 748 | * userland initializes nformats to the number of allocated formats[] records. | ||
| 749 | * On exit we set nformats to the number of records we've actually initialized. | ||
| 750 | */ | ||
| 751 | |||
| 752 | static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg) | ||
| 753 | { | ||
| 754 | struct ide_floppy_obj *floppy = drive->driver_data; | ||
| 755 | struct ide_atapi_pc pc; | ||
| 756 | u8 header_len, desc_cnt; | ||
| 757 | int i, blocks, length, u_array_size, u_index; | ||
| 758 | int __user *argp; | ||
| 759 | |||
| 760 | if (get_user(u_array_size, arg)) | ||
| 761 | return -EFAULT; | ||
| 762 | |||
| 763 | if (u_array_size <= 0) | ||
| 764 | return -EINVAL; | ||
| 765 | |||
| 766 | idefloppy_create_read_capacity_cmd(&pc); | ||
| 767 | if (ide_queue_pc_tail(drive, floppy->disk, &pc)) { | ||
| 768 | printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n"); | ||
| 769 | return -EIO; | ||
| 770 | } | ||
| 771 | |||
| 772 | header_len = pc.buf[3]; | ||
| 773 | desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */ | ||
| 774 | |||
| 775 | u_index = 0; | ||
| 776 | argp = arg + 1; | ||
| 777 | |||
| 778 | /* | ||
| 779 | * We always skip the first capacity descriptor. That's the current | ||
| 780 | * capacity. We are interested in the remaining descriptors, the | ||
| 781 | * formattable capacities. | ||
| 782 | */ | ||
| 783 | for (i = 1; i < desc_cnt; i++) { | ||
| 784 | unsigned int desc_start = 4 + i*8; | ||
| 785 | |||
| 786 | if (u_index >= u_array_size) | ||
| 787 | break; /* User-supplied buffer too small */ | ||
| 788 | |||
| 789 | blocks = be32_to_cpup((__be32 *)&pc.buf[desc_start]); | ||
| 790 | length = be16_to_cpup((__be16 *)&pc.buf[desc_start + 6]); | ||
| 791 | |||
| 792 | if (put_user(blocks, argp)) | ||
| 793 | return -EFAULT; | ||
| 794 | |||
| 795 | ++argp; | ||
| 796 | |||
| 797 | if (put_user(length, argp)) | ||
| 798 | return -EFAULT; | ||
| 799 | |||
| 800 | ++argp; | ||
| 801 | |||
| 802 | ++u_index; | ||
| 803 | } | ||
| 804 | |||
| 805 | if (put_user(u_index, arg)) | ||
| 806 | return -EFAULT; | ||
| 807 | |||
| 808 | return 0; | ||
| 809 | } | ||
| 810 | |||
| 811 | /* | ||
| 812 | * Get ATAPI_FORMAT_UNIT progress indication. | ||
| 813 | * | ||
| 814 | * Userland gives a pointer to an int. The int is set to a progress | ||
| 815 | * indicator 0-65536, with 65536=100%. | ||
| 816 | * | ||
| 817 | * If the drive does not support format progress indication, we just check | ||
| 818 | * the dsc bit, and return either 0 or 65536. | ||
| 819 | */ | ||
| 820 | |||
| 821 | static int ide_floppy_get_format_progress(ide_drive_t *drive, int __user *arg) | ||
| 822 | { | ||
| 823 | idefloppy_floppy_t *floppy = drive->driver_data; | ||
| 824 | struct ide_atapi_pc pc; | ||
| 825 | int progress_indication = 0x10000; | ||
| 826 | |||
| 827 | if (drive->atapi_flags & IDE_AFLAG_SRFP) { | ||
| 828 | idefloppy_create_request_sense_cmd(&pc); | ||
| 829 | if (ide_queue_pc_tail(drive, floppy->disk, &pc)) | ||
| 830 | return -EIO; | ||
| 831 | |||
| 832 | if (floppy->sense_key == 2 && | ||
| 833 | floppy->asc == 4 && | ||
| 834 | floppy->ascq == 4) | ||
| 835 | progress_indication = floppy->progress_indication; | ||
| 836 | |||
| 837 | /* Else assume format_unit has finished, and we're at 0x10000 */ | ||
| 838 | } else { | ||
| 839 | ide_hwif_t *hwif = drive->hwif; | ||
| 840 | unsigned long flags; | ||
| 841 | u8 stat; | ||
| 842 | |||
| 843 | local_irq_save(flags); | ||
| 844 | stat = hwif->tp_ops->read_status(hwif); | ||
| 845 | local_irq_restore(flags); | ||
| 846 | |||
| 847 | progress_indication = ((stat & ATA_DSC) == 0) ? 0 : 0x10000; | ||
| 848 | } | ||
| 849 | |||
| 850 | if (put_user(progress_indication, arg)) | ||
| 851 | return -EFAULT; | ||
| 852 | |||
| 853 | return 0; | ||
| 854 | } | ||
| 855 | |||
| 856 | static sector_t idefloppy_capacity(ide_drive_t *drive) | 644 | static sector_t idefloppy_capacity(ide_drive_t *drive) |
| 857 | { | 645 | { |
| 858 | idefloppy_floppy_t *floppy = drive->driver_data; | 646 | idefloppy_floppy_t *floppy = drive->driver_data; |
| @@ -1118,73 +906,6 @@ static int ide_floppy_lockdoor(ide_drive_t *drive, struct ide_atapi_pc *pc, | |||
| 1118 | return 0; | 906 | return 0; |
| 1119 | } | 907 | } |
| 1120 | 908 | ||
| 1121 | static int ide_floppy_format_unit(ide_drive_t *drive, int __user *arg) | ||
| 1122 | { | ||
| 1123 | idefloppy_floppy_t *floppy = drive->driver_data; | ||
| 1124 | struct ide_atapi_pc pc; | ||
| 1125 | int blocks, length, flags, err = 0; | ||
| 1126 | |||
| 1127 | if (floppy->openers > 1) { | ||
| 1128 | /* Don't format if someone is using the disk */ | ||
| 1129 | drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS; | ||
| 1130 | return -EBUSY; | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | drive->atapi_flags |= IDE_AFLAG_FORMAT_IN_PROGRESS; | ||
| 1134 | |||
| 1135 | /* | ||
| 1136 | * Send ATAPI_FORMAT_UNIT to the drive. | ||
| 1137 | * | ||
| 1138 | * Userland gives us the following structure: | ||
| 1139 | * | ||
| 1140 | * struct idefloppy_format_command { | ||
| 1141 | * int nblocks; | ||
| 1142 | * int blocksize; | ||
| 1143 | * int flags; | ||
| 1144 | * } ; | ||
| 1145 | * | ||
| 1146 | * flags is a bitmask, currently, the only defined flag is: | ||
| 1147 | * | ||
| 1148 | * 0x01 - verify media after format. | ||
| 1149 | */ | ||
| 1150 | if (get_user(blocks, arg) || | ||
| 1151 | get_user(length, arg+1) || | ||
| 1152 | get_user(flags, arg+2)) { | ||
| 1153 | err = -EFAULT; | ||
| 1154 | goto out; | ||
| 1155 | } | ||
| 1156 | |||
| 1157 | (void) idefloppy_get_sfrp_bit(drive); | ||
| 1158 | idefloppy_create_format_unit_cmd(&pc, blocks, length, flags); | ||
| 1159 | |||
| 1160 | if (ide_queue_pc_tail(drive, floppy->disk, &pc)) | ||
| 1161 | err = -EIO; | ||
| 1162 | |||
| 1163 | out: | ||
| 1164 | if (err) | ||
| 1165 | drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS; | ||
| 1166 | return err; | ||
| 1167 | } | ||
| 1168 | |||
| 1169 | static int ide_floppy_format_ioctl(ide_drive_t *drive, struct file *file, | ||
| 1170 | unsigned int cmd, void __user *argp) | ||
| 1171 | { | ||
| 1172 | switch (cmd) { | ||
| 1173 | case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED: | ||
| 1174 | return 0; | ||
| 1175 | case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY: | ||
| 1176 | return ide_floppy_get_format_capacities(drive, argp); | ||
| 1177 | case IDEFLOPPY_IOCTL_FORMAT_START: | ||
| 1178 | if (!(file->f_mode & 2)) | ||
| 1179 | return -EPERM; | ||
| 1180 | return ide_floppy_format_unit(drive, (int __user *)argp); | ||
| 1181 | case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS: | ||
| 1182 | return ide_floppy_get_format_progress(drive, argp); | ||
| 1183 | default: | ||
| 1184 | return -ENOTTY; | ||
| 1185 | } | ||
| 1186 | } | ||
| 1187 | |||
| 1188 | static int idefloppy_ioctl(struct inode *inode, struct file *file, | 909 | static int idefloppy_ioctl(struct inode *inode, struct file *file, |
| 1189 | unsigned int cmd, unsigned long arg) | 910 | unsigned int cmd, unsigned long arg) |
| 1190 | { | 911 | { |
| @@ -1316,6 +1037,7 @@ static int __init idefloppy_init(void) | |||
| 1316 | } | 1037 | } |
| 1317 | 1038 | ||
| 1318 | MODULE_ALIAS("ide:*m-floppy*"); | 1039 | MODULE_ALIAS("ide:*m-floppy*"); |
| 1040 | MODULE_ALIAS("ide-floppy"); | ||
| 1319 | module_init(idefloppy_init); | 1041 | module_init(idefloppy_init); |
| 1320 | module_exit(idefloppy_exit); | 1042 | module_exit(idefloppy_exit); |
| 1321 | MODULE_LICENSE("GPL"); | 1043 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/ide/ide-floppy.h b/drivers/ide/ide-floppy.h new file mode 100644 index 000000000000..ecadc2bc322d --- /dev/null +++ b/drivers/ide/ide-floppy.h | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | #ifndef __IDE_FLOPPY_H | ||
| 2 | #define __IDE_FLOPPY_H | ||
| 3 | |||
| 4 | /* | ||
| 5 | * Most of our global data which we need to save even as we leave the driver | ||
| 6 | * due to an interrupt or a timer event is stored in a variable of type | ||
| 7 | * idefloppy_floppy_t, defined below. | ||
| 8 | */ | ||
| 9 | typedef struct ide_floppy_obj { | ||
| 10 | ide_drive_t *drive; | ||
| 11 | ide_driver_t *driver; | ||
| 12 | struct gendisk *disk; | ||
| 13 | struct kref kref; | ||
| 14 | unsigned int openers; /* protected by BKL for now */ | ||
| 15 | |||
| 16 | /* Current packet command */ | ||
| 17 | struct ide_atapi_pc *pc; | ||
| 18 | /* Last failed packet command */ | ||
| 19 | struct ide_atapi_pc *failed_pc; | ||
| 20 | /* used for blk_{fs,pc}_request() requests */ | ||
| 21 | struct ide_atapi_pc queued_pc; | ||
| 22 | |||
| 23 | struct ide_atapi_pc request_sense_pc; | ||
| 24 | struct request request_sense_rq; | ||
| 25 | |||
| 26 | /* Last error information */ | ||
| 27 | u8 sense_key, asc, ascq; | ||
| 28 | /* delay this long before sending packet command */ | ||
| 29 | u8 ticks; | ||
| 30 | int progress_indication; | ||
| 31 | |||
| 32 | /* Device information */ | ||
| 33 | /* Current format */ | ||
| 34 | int blocks, block_size, bs_factor; | ||
| 35 | /* Last format capacity descriptor */ | ||
| 36 | u8 cap_desc[8]; | ||
| 37 | /* Copy of the flexible disk page */ | ||
| 38 | u8 flexible_disk_page[32]; | ||
| 39 | } idefloppy_floppy_t; | ||
| 40 | |||
| 41 | /* | ||
| 42 | * Pages of the SELECT SENSE / MODE SENSE packet commands. | ||
| 43 | * See SFF-8070i spec. | ||
| 44 | */ | ||
| 45 | #define IDEFLOPPY_CAPABILITIES_PAGE 0x1b | ||
| 46 | #define IDEFLOPPY_FLEXIBLE_DISK_PAGE 0x05 | ||
| 47 | |||
| 48 | /* IOCTLs used in low-level formatting. */ | ||
| 49 | #define IDEFLOPPY_IOCTL_FORMAT_SUPPORTED 0x4600 | ||
| 50 | #define IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY 0x4601 | ||
| 51 | #define IDEFLOPPY_IOCTL_FORMAT_START 0x4602 | ||
| 52 | #define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS 0x4603 | ||
| 53 | |||
| 54 | /* ide-floppy.c */ | ||
| 55 | void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *, u8); | ||
| 56 | void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *); | ||
| 57 | void ide_floppy_create_request_sense_cmd(struct ide_atapi_pc *); | ||
| 58 | |||
| 59 | /* ide-floppy_ioctl.c */ | ||
| 60 | int ide_floppy_format_ioctl(ide_drive_t *, struct file *, unsigned int, | ||
| 61 | void __user *); | ||
| 62 | |||
| 63 | #endif /*__IDE_FLOPPY_H */ | ||
diff --git a/drivers/ide/ide-floppy_ioctl.c b/drivers/ide/ide-floppy_ioctl.c new file mode 100644 index 000000000000..5ffc4512d14b --- /dev/null +++ b/drivers/ide/ide-floppy_ioctl.c | |||
| @@ -0,0 +1,243 @@ | |||
| 1 | /* | ||
| 2 | * ide-floppy IOCTLs handling. | ||
| 3 | */ | ||
| 4 | |||
| 5 | #include <linux/kernel.h> | ||
| 6 | #include <linux/ide.h> | ||
| 7 | #include <linux/cdrom.h> | ||
| 8 | |||
| 9 | #include <asm/unaligned.h> | ||
| 10 | |||
| 11 | #include <scsi/scsi_ioctl.h> | ||
| 12 | |||
| 13 | #include "ide-floppy.h" | ||
| 14 | |||
| 15 | /* | ||
| 16 | * Obtain the list of formattable capacities. | ||
| 17 | * Very similar to ide_floppy_get_capacity, except that we push the capacity | ||
| 18 | * descriptors to userland, instead of our own structures. | ||
| 19 | * | ||
| 20 | * Userland gives us the following structure: | ||
| 21 | * | ||
| 22 | * struct idefloppy_format_capacities { | ||
| 23 | * int nformats; | ||
| 24 | * struct { | ||
| 25 | * int nblocks; | ||
| 26 | * int blocksize; | ||
| 27 | * } formats[]; | ||
| 28 | * }; | ||
| 29 | * | ||
| 30 | * userland initializes nformats to the number of allocated formats[] records. | ||
| 31 | * On exit we set nformats to the number of records we've actually initialized. | ||
| 32 | */ | ||
| 33 | |||
| 34 | static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg) | ||
| 35 | { | ||
| 36 | struct ide_floppy_obj *floppy = drive->driver_data; | ||
| 37 | struct ide_atapi_pc pc; | ||
| 38 | u8 header_len, desc_cnt; | ||
| 39 | int i, blocks, length, u_array_size, u_index; | ||
| 40 | int __user *argp; | ||
| 41 | |||
| 42 | if (get_user(u_array_size, arg)) | ||
| 43 | return -EFAULT; | ||
| 44 | |||
| 45 | if (u_array_size <= 0) | ||
| 46 | return -EINVAL; | ||
| 47 | |||
| 48 | ide_floppy_create_read_capacity_cmd(&pc); | ||
| 49 | if (ide_queue_pc_tail(drive, floppy->disk, &pc)) { | ||
| 50 | printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n"); | ||
| 51 | return -EIO; | ||
| 52 | } | ||
| 53 | |||
| 54 | header_len = pc.buf[3]; | ||
| 55 | desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */ | ||
| 56 | |||
| 57 | u_index = 0; | ||
| 58 | argp = arg + 1; | ||
| 59 | |||
| 60 | /* | ||
| 61 | * We always skip the first capacity descriptor. That's the current | ||
| 62 | * capacity. We are interested in the remaining descriptors, the | ||
| 63 | * formattable capacities. | ||
| 64 | */ | ||
| 65 | for (i = 1; i < desc_cnt; i++) { | ||
| 66 | unsigned int desc_start = 4 + i*8; | ||
| 67 | |||
| 68 | if (u_index >= u_array_size) | ||
| 69 | break; /* User-supplied buffer too small */ | ||
| 70 | |||
| 71 | blocks = be32_to_cpup((__be32 *)&pc.buf[desc_start]); | ||
| 72 | length = be16_to_cpup((__be16 *)&pc.buf[desc_start + 6]); | ||
| 73 | |||
| 74 | if (put_user(blocks, argp)) | ||
| 75 | return -EFAULT; | ||
| 76 | |||
| 77 | ++argp; | ||
| 78 | |||
| 79 | if (put_user(length, argp)) | ||
| 80 | return -EFAULT; | ||
| 81 | |||
| 82 | ++argp; | ||
| 83 | |||
| 84 | ++u_index; | ||
| 85 | } | ||
| 86 | |||
| 87 | if (put_user(u_index, arg)) | ||
| 88 | return -EFAULT; | ||
| 89 | |||
| 90 | return 0; | ||
| 91 | } | ||
| 92 | |||
| 93 | static void ide_floppy_create_format_unit_cmd(struct ide_atapi_pc *pc, int b, | ||
| 94 | int l, int flags) | ||
| 95 | { | ||
| 96 | ide_init_pc(pc); | ||
| 97 | pc->c[0] = GPCMD_FORMAT_UNIT; | ||
| 98 | pc->c[1] = 0x17; | ||
| 99 | |||
| 100 | memset(pc->buf, 0, 12); | ||
| 101 | pc->buf[1] = 0xA2; | ||
| 102 | /* Default format list header, u8 1: FOV/DCRT/IMM bits set */ | ||
| 103 | |||
| 104 | if (flags & 1) /* Verify bit on... */ | ||
| 105 | pc->buf[1] ^= 0x20; /* ... turn off DCRT bit */ | ||
| 106 | pc->buf[3] = 8; | ||
| 107 | |||
| 108 | put_unaligned(cpu_to_be32(b), (unsigned int *)(&pc->buf[4])); | ||
| 109 | put_unaligned(cpu_to_be32(l), (unsigned int *)(&pc->buf[8])); | ||
| 110 | pc->buf_size = 12; | ||
| 111 | pc->flags |= PC_FLAG_WRITING; | ||
| 112 | } | ||
| 113 | |||
| 114 | static int ide_floppy_get_sfrp_bit(ide_drive_t *drive) | ||
| 115 | { | ||
| 116 | idefloppy_floppy_t *floppy = drive->driver_data; | ||
| 117 | struct ide_atapi_pc pc; | ||
| 118 | |||
| 119 | drive->atapi_flags &= ~IDE_AFLAG_SRFP; | ||
| 120 | |||
| 121 | ide_floppy_create_mode_sense_cmd(&pc, IDEFLOPPY_CAPABILITIES_PAGE); | ||
| 122 | pc.flags |= PC_FLAG_SUPPRESS_ERROR; | ||
| 123 | |||
| 124 | if (ide_queue_pc_tail(drive, floppy->disk, &pc)) | ||
| 125 | return 1; | ||
| 126 | |||
| 127 | if (pc.buf[8 + 2] & 0x40) | ||
| 128 | drive->atapi_flags |= IDE_AFLAG_SRFP; | ||
| 129 | |||
| 130 | return 0; | ||
| 131 | } | ||
| 132 | |||
| 133 | static int ide_floppy_format_unit(ide_drive_t *drive, int __user *arg) | ||
| 134 | { | ||
| 135 | idefloppy_floppy_t *floppy = drive->driver_data; | ||
| 136 | struct ide_atapi_pc pc; | ||
| 137 | int blocks, length, flags, err = 0; | ||
| 138 | |||
| 139 | if (floppy->openers > 1) { | ||
| 140 | /* Don't format if someone is using the disk */ | ||
| 141 | drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS; | ||
| 142 | return -EBUSY; | ||
| 143 | } | ||
| 144 | |||
| 145 | drive->atapi_flags |= IDE_AFLAG_FORMAT_IN_PROGRESS; | ||
| 146 | |||
| 147 | /* | ||
| 148 | * Send ATAPI_FORMAT_UNIT to the drive. | ||
| 149 | * | ||
| 150 | * Userland gives us the following structure: | ||
| 151 | * | ||
| 152 | * struct idefloppy_format_command { | ||
| 153 | * int nblocks; | ||
| 154 | * int blocksize; | ||
| 155 | * int flags; | ||
| 156 | * } ; | ||
| 157 | * | ||
| 158 | * flags is a bitmask, currently, the only defined flag is: | ||
| 159 | * | ||
| 160 | * 0x01 - verify media after format. | ||
| 161 | */ | ||
| 162 | if (get_user(blocks, arg) || | ||
| 163 | get_user(length, arg+1) || | ||
| 164 | get_user(flags, arg+2)) { | ||
| 165 | err = -EFAULT; | ||
| 166 | goto out; | ||
| 167 | } | ||
| 168 | |||
| 169 | (void)ide_floppy_get_sfrp_bit(drive); | ||
| 170 | ide_floppy_create_format_unit_cmd(&pc, blocks, length, flags); | ||
| 171 | |||
| 172 | if (ide_queue_pc_tail(drive, floppy->disk, &pc)) | ||
| 173 | err = -EIO; | ||
| 174 | |||
| 175 | out: | ||
| 176 | if (err) | ||
| 177 | drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS; | ||
| 178 | return err; | ||
| 179 | } | ||
| 180 | |||
| 181 | /* | ||
| 182 | * Get ATAPI_FORMAT_UNIT progress indication. | ||
| 183 | * | ||
| 184 | * Userland gives a pointer to an int. The int is set to a progress | ||
| 185 | * indicator 0-65536, with 65536=100%. | ||
| 186 | * | ||
| 187 | * If the drive does not support format progress indication, we just check | ||
| 188 | * the dsc bit, and return either 0 or 65536. | ||
| 189 | */ | ||
| 190 | |||
| 191 | static int ide_floppy_get_format_progress(ide_drive_t *drive, int __user *arg) | ||
| 192 | { | ||
| 193 | idefloppy_floppy_t *floppy = drive->driver_data; | ||
| 194 | struct ide_atapi_pc pc; | ||
| 195 | int progress_indication = 0x10000; | ||
| 196 | |||
| 197 | if (drive->atapi_flags & IDE_AFLAG_SRFP) { | ||
| 198 | ide_floppy_create_request_sense_cmd(&pc); | ||
| 199 | if (ide_queue_pc_tail(drive, floppy->disk, &pc)) | ||
| 200 | return -EIO; | ||
| 201 | |||
| 202 | if (floppy->sense_key == 2 && | ||
| 203 | floppy->asc == 4 && | ||
| 204 | floppy->ascq == 4) | ||
| 205 | progress_indication = floppy->progress_indication; | ||
| 206 | |||
| 207 | /* Else assume format_unit has finished, and we're at 0x10000 */ | ||
| 208 | } else { | ||
| 209 | ide_hwif_t *hwif = drive->hwif; | ||
| 210 | unsigned long flags; | ||
| 211 | u8 stat; | ||
| 212 | |||
| 213 | local_irq_save(flags); | ||
| 214 | stat = hwif->tp_ops->read_status(hwif); | ||
| 215 | local_irq_restore(flags); | ||
| 216 | |||
| 217 | progress_indication = ((stat & ATA_DSC) == 0) ? 0 : 0x10000; | ||
| 218 | } | ||
| 219 | |||
| 220 | if (put_user(progress_indication, arg)) | ||
| 221 | return -EFAULT; | ||
| 222 | |||
| 223 | return 0; | ||
| 224 | } | ||
| 225 | |||
| 226 | int ide_floppy_format_ioctl(ide_drive_t *drive, struct file *file, | ||
| 227 | unsigned int cmd, void __user *argp) | ||
| 228 | { | ||
| 229 | switch (cmd) { | ||
| 230 | case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED: | ||
| 231 | return 0; | ||
| 232 | case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY: | ||
| 233 | return ide_floppy_get_format_capacities(drive, argp); | ||
| 234 | case IDEFLOPPY_IOCTL_FORMAT_START: | ||
| 235 | if (!(file->f_mode & 2)) | ||
| 236 | return -EPERM; | ||
| 237 | return ide_floppy_format_unit(drive, (int __user *)argp); | ||
| 238 | case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS: | ||
| 239 | return ide_floppy_get_format_progress(drive, argp); | ||
| 240 | default: | ||
| 241 | return -ENOTTY; | ||
| 242 | } | ||
| 243 | } | ||
