aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ide
diff options
context:
space:
mode:
authorBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2008-10-10 16:39:38 -0400
committerBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2008-10-10 16:39:38 -0400
commit0127854d7c96612a454bed6de242e28f8021fa7f (patch)
tree32aef08c4908b511c732d32f50a688ef14a4d0a2 /drivers/ide
parent49cac39e71bd6bbcf934c6ba837e21503902c088 (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/ide')
-rw-r--r--drivers/ide/Makefile3
-rw-r--r--drivers/ide/ide-floppy.c296
-rw-r--r--drivers/ide/ide-floppy.h63
-rw-r--r--drivers/ide/ide-floppy_ioctl.c243
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
37obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o 37obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o
38 38
39ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o 39ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o
40ide-floppy_mod-y += ide-floppy.o ide-floppy_ioctl.o
40 41
41obj-$(CONFIG_BLK_DEV_IDEDISK) += ide-disk.o 42obj-$(CONFIG_BLK_DEV_IDEDISK) += ide-disk.o
42obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd_mod.o 43obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd_mod.o
44obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy_mod.o
43obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o 45obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o
44obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o
45 46
46ifeq ($(CONFIG_BLK_DEV_IDECS), y) 47ifeq ($(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 */
83typedef 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
133static DEFINE_MUTEX(idefloppy_ref_mutex); 85static 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
248static void idefloppy_create_request_sense_cmd(struct ide_atapi_pc *pc) 200void 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
385static void idefloppy_create_read_capacity_cmd(struct ide_atapi_pc *pc) 337void 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
394static 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. */
416static void idefloppy_create_mode_sense_cmd(struct ide_atapi_pc *pc, 347void 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
614static 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
752static 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
821static 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
856static sector_t idefloppy_capacity(ide_drive_t *drive) 644static 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
1121static 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
1163out:
1164 if (err)
1165 drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
1166 return err;
1167}
1168
1169static 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
1188static int idefloppy_ioctl(struct inode *inode, struct file *file, 909static 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
1318MODULE_ALIAS("ide:*m-floppy*"); 1039MODULE_ALIAS("ide:*m-floppy*");
1040MODULE_ALIAS("ide-floppy");
1319module_init(idefloppy_init); 1041module_init(idefloppy_init);
1320module_exit(idefloppy_exit); 1042module_exit(idefloppy_exit);
1321MODULE_LICENSE("GPL"); 1043MODULE_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 */
9typedef 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 */
55void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *, u8);
56void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *);
57void ide_floppy_create_request_sense_cmd(struct ide_atapi_pc *);
58
59/* ide-floppy_ioctl.c */
60int 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
34static 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
93static 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
114static 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
133static 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
175out:
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
191static 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
226int 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}