diff options
-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 | } | ||