Linux Audio

Check our new training course

Buildroot integration, development and maintenance

Need a Buildroot system for your embedded project?
Loading...
v5.9
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * ide-floppy IOCTLs handling.
  4 */
  5
  6#include <linux/kernel.h>
  7#include <linux/ide.h>
  8#include <linux/compat.h>
  9#include <linux/cdrom.h>
 10#include <linux/mutex.h>
 11
 12#include <asm/unaligned.h>
 13
 14#include <scsi/scsi_ioctl.h>
 15
 16#include "ide-floppy.h"
 17
 18/*
 19 * Obtain the list of formattable capacities.
 20 * Very similar to ide_floppy_get_capacity, except that we push the capacity
 21 * descriptors to userland, instead of our own structures.
 22 *
 23 * Userland gives us the following structure:
 24 *
 25 * struct idefloppy_format_capacities {
 26 *	int nformats;
 27 *	struct {
 28 *		int nblocks;
 29 *		int blocksize;
 30 *	} formats[];
 31 * };
 32 *
 33 * userland initializes nformats to the number of allocated formats[] records.
 34 * On exit we set nformats to the number of records we've actually initialized.
 35 */
 36
 37static DEFINE_MUTEX(ide_floppy_ioctl_mutex);
 38static int ide_floppy_get_format_capacities(ide_drive_t *drive,
 39					    struct ide_atapi_pc *pc,
 40					    int __user *arg)
 41{
 42	struct ide_disk_obj *floppy = drive->driver_data;
 43	int i, blocks, length, u_array_size, u_index;
 44	int __user *argp;
 45	u8 pc_buf[256], header_len, desc_cnt;
 46
 47	if (get_user(u_array_size, arg))
 48		return -EFAULT;
 49
 50	if (u_array_size <= 0)
 51		return -EINVAL;
 52
 53	ide_floppy_create_read_capacity_cmd(pc);
 54
 55	if (ide_queue_pc_tail(drive, floppy->disk, pc, pc_buf, pc->req_xfer)) {
 56		printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
 57		return -EIO;
 58	}
 59
 60	header_len = pc_buf[3];
 61	desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
 62
 63	u_index = 0;
 64	argp = arg + 1;
 65
 66	/*
 67	 * We always skip the first capacity descriptor.  That's the current
 68	 * capacity.  We are interested in the remaining descriptors, the
 69	 * formattable capacities.
 70	 */
 71	for (i = 1; i < desc_cnt; i++) {
 72		unsigned int desc_start = 4 + i*8;
 73
 74		if (u_index >= u_array_size)
 75			break;	/* User-supplied buffer too small */
 76
 77		blocks = be32_to_cpup((__be32 *)&pc_buf[desc_start]);
 78		length = be16_to_cpup((__be16 *)&pc_buf[desc_start + 6]);
 79
 80		if (put_user(blocks, argp))
 81			return -EFAULT;
 82
 83		++argp;
 84
 85		if (put_user(length, argp))
 86			return -EFAULT;
 87
 88		++argp;
 89
 90		++u_index;
 91	}
 92
 93	if (put_user(u_index, arg))
 94		return -EFAULT;
 95
 96	return 0;
 97}
 98
 99static void ide_floppy_create_format_unit_cmd(struct ide_atapi_pc *pc,
100					      u8 *buf, int b, int l,
101					      int flags)
102{
103	ide_init_pc(pc);
104	pc->c[0] = GPCMD_FORMAT_UNIT;
105	pc->c[1] = 0x17;
106
107	memset(buf, 0, 12);
108	buf[1] = 0xA2;
109	/* Default format list header, u8 1: FOV/DCRT/IMM bits set */
110
111	if (flags & 1)				/* Verify bit on... */
112		buf[1] ^= 0x20;			/* ... turn off DCRT bit */
113	buf[3] = 8;
114
115	put_unaligned(cpu_to_be32(b), (unsigned int *)(&buf[4]));
116	put_unaligned(cpu_to_be32(l), (unsigned int *)(&buf[8]));
117	pc->req_xfer = 12;
118	pc->flags |= PC_FLAG_WRITING;
119}
120
121static int ide_floppy_get_sfrp_bit(ide_drive_t *drive, struct ide_atapi_pc *pc)
122{
123	struct ide_disk_obj *floppy = drive->driver_data;
124	u8 buf[20];
125
126	drive->atapi_flags &= ~IDE_AFLAG_SRFP;
127
128	ide_floppy_create_mode_sense_cmd(pc, IDEFLOPPY_CAPABILITIES_PAGE);
129	pc->flags |= PC_FLAG_SUPPRESS_ERROR;
130
131	if (ide_queue_pc_tail(drive, floppy->disk, pc, buf, pc->req_xfer))
132		return 1;
133
134	if (buf[8 + 2] & 0x40)
135		drive->atapi_flags |= IDE_AFLAG_SRFP;
136
137	return 0;
138}
139
140static int ide_floppy_format_unit(ide_drive_t *drive, struct ide_atapi_pc *pc,
141				  int __user *arg)
142{
143	struct ide_disk_obj *floppy = drive->driver_data;
144	u8 buf[12];
145	int blocks, length, flags, err = 0;
146
147	if (floppy->openers > 1) {
148		/* Don't format if someone is using the disk */
149		drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
150		return -EBUSY;
151	}
152
153	drive->dev_flags |= IDE_DFLAG_FORMAT_IN_PROGRESS;
154
155	/*
156	 * Send ATAPI_FORMAT_UNIT to the drive.
157	 *
158	 * Userland gives us the following structure:
159	 *
160	 * struct idefloppy_format_command {
161	 *        int nblocks;
162	 *        int blocksize;
163	 *        int flags;
164	 *        } ;
165	 *
166	 * flags is a bitmask, currently, the only defined flag is:
167	 *
168	 *        0x01 - verify media after format.
169	 */
170	if (get_user(blocks, arg) ||
171			get_user(length, arg+1) ||
172			get_user(flags, arg+2)) {
173		err = -EFAULT;
174		goto out;
175	}
176
177	ide_floppy_get_sfrp_bit(drive, pc);
178	ide_floppy_create_format_unit_cmd(pc, buf, blocks, length, flags);
179
180	if (ide_queue_pc_tail(drive, floppy->disk, pc, buf, pc->req_xfer))
181		err = -EIO;
182
183out:
184	if (err)
185		drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
186	return err;
187}
188
189/*
190 * Get ATAPI_FORMAT_UNIT progress indication.
191 *
192 * Userland gives a pointer to an int.  The int is set to a progress
193 * indicator 0-65536, with 65536=100%.
194 *
195 * If the drive does not support format progress indication, we just check
196 * the dsc bit, and return either 0 or 65536.
197 */
198
199static int ide_floppy_get_format_progress(ide_drive_t *drive,
200					  struct ide_atapi_pc *pc,
201					  int __user *arg)
202{
203	struct ide_disk_obj *floppy = drive->driver_data;
204	u8 sense_buf[18];
205	int progress_indication = 0x10000;
206
207	if (drive->atapi_flags & IDE_AFLAG_SRFP) {
208		ide_create_request_sense_cmd(drive, pc);
209		if (ide_queue_pc_tail(drive, floppy->disk, pc, sense_buf,
210				      pc->req_xfer))
211			return -EIO;
212
213		if (floppy->sense_key == 2 &&
214		    floppy->asc == 4 &&
215		    floppy->ascq == 4)
216			progress_indication = floppy->progress_indication;
217
218		/* Else assume format_unit has finished, and we're at 0x10000 */
219	} else {
220		ide_hwif_t *hwif = drive->hwif;
221		unsigned long flags;
222		u8 stat;
223
224		local_irq_save(flags);
225		stat = hwif->tp_ops->read_status(hwif);
226		local_irq_restore(flags);
227
228		progress_indication = ((stat & ATA_DSC) == 0) ? 0 : 0x10000;
229	}
230
231	if (put_user(progress_indication, arg))
232		return -EFAULT;
233
234	return 0;
235}
236
237static int ide_floppy_lockdoor(ide_drive_t *drive, struct ide_atapi_pc *pc,
238			       unsigned long arg, unsigned int cmd)
239{
240	struct ide_disk_obj *floppy = drive->driver_data;
241	struct gendisk *disk = floppy->disk;
242	int prevent = (arg && cmd != CDROMEJECT) ? 1 : 0;
243
244	if (floppy->openers > 1)
245		return -EBUSY;
246
247	ide_set_media_lock(drive, disk, prevent);
248
249	if (cmd == CDROMEJECT)
250		ide_do_start_stop(drive, disk, 2);
251
252	return 0;
253}
254
255static int ide_floppy_format_ioctl(ide_drive_t *drive, struct ide_atapi_pc *pc,
256				   fmode_t mode, unsigned int cmd,
257				   void __user *argp)
258{
259	switch (cmd) {
260	case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED:
261		return 0;
262	case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY:
263		return ide_floppy_get_format_capacities(drive, pc, argp);
264	case IDEFLOPPY_IOCTL_FORMAT_START:
265		if (!(mode & FMODE_WRITE))
266			return -EPERM;
267		return ide_floppy_format_unit(drive, pc, (int __user *)argp);
268	case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
269		return ide_floppy_get_format_progress(drive, pc, argp);
270	default:
271		return -ENOTTY;
272	}
273}
274
275int ide_floppy_ioctl(ide_drive_t *drive, struct block_device *bdev,
276		     fmode_t mode, unsigned int cmd, unsigned long arg)
277{
278	struct ide_atapi_pc pc;
279	void __user *argp = (void __user *)arg;
280	int err;
281
282	mutex_lock(&ide_floppy_ioctl_mutex);
283	if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR) {
284		err = ide_floppy_lockdoor(drive, &pc, arg, cmd);
285		goto out;
286	}
287
288	err = ide_floppy_format_ioctl(drive, &pc, mode, cmd, argp);
289	if (err != -ENOTTY)
290		goto out;
291
292	/*
293	 * skip SCSI_IOCTL_SEND_COMMAND (deprecated)
294	 * and CDROM_SEND_PACKET (legacy) ioctls
295	 */
296	if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
297		err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
298
299	if (err == -ENOTTY)
300		err = generic_ide_ioctl(drive, bdev, cmd, arg);
301
302out:
303	mutex_unlock(&ide_floppy_ioctl_mutex);
304	return err;
305}
306
307#ifdef CONFIG_COMPAT
308int ide_floppy_compat_ioctl(ide_drive_t *drive, struct block_device *bdev,
309			    fmode_t mode, unsigned int cmd, unsigned long arg)
310{
311	struct ide_atapi_pc pc;
312	void __user *argp = compat_ptr(arg);
313	int err;
314
315	mutex_lock(&ide_floppy_ioctl_mutex);
316	if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR) {
317		err = ide_floppy_lockdoor(drive, &pc, arg, cmd);
318		goto out;
319	}
320
321	err = ide_floppy_format_ioctl(drive, &pc, mode, cmd, argp);
322	if (err != -ENOTTY)
323		goto out;
324
325	/*
326	 * skip SCSI_IOCTL_SEND_COMMAND (deprecated)
327	 * and CDROM_SEND_PACKET (legacy) ioctls
328	 */
329	if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
330		err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
331
332	if (err == -ENOTTY)
333		err = generic_ide_ioctl(drive, bdev, cmd, arg);
334
335out:
336	mutex_unlock(&ide_floppy_ioctl_mutex);
337	return err;
338}
339#endif
v4.17
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * ide-floppy IOCTLs handling.
  4 */
  5
  6#include <linux/kernel.h>
  7#include <linux/ide.h>
 
  8#include <linux/cdrom.h>
  9#include <linux/mutex.h>
 10
 11#include <asm/unaligned.h>
 12
 13#include <scsi/scsi_ioctl.h>
 14
 15#include "ide-floppy.h"
 16
 17/*
 18 * Obtain the list of formattable capacities.
 19 * Very similar to ide_floppy_get_capacity, except that we push the capacity
 20 * descriptors to userland, instead of our own structures.
 21 *
 22 * Userland gives us the following structure:
 23 *
 24 * struct idefloppy_format_capacities {
 25 *	int nformats;
 26 *	struct {
 27 *		int nblocks;
 28 *		int blocksize;
 29 *	} formats[];
 30 * };
 31 *
 32 * userland initializes nformats to the number of allocated formats[] records.
 33 * On exit we set nformats to the number of records we've actually initialized.
 34 */
 35
 36static DEFINE_MUTEX(ide_floppy_ioctl_mutex);
 37static int ide_floppy_get_format_capacities(ide_drive_t *drive,
 38					    struct ide_atapi_pc *pc,
 39					    int __user *arg)
 40{
 41	struct ide_disk_obj *floppy = drive->driver_data;
 42	int i, blocks, length, u_array_size, u_index;
 43	int __user *argp;
 44	u8 pc_buf[256], header_len, desc_cnt;
 45
 46	if (get_user(u_array_size, arg))
 47		return -EFAULT;
 48
 49	if (u_array_size <= 0)
 50		return -EINVAL;
 51
 52	ide_floppy_create_read_capacity_cmd(pc);
 53
 54	if (ide_queue_pc_tail(drive, floppy->disk, pc, pc_buf, pc->req_xfer)) {
 55		printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
 56		return -EIO;
 57	}
 58
 59	header_len = pc_buf[3];
 60	desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
 61
 62	u_index = 0;
 63	argp = arg + 1;
 64
 65	/*
 66	 * We always skip the first capacity descriptor.  That's the current
 67	 * capacity.  We are interested in the remaining descriptors, the
 68	 * formattable capacities.
 69	 */
 70	for (i = 1; i < desc_cnt; i++) {
 71		unsigned int desc_start = 4 + i*8;
 72
 73		if (u_index >= u_array_size)
 74			break;	/* User-supplied buffer too small */
 75
 76		blocks = be32_to_cpup((__be32 *)&pc_buf[desc_start]);
 77		length = be16_to_cpup((__be16 *)&pc_buf[desc_start + 6]);
 78
 79		if (put_user(blocks, argp))
 80			return -EFAULT;
 81
 82		++argp;
 83
 84		if (put_user(length, argp))
 85			return -EFAULT;
 86
 87		++argp;
 88
 89		++u_index;
 90	}
 91
 92	if (put_user(u_index, arg))
 93		return -EFAULT;
 94
 95	return 0;
 96}
 97
 98static void ide_floppy_create_format_unit_cmd(struct ide_atapi_pc *pc,
 99					      u8 *buf, int b, int l,
100					      int flags)
101{
102	ide_init_pc(pc);
103	pc->c[0] = GPCMD_FORMAT_UNIT;
104	pc->c[1] = 0x17;
105
106	memset(buf, 0, 12);
107	buf[1] = 0xA2;
108	/* Default format list header, u8 1: FOV/DCRT/IMM bits set */
109
110	if (flags & 1)				/* Verify bit on... */
111		buf[1] ^= 0x20;			/* ... turn off DCRT bit */
112	buf[3] = 8;
113
114	put_unaligned(cpu_to_be32(b), (unsigned int *)(&buf[4]));
115	put_unaligned(cpu_to_be32(l), (unsigned int *)(&buf[8]));
116	pc->req_xfer = 12;
117	pc->flags |= PC_FLAG_WRITING;
118}
119
120static int ide_floppy_get_sfrp_bit(ide_drive_t *drive, struct ide_atapi_pc *pc)
121{
122	struct ide_disk_obj *floppy = drive->driver_data;
123	u8 buf[20];
124
125	drive->atapi_flags &= ~IDE_AFLAG_SRFP;
126
127	ide_floppy_create_mode_sense_cmd(pc, IDEFLOPPY_CAPABILITIES_PAGE);
128	pc->flags |= PC_FLAG_SUPPRESS_ERROR;
129
130	if (ide_queue_pc_tail(drive, floppy->disk, pc, buf, pc->req_xfer))
131		return 1;
132
133	if (buf[8 + 2] & 0x40)
134		drive->atapi_flags |= IDE_AFLAG_SRFP;
135
136	return 0;
137}
138
139static int ide_floppy_format_unit(ide_drive_t *drive, struct ide_atapi_pc *pc,
140				  int __user *arg)
141{
142	struct ide_disk_obj *floppy = drive->driver_data;
143	u8 buf[12];
144	int blocks, length, flags, err = 0;
145
146	if (floppy->openers > 1) {
147		/* Don't format if someone is using the disk */
148		drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
149		return -EBUSY;
150	}
151
152	drive->dev_flags |= IDE_DFLAG_FORMAT_IN_PROGRESS;
153
154	/*
155	 * Send ATAPI_FORMAT_UNIT to the drive.
156	 *
157	 * Userland gives us the following structure:
158	 *
159	 * struct idefloppy_format_command {
160	 *        int nblocks;
161	 *        int blocksize;
162	 *        int flags;
163	 *        } ;
164	 *
165	 * flags is a bitmask, currently, the only defined flag is:
166	 *
167	 *        0x01 - verify media after format.
168	 */
169	if (get_user(blocks, arg) ||
170			get_user(length, arg+1) ||
171			get_user(flags, arg+2)) {
172		err = -EFAULT;
173		goto out;
174	}
175
176	ide_floppy_get_sfrp_bit(drive, pc);
177	ide_floppy_create_format_unit_cmd(pc, buf, blocks, length, flags);
178
179	if (ide_queue_pc_tail(drive, floppy->disk, pc, buf, pc->req_xfer))
180		err = -EIO;
181
182out:
183	if (err)
184		drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
185	return err;
186}
187
188/*
189 * Get ATAPI_FORMAT_UNIT progress indication.
190 *
191 * Userland gives a pointer to an int.  The int is set to a progress
192 * indicator 0-65536, with 65536=100%.
193 *
194 * If the drive does not support format progress indication, we just check
195 * the dsc bit, and return either 0 or 65536.
196 */
197
198static int ide_floppy_get_format_progress(ide_drive_t *drive,
199					  struct ide_atapi_pc *pc,
200					  int __user *arg)
201{
202	struct ide_disk_obj *floppy = drive->driver_data;
203	u8 sense_buf[18];
204	int progress_indication = 0x10000;
205
206	if (drive->atapi_flags & IDE_AFLAG_SRFP) {
207		ide_create_request_sense_cmd(drive, pc);
208		if (ide_queue_pc_tail(drive, floppy->disk, pc, sense_buf,
209				      pc->req_xfer))
210			return -EIO;
211
212		if (floppy->sense_key == 2 &&
213		    floppy->asc == 4 &&
214		    floppy->ascq == 4)
215			progress_indication = floppy->progress_indication;
216
217		/* Else assume format_unit has finished, and we're at 0x10000 */
218	} else {
219		ide_hwif_t *hwif = drive->hwif;
220		unsigned long flags;
221		u8 stat;
222
223		local_irq_save(flags);
224		stat = hwif->tp_ops->read_status(hwif);
225		local_irq_restore(flags);
226
227		progress_indication = ((stat & ATA_DSC) == 0) ? 0 : 0x10000;
228	}
229
230	if (put_user(progress_indication, arg))
231		return -EFAULT;
232
233	return 0;
234}
235
236static int ide_floppy_lockdoor(ide_drive_t *drive, struct ide_atapi_pc *pc,
237			       unsigned long arg, unsigned int cmd)
238{
239	struct ide_disk_obj *floppy = drive->driver_data;
240	struct gendisk *disk = floppy->disk;
241	int prevent = (arg && cmd != CDROMEJECT) ? 1 : 0;
242
243	if (floppy->openers > 1)
244		return -EBUSY;
245
246	ide_set_media_lock(drive, disk, prevent);
247
248	if (cmd == CDROMEJECT)
249		ide_do_start_stop(drive, disk, 2);
250
251	return 0;
252}
253
254static int ide_floppy_format_ioctl(ide_drive_t *drive, struct ide_atapi_pc *pc,
255				   fmode_t mode, unsigned int cmd,
256				   void __user *argp)
257{
258	switch (cmd) {
259	case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED:
260		return 0;
261	case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY:
262		return ide_floppy_get_format_capacities(drive, pc, argp);
263	case IDEFLOPPY_IOCTL_FORMAT_START:
264		if (!(mode & FMODE_WRITE))
265			return -EPERM;
266		return ide_floppy_format_unit(drive, pc, (int __user *)argp);
267	case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
268		return ide_floppy_get_format_progress(drive, pc, argp);
269	default:
270		return -ENOTTY;
271	}
272}
273
274int ide_floppy_ioctl(ide_drive_t *drive, struct block_device *bdev,
275		     fmode_t mode, unsigned int cmd, unsigned long arg)
276{
277	struct ide_atapi_pc pc;
278	void __user *argp = (void __user *)arg;
279	int err;
280
281	mutex_lock(&ide_floppy_ioctl_mutex);
282	if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR) {
283		err = ide_floppy_lockdoor(drive, &pc, arg, cmd);
284		goto out;
285	}
286
287	err = ide_floppy_format_ioctl(drive, &pc, mode, cmd, argp);
288	if (err != -ENOTTY)
289		goto out;
290
291	/*
292	 * skip SCSI_IOCTL_SEND_COMMAND (deprecated)
293	 * and CDROM_SEND_PACKET (legacy) ioctls
294	 */
295	if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
296		err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
297
298	if (err == -ENOTTY)
299		err = generic_ide_ioctl(drive, bdev, cmd, arg);
300
301out:
302	mutex_unlock(&ide_floppy_ioctl_mutex);
303	return err;
304}