ide-floppy.c 43.6 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
/*
Borislav Petkov's avatar
Borislav Petkov committed
2
3
 * IDE ATAPI floppy driver.
 *
4
5
6
 * Copyright (C) 1996-1999  Gadi Oxman <gadio@netvision.net.il>
 * Copyright (C) 2000-2002  Paul Bristow <paul@paulbristow.net>
 * Copyright (C) 2005       Bartlomiej Zolnierkiewicz
7
 *
Linus Torvalds's avatar
Linus Torvalds committed
8
9
10
11
12
13
 * This driver supports the following IDE floppy drives:
 *
 * LS-120/240 SuperDisk
 * Iomega Zip 100/250
 * Iomega PC Card Clik!/PocketZip
 *
Borislav Petkov's avatar
Borislav Petkov committed
14
15
 * For a historical changelog see
 * Documentation/ide/ChangeLog.ide-floppy.1996-2002
Linus Torvalds's avatar
Linus Torvalds committed
16
17
 */

18
#define IDEFLOPPY_VERSION "1.00"
Linus Torvalds's avatar
Linus Torvalds committed
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/genhd.h>
#include <linux/slab.h>
#include <linux/cdrom.h>
#include <linux/ide.h>
#include <linux/bitops.h>
35
#include <linux/mutex.h>
Linus Torvalds's avatar
Linus Torvalds committed
36

37
38
#include <scsi/scsi_ioctl.h>

Linus Torvalds's avatar
Linus Torvalds committed
39
#include <asm/byteorder.h>
40
41
42
#include <linux/irq.h>
#include <linux/uaccess.h>
#include <linux/io.h>
Linus Torvalds's avatar
Linus Torvalds committed
43
44
#include <asm/unaligned.h>

45
/* define to see debug info */
Linus Torvalds's avatar
Linus Torvalds committed
46
47
48
#define IDEFLOPPY_DEBUG_LOG		0

/* #define IDEFLOPPY_DEBUG(fmt, args...) printk(KERN_INFO fmt, ## args) */
49
#define IDEFLOPPY_DEBUG(fmt, args...)
Linus Torvalds's avatar
Linus Torvalds committed
50
51

#if IDEFLOPPY_DEBUG_LOG
52
53
#define debug_log(fmt, args...) \
	printk(KERN_INFO "ide-floppy: " fmt, ## args)
Linus Torvalds's avatar
Linus Torvalds committed
54
#else
55
#define debug_log(fmt, args...) do {} while (0)
Linus Torvalds's avatar
Linus Torvalds committed
56
57
58
#endif


59
/* Some drives require a longer irq timeout. */
Linus Torvalds's avatar
Linus Torvalds committed
60
61
62
#define IDEFLOPPY_WAIT_CMD		(5 * WAIT_CMD)

/*
63
64
 * After each failed packet command we issue a request sense command and retry
 * the packet command IDEFLOPPY_MAX_PC_RETRIES times.
Linus Torvalds's avatar
Linus Torvalds committed
65
66
67
68
 */
#define IDEFLOPPY_MAX_PC_RETRIES	3

/*
69
70
 * With each packet command, we allocate a buffer of IDEFLOPPY_PC_BUFFER_SIZE
 * bytes.
Linus Torvalds's avatar
Linus Torvalds committed
71
72
73
74
 */
#define IDEFLOPPY_PC_BUFFER_SIZE	256

/*
75
76
77
 * In various places in the driver, we need to allocate storage for packet
 * commands and requests, which will remain valid while	we leave the driver to
 * wait for an interrupt or a timeout event.
Linus Torvalds's avatar
Linus Torvalds committed
78
79
80
 */
#define IDEFLOPPY_PC_STACK		(10 + IDEFLOPPY_MAX_PC_RETRIES)

81
/* format capacities descriptor codes */
Linus Torvalds's avatar
Linus Torvalds committed
82
83
84
85
86
87
#define CAPACITY_INVALID	0x00
#define CAPACITY_UNFORMATTED	0x01
#define CAPACITY_CURRENT	0x02
#define CAPACITY_NO_CARTRIDGE	0x03

/*
88
89
90
 * Most of our global data which we need to save even as we leave the driver
 * due to an interrupt or a timer event is stored in a variable of type
 * idefloppy_floppy_t, defined below.
Linus Torvalds's avatar
Linus Torvalds committed
91
92
93
94
95
96
 */
typedef struct ide_floppy_obj {
	ide_drive_t	*drive;
	ide_driver_t	*driver;
	struct gendisk	*disk;
	struct kref	kref;
97
	unsigned int	openers;	/* protected by BKL for now */
Linus Torvalds's avatar
Linus Torvalds committed
98
99

	/* Current packet command */
100
	struct ide_atapi_pc *pc;
Linus Torvalds's avatar
Linus Torvalds committed
101
	/* Last failed packet command */
102
	struct ide_atapi_pc *failed_pc;
Linus Torvalds's avatar
Linus Torvalds committed
103
	/* Packet command stack */
104
	struct ide_atapi_pc pc_stack[IDEFLOPPY_PC_STACK];
Linus Torvalds's avatar
Linus Torvalds committed
105
106
107
108
109
110
	/* Next free packet command storage space */
	int pc_stack_index;
	struct request rq_stack[IDEFLOPPY_PC_STACK];
	/* We implement a circular array */
	int rq_stack_index;

111
	/* Last error information */
Linus Torvalds's avatar
Linus Torvalds committed
112
113
114
115
116
	u8 sense_key, asc, ascq;
	/* delay this long before sending packet command */
	u8 ticks;
	int progress_indication;

117
	/* Device information */
Linus Torvalds's avatar
Linus Torvalds committed
118
119
	/* Current format */
	int blocks, block_size, bs_factor;
120
121
	/* Last format capacity descriptor */
	u8 cap_desc[8];
Linus Torvalds's avatar
Linus Torvalds committed
122
	/* Copy of the flexible disk page */
123
	u8 flexible_disk_page[32];
Linus Torvalds's avatar
Linus Torvalds committed
124
125
126
127
128
129
130
131
	/* Write protect */
	int wp;
	/* Supports format progress report */
	int srfp;
	/* Status/Action flags */
	unsigned long flags;
} idefloppy_floppy_t;

132
#define IDEFLOPPY_TICKS_DELAY	HZ/20	/* default delay for ZIP 100 (50ms) */
Linus Torvalds's avatar
Linus Torvalds committed
133

134
135
136
137
138
139
140
141
142
143
144
145
146
/* Floppy flag bits values. */
enum {
	/* DRQ interrupt device */
	IDEFLOPPY_FLAG_DRQ_INTERRUPT		= (1 <<	0),
	/* Media may have changed */
	IDEFLOPPY_FLAG_MEDIA_CHANGED		= (1 << 1),
	/* Format in progress */
	IDEFLOPPY_FLAG_FORMAT_IN_PROGRESS	= (1 << 2),
	/* Avoid commands not supported in Clik drive */
	IDEFLOPPY_FLAG_CLIK_DRIVE		= (1 << 3),
	/* Requires BH algorithm for packets */
	IDEFLOPPY_FLAG_ZIP_DRIVE		= (1 << 4),
};
Linus Torvalds's avatar
Linus Torvalds committed
147

148
/* Defines for the MODE SENSE command */
Linus Torvalds's avatar
Linus Torvalds committed
149
150
#define MODE_SENSE_CURRENT		0x00
#define MODE_SENSE_CHANGEABLE		0x01
151
#define MODE_SENSE_DEFAULT		0x02
Linus Torvalds's avatar
Linus Torvalds committed
152
153
#define MODE_SENSE_SAVED		0x03

154
/* IOCTLs used in low-level formatting. */
Linus Torvalds's avatar
Linus Torvalds committed
155
156
157
158
159
#define	IDEFLOPPY_IOCTL_FORMAT_SUPPORTED	0x4600
#define	IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY	0x4601
#define	IDEFLOPPY_IOCTL_FORMAT_START		0x4602
#define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS	0x4603

160
/* Error code returned in rq->errors to the higher part of the driver. */
Linus Torvalds's avatar
Linus Torvalds committed
161
162
163
#define	IDEFLOPPY_ERROR_GENERAL		101

/*
164
165
 * Pages of the SELECT SENSE / MODE SENSE packet commands.
 * See SFF-8070i spec.
Linus Torvalds's avatar
Linus Torvalds committed
166
167
168
169
 */
#define	IDEFLOPPY_CAPABILITIES_PAGE	0x1b
#define IDEFLOPPY_FLEXIBLE_DISK_PAGE	0x05

170
static DEFINE_MUTEX(idefloppy_ref_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
171
172
173
174
175
176
177
178
179
180

#define to_ide_floppy(obj) container_of(obj, struct ide_floppy_obj, kref)

#define ide_floppy_g(disk) \
	container_of((disk)->private_data, struct ide_floppy_obj, driver)

static struct ide_floppy_obj *ide_floppy_get(struct gendisk *disk)
{
	struct ide_floppy_obj *floppy = NULL;

181
	mutex_lock(&idefloppy_ref_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
182
183
184
	floppy = ide_floppy_g(disk);
	if (floppy)
		kref_get(&floppy->kref);
185
	mutex_unlock(&idefloppy_ref_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
186
187
188
	return floppy;
}

189
static void idefloppy_cleanup_obj(struct kref *);
Linus Torvalds's avatar
Linus Torvalds committed
190
191
192

static void ide_floppy_put(struct ide_floppy_obj *floppy)
{
193
	mutex_lock(&idefloppy_ref_mutex);
194
	kref_put(&floppy->kref, idefloppy_cleanup_obj);
195
	mutex_unlock(&idefloppy_ref_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
196
197
198
}

/*
199
200
 * Used to finish servicing a request. For read/write requests, we will call
 * ide_end_request to pass to the next buffer.
Linus Torvalds's avatar
Linus Torvalds committed
201
 */
202
static int idefloppy_end_request(ide_drive_t *drive, int uptodate, int nsecs)
Linus Torvalds's avatar
Linus Torvalds committed
203
204
205
206
207
{
	idefloppy_floppy_t *floppy = drive->driver_data;
	struct request *rq = HWGROUP(drive)->rq;
	int error;

208
	debug_log("Reached %s\n", __func__);
Linus Torvalds's avatar
Linus Torvalds committed
209
210

	switch (uptodate) {
211
212
213
	case 0: error = IDEFLOPPY_ERROR_GENERAL; break;
	case 1: error = 0; break;
	default: error = uptodate;
Linus Torvalds's avatar
Linus Torvalds committed
214
215
216
217
218
219
	}
	if (error)
		floppy->failed_pc = NULL;
	/* Why does this happen? */
	if (!rq)
		return 0;
220
	if (!blk_special_request(rq)) {
Linus Torvalds's avatar
Linus Torvalds committed
221
222
223
224
225
226
227
228
229
230
		/* our real local end request function */
		ide_end_request(drive, uptodate, nsecs);
		return 0;
	}
	rq->errors = error;
	/* fixme: need to move this local also */
	ide_end_drive_cmd(drive, 0, 0);
	return 0;
}

231
static void ide_floppy_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
232
				  unsigned int bcount, int direction)
Linus Torvalds's avatar
Linus Torvalds committed
233
{
234
	ide_hwif_t *hwif = drive->hwif;
Linus Torvalds's avatar
Linus Torvalds committed
235
	struct request *rq = pc->rq;
236
	struct req_iterator iter;
Linus Torvalds's avatar
Linus Torvalds committed
237
238
	struct bio_vec *bvec;
	unsigned long flags;
239
	int count, done = 0;
Linus Torvalds's avatar
Linus Torvalds committed
240
241
	char *data;

242
	rq_for_each_segment(bvec, rq, iter) {
243
244
		if (!bcount)
			break;
Linus Torvalds's avatar
Linus Torvalds committed
245

246
		count = min(bvec->bv_len, bcount);
Linus Torvalds's avatar
Linus Torvalds committed
247

248
		data = bvec_kmap_irq(bvec, &flags);
249
		if (direction)
250
			hwif->output_data(drive, NULL, data, count);
251
		else
252
			hwif->input_data(drive, NULL, data, count);
253
		bvec_kunmap_irq(data, &flags);
Linus Torvalds's avatar
Linus Torvalds committed
254

255
256
257
		bcount -= count;
		pc->b_count += count;
		done += count;
Linus Torvalds's avatar
Linus Torvalds committed
258
259
	}

260
	idefloppy_end_request(drive, 1, done >> 9);
Linus Torvalds's avatar
Linus Torvalds committed
261
262

	if (bcount) {
263
264
		printk(KERN_ERR "%s: leftover data in %s, bcount == %d\n",
				drive->name, __func__, bcount);
265
		ide_pad_transfer(drive, direction, bcount);
Linus Torvalds's avatar
Linus Torvalds committed
266
267
268
	}
}

269
270
static void idefloppy_update_buffers(ide_drive_t *drive,
				struct ide_atapi_pc *pc)
Linus Torvalds's avatar
Linus Torvalds committed
271
272
273
274
275
{
	struct request *rq = pc->rq;
	struct bio *bio = rq->bio;

	while ((bio = rq->bio) != NULL)
276
		idefloppy_end_request(drive, 1, 0);
Linus Torvalds's avatar
Linus Torvalds committed
277
278
279
}

/*
280
281
282
 * Generate a new packet command request in front of the request queue, before
 * the current request so that it will be processed immediately, on the next
 * pass through the driver.
Linus Torvalds's avatar
Linus Torvalds committed
283
 */
284
static void idefloppy_queue_pc_head(ide_drive_t *drive, struct ide_atapi_pc *pc,
285
		struct request *rq)
Linus Torvalds's avatar
Linus Torvalds committed
286
287
288
{
	struct ide_floppy_obj *floppy = drive->driver_data;

289
	blk_rq_init(NULL, rq);
Linus Torvalds's avatar
Linus Torvalds committed
290
	rq->buffer = (char *) pc;
291
	rq->cmd_type = REQ_TYPE_SPECIAL;
292
	rq->cmd_flags |= REQ_PREEMPT;
Linus Torvalds's avatar
Linus Torvalds committed
293
	rq->rq_disk = floppy->disk;
294
	ide_do_drive_cmd(drive, rq);
Linus Torvalds's avatar
Linus Torvalds committed
295
296
}

297
static struct ide_atapi_pc *idefloppy_next_pc_storage(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
298
299
300
301
{
	idefloppy_floppy_t *floppy = drive->driver_data;

	if (floppy->pc_stack_index == IDEFLOPPY_PC_STACK)
302
		floppy->pc_stack_index = 0;
Linus Torvalds's avatar
Linus Torvalds committed
303
304
305
	return (&floppy->pc_stack[floppy->pc_stack_index++]);
}

306
static struct request *idefloppy_next_rq_storage(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
307
308
309
310
311
312
313
314
{
	idefloppy_floppy_t *floppy = drive->driver_data;

	if (floppy->rq_stack_index == IDEFLOPPY_PC_STACK)
		floppy->rq_stack_index = 0;
	return (&floppy->rq_stack[floppy->rq_stack_index++]);
}

315
static void idefloppy_request_sense_callback(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
316
317
{
	idefloppy_floppy_t *floppy = drive->driver_data;
318
	u8 *buf = floppy->pc->buf;
Linus Torvalds's avatar
Linus Torvalds committed
319

320
321
	debug_log("Reached %s\n", __func__);

Linus Torvalds's avatar
Linus Torvalds committed
322
	if (!floppy->pc->error) {
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
		floppy->sense_key = buf[2] & 0x0F;
		floppy->asc = buf[12];
		floppy->ascq = buf[13];
		floppy->progress_indication = buf[15] & 0x80 ?
			(u16)get_unaligned((u16 *)&buf[16]) : 0x10000;

		if (floppy->failed_pc)
			debug_log("pc = %x, sense key = %x, asc = %x,"
					" ascq = %x\n",
					floppy->failed_pc->c[0],
					floppy->sense_key,
					floppy->asc,
					floppy->ascq);
		else
			debug_log("sense key = %x, asc = %x, ascq = %x\n",
					floppy->sense_key,
					floppy->asc,
					floppy->ascq);


343
		idefloppy_end_request(drive, 1, 0);
Linus Torvalds's avatar
Linus Torvalds committed
344
	} else {
345
346
		printk(KERN_ERR "Error in REQUEST SENSE itself - Aborting"
				" request!\n");
347
		idefloppy_end_request(drive, 0, 0);
Linus Torvalds's avatar
Linus Torvalds committed
348
349
350
	}
}

351
352
/* General packet command callback function. */
static void idefloppy_pc_callback(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
353
354
{
	idefloppy_floppy_t *floppy = drive->driver_data;
355
356

	debug_log("Reached %s\n", __func__);
Linus Torvalds's avatar
Linus Torvalds committed
357

358
	idefloppy_end_request(drive, floppy->pc->error ? 0 : 1, 0);
Linus Torvalds's avatar
Linus Torvalds committed
359
360
}

361
static void idefloppy_init_pc(struct ide_atapi_pc *pc)
Linus Torvalds's avatar
Linus Torvalds committed
362
363
364
365
{
	memset(pc->c, 0, 12);
	pc->retries = 0;
	pc->flags = 0;
366
367
368
369
	pc->req_xfer = 0;
	pc->buf = pc->pc_buf;
	pc->buf_size = IDEFLOPPY_PC_BUFFER_SIZE;
	pc->idefloppy_callback = &idefloppy_pc_callback;
Linus Torvalds's avatar
Linus Torvalds committed
370
371
}

372
static void idefloppy_create_request_sense_cmd(struct ide_atapi_pc *pc)
Linus Torvalds's avatar
Linus Torvalds committed
373
{
374
375
	idefloppy_init_pc(pc);
	pc->c[0] = GPCMD_REQUEST_SENSE;
Linus Torvalds's avatar
Linus Torvalds committed
376
	pc->c[4] = 255;
377
378
	pc->req_xfer = 18;
	pc->idefloppy_callback = &idefloppy_request_sense_callback;
Linus Torvalds's avatar
Linus Torvalds committed
379
380
381
}

/*
382
383
 * Called when an error was detected during the last packet command. We queue a
 * request sense packet command in the head of the request list.
Linus Torvalds's avatar
Linus Torvalds committed
384
 */
385
static void idefloppy_retry_pc(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
386
{
387
	struct ide_atapi_pc *pc;
Linus Torvalds's avatar
Linus Torvalds committed
388
389
	struct request *rq;

390
	(void)ide_read_error(drive);
Linus Torvalds's avatar
Linus Torvalds committed
391
392
393
394
395
396
	pc = idefloppy_next_pc_storage(drive);
	rq = idefloppy_next_rq_storage(drive);
	idefloppy_create_request_sense_cmd(pc);
	idefloppy_queue_pc_head(drive, pc, rq);
}

397
/* The usual interrupt handler called during a packet command. */
398
static ide_startstop_t idefloppy_pc_intr(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
399
400
{
	idefloppy_floppy_t *floppy = drive->driver_data;
401
	ide_hwif_t *hwif = drive->hwif;
402
	struct ide_atapi_pc *pc = floppy->pc;
Linus Torvalds's avatar
Linus Torvalds committed
403
	struct request *rq = pc->rq;
404
	xfer_func_t *xferfunc;
Linus Torvalds's avatar
Linus Torvalds committed
405
	unsigned int temp;
406
	int dma_error = 0;
407
	u16 bcount;
408
	u8 stat, ireason;
Linus Torvalds's avatar
Linus Torvalds committed
409

410
	debug_log("Reached %s interrupt handler\n", __func__);
Linus Torvalds's avatar
Linus Torvalds committed
411

412
	if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
413
		dma_error = hwif->dma_ops->dma_end(drive);
414
415
416
		if (dma_error) {
			printk(KERN_ERR "%s: DMA %s error\n", drive->name,
					rq_data_dir(rq) ? "write" : "read");
417
			pc->flags |= PC_FLAG_DMA_ERROR;
Linus Torvalds's avatar
Linus Torvalds committed
418
		} else {
419
			pc->xferred = pc->req_xfer;
Linus Torvalds's avatar
Linus Torvalds committed
420
421
			idefloppy_update_buffers(drive, pc);
		}
422
		debug_log("DMA finished\n");
Linus Torvalds's avatar
Linus Torvalds committed
423
424
425
	}

	/* Clear the interrupt */
426
	stat = ide_read_status(drive);
Linus Torvalds's avatar
Linus Torvalds committed
427

428
429
	/* No more interrupts */
	if ((stat & DRQ_STAT) == 0) {
430
		debug_log("Packet command completed, %d bytes transferred\n",
431
				pc->xferred);
432
		pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS;
Linus Torvalds's avatar
Linus Torvalds committed
433

434
		local_irq_enable_in_hardirq();
Linus Torvalds's avatar
Linus Torvalds committed
435

436
		if ((stat & ERR_STAT) || (pc->flags & PC_FLAG_DMA_ERROR)) {
Linus Torvalds's avatar
Linus Torvalds committed
437
			/* Error detected */
438
			debug_log("%s: I/O error\n", drive->name);
Linus Torvalds's avatar
Linus Torvalds committed
439
			rq->errors++;
440
			if (pc->c[0] == GPCMD_REQUEST_SENSE) {
Linus Torvalds's avatar
Linus Torvalds committed
441
442
443
444
445
446
447
448
449
450
451
452
453
				printk(KERN_ERR "ide-floppy: I/O error in "
					"request sense command\n");
				return ide_do_reset(drive);
			}
			/* Retry operation */
			idefloppy_retry_pc(drive);
			/* queued, but not started */
			return ide_stopped;
		}
		pc->error = 0;
		if (floppy->failed_pc == pc)
			floppy->failed_pc = NULL;
		/* Command finished - Call the callback function */
454
		pc->idefloppy_callback(drive);
Linus Torvalds's avatar
Linus Torvalds committed
455
456
457
		return ide_stopped;
	}

458
459
	if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
		pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS;
Linus Torvalds's avatar
Linus Torvalds committed
460
461
		printk(KERN_ERR "ide-floppy: The floppy wants to issue "
			"more interrupts in DMA mode\n");
462
		ide_dma_off(drive);
Linus Torvalds's avatar
Linus Torvalds committed
463
464
465
466
		return ide_do_reset(drive);
	}

	/* Get the number of bytes to transfer */
467
468
	bcount = (hwif->INB(hwif->io_ports.lbah_addr) << 8) |
		  hwif->INB(hwif->io_ports.lbam_addr);
Linus Torvalds's avatar
Linus Torvalds committed
469
	/* on this interrupt */
470
	ireason = hwif->INB(hwif->io_ports.nsect_addr);
Linus Torvalds's avatar
Linus Torvalds committed
471

472
	if (ireason & CD) {
473
		printk(KERN_ERR "ide-floppy: CoD != 0 in %s\n", __func__);
Linus Torvalds's avatar
Linus Torvalds committed
474
475
		return ide_do_reset(drive);
	}
476
	if (((ireason & IO) == IO) == !!(pc->flags & PC_FLAG_WRITING)) {
Linus Torvalds's avatar
Linus Torvalds committed
477
478
		/* Hopefully, we will never get here */
		printk(KERN_ERR "ide-floppy: We wanted to %s, ",
479
				(ireason & IO) ? "Write" : "Read");
Linus Torvalds's avatar
Linus Torvalds committed
480
		printk(KERN_ERR "but the floppy wants us to %s !\n",
481
				(ireason & IO) ? "Read" : "Write");
Linus Torvalds's avatar
Linus Torvalds committed
482
483
		return ide_do_reset(drive);
	}
484
	if (!(pc->flags & PC_FLAG_WRITING)) {
Linus Torvalds's avatar
Linus Torvalds committed
485
		/* Reading - Check that we have enough space */
486
487
488
		temp = pc->xferred + bcount;
		if (temp > pc->req_xfer) {
			if (temp > pc->buf_size) {
Linus Torvalds's avatar
Linus Torvalds committed
489
490
491
				printk(KERN_ERR "ide-floppy: The floppy wants "
					"to send us more data than expected "
					"- discarding data\n");
492
				ide_pad_transfer(drive, 0, bcount);
493

Linus Torvalds's avatar
Linus Torvalds committed
494
495
496
497
498
499
				ide_set_handler(drive,
						&idefloppy_pc_intr,
						IDEFLOPPY_WAIT_CMD,
						NULL);
				return ide_started;
			}
500
501
			debug_log("The floppy wants to send us more data than"
					" expected - allowing transfer\n");
Linus Torvalds's avatar
Linus Torvalds committed
502
503
		}
	}
504
	if (pc->flags & PC_FLAG_WRITING)
505
		xferfunc = hwif->output_data;
506
	else
507
		xferfunc = hwif->input_data;
508

509
	if (pc->buf)
510
		xferfunc(drive, NULL, pc->cur_pos, bcount);
511
	else
512
		ide_floppy_io_buffers(drive, pc, bcount,
513
				      !!(pc->flags & PC_FLAG_WRITING));
514

Linus Torvalds's avatar
Linus Torvalds committed
515
	/* Update the current position */
516
517
	pc->xferred += bcount;
	pc->cur_pos += bcount;
Linus Torvalds's avatar
Linus Torvalds committed
518

519
520
	/* And set the interrupt handler again */
	ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
521
522
523
524
	return ide_started;
}

/*
525
526
527
528
 * What we have here is a classic case of a top half / bottom half interrupt
 * service routine. In interrupt mode, the device sends an interrupt to signal
 * that it is ready to receive a packet. However, we need to delay about 2-3
 * ticks before issuing the packet or we gets in trouble.
Linus Torvalds's avatar
Linus Torvalds committed
529
 *
530
531
532
 * So, follow carefully. transfer_pc1 is called as an interrupt (or directly).
 * In either case, when the device says it's ready for a packet, we schedule
 * the packet transfer to occur about 2-3 ticks later in transfer_pc2.
Linus Torvalds's avatar
Linus Torvalds committed
533
 */
534
static int idefloppy_transfer_pc2(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
535
536
537
538
{
	idefloppy_floppy_t *floppy = drive->driver_data;

	/* Send the actual packet */
539
540
	drive->hwif->output_data(drive, NULL, floppy->pc->c, 12);

Linus Torvalds's avatar
Linus Torvalds committed
541
542
543
544
	/* Timeout for the packet command */
	return IDEFLOPPY_WAIT_CMD;
}

545
static ide_startstop_t idefloppy_transfer_pc1(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
546
{
547
	ide_hwif_t *hwif = drive->hwif;
Linus Torvalds's avatar
Linus Torvalds committed
548
	idefloppy_floppy_t *floppy = drive->driver_data;
549
550
	ide_expiry_t *expiry;
	unsigned int timeout;
Linus Torvalds's avatar
Linus Torvalds committed
551
	ide_startstop_t startstop;
552
	u8 ireason;
Linus Torvalds's avatar
Linus Torvalds committed
553
554
555
556
557
558

	if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
		printk(KERN_ERR "ide-floppy: Strange, packet command "
				"initiated yet DRQ isn't asserted\n");
		return startstop;
	}
559
	ireason = hwif->INB(hwif->io_ports.nsect_addr);
560
	if ((ireason & CD) == 0 || (ireason & IO)) {
Linus Torvalds's avatar
Linus Torvalds committed
561
562
563
564
		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) "
				"while issuing a packet command\n");
		return ide_do_reset(drive);
	}
565
	/*
Linus Torvalds's avatar
Linus Torvalds committed
566
567
568
569
570
571
572
	 * The following delay solves a problem with ATAPI Zip 100 drives
	 * where the Busy flag was apparently being deasserted before the
	 * unit was ready to receive data. This was happening on a
	 * 1200 MHz Athlon system. 10/26/01 25msec is too short,
	 * 40 and 50msec work well. idefloppy_pc_intr will not be actually
	 * used until after the packet is moved in about 50 msec.
	 */
573
574
575
576
577
578
579
580
581
582
583
584
585
	if (floppy->flags & IDEFLOPPY_FLAG_ZIP_DRIVE) {
		timeout = floppy->ticks;
		expiry = &idefloppy_transfer_pc2;
	} else {
		timeout = IDEFLOPPY_WAIT_CMD;
		expiry = NULL;
	}

	ide_set_handler(drive, &idefloppy_pc_intr, timeout, expiry);

	if ((floppy->flags & IDEFLOPPY_FLAG_ZIP_DRIVE) == 0)
		/* Send the actual packet */
		hwif->output_data(drive, NULL, floppy->pc->c, 12);
586

Linus Torvalds's avatar
Linus Torvalds committed
587
588
589
	return ide_started;
}

590
static void ide_floppy_report_error(idefloppy_floppy_t *floppy,
591
				    struct ide_atapi_pc *pc)
Linus Torvalds's avatar
Linus Torvalds committed
592
{
593
	/* supress error messages resulting from Medium not present */
Linus Torvalds's avatar
Linus Torvalds committed
594
595
596
	if (floppy->sense_key == 0x02 &&
	    floppy->asc       == 0x3a &&
	    floppy->ascq      == 0x00)
597
598
599
600
601
602
603
		return;

	printk(KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, "
			"asc = %2x, ascq = %2x\n",
			floppy->drive->name, pc->c[0], floppy->sense_key,
			floppy->asc, floppy->ascq);

Linus Torvalds's avatar
Linus Torvalds committed
604
605
}

606
static ide_startstop_t idefloppy_issue_pc(ide_drive_t *drive,
607
		struct ide_atapi_pc *pc)
Linus Torvalds's avatar
Linus Torvalds committed
608
609
610
{
	idefloppy_floppy_t *floppy = drive->driver_data;
	ide_hwif_t *hwif = drive->hwif;
611
	u16 bcount;
612
	u8 dma;
Linus Torvalds's avatar
Linus Torvalds committed
613
614

	if (floppy->failed_pc == NULL &&
615
	    pc->c[0] != GPCMD_REQUEST_SENSE)
Linus Torvalds's avatar
Linus Torvalds committed
616
617
618
619
		floppy->failed_pc = pc;
	/* Set the current packet command */
	floppy->pc = pc;

620
	if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES) {
621
		if (!(pc->flags & PC_FLAG_SUPPRESS_ERROR))
622
623
624
625
			ide_floppy_report_error(floppy, pc);
		/* Giving up */
		pc->error = IDEFLOPPY_ERROR_GENERAL;

Linus Torvalds's avatar
Linus Torvalds committed
626
		floppy->failed_pc = NULL;
627
		pc->idefloppy_callback(drive);
Linus Torvalds's avatar
Linus Torvalds committed
628
629
630
		return ide_stopped;
	}

631
	debug_log("Retry number - %d\n", pc->retries);
Linus Torvalds's avatar
Linus Torvalds committed
632
633
634

	pc->retries++;
	/* We haven't transferred any data yet */
635
636
637
	pc->xferred = 0;
	pc->cur_pos = pc->buf;
	bcount = min(pc->req_xfer, 63 * 1024);
Linus Torvalds's avatar
Linus Torvalds committed
638

639
640
	if (pc->flags & PC_FLAG_DMA_ERROR) {
		pc->flags &= ~PC_FLAG_DMA_ERROR;
641
		ide_dma_off(drive);
642
	}
643
	dma = 0;
Linus Torvalds's avatar
Linus Torvalds committed
644

645
	if ((pc->flags & PC_FLAG_DMA_RECOMMENDED) && drive->using_dma)
646
		dma = !hwif->dma_ops->dma_setup(drive);
Linus Torvalds's avatar
Linus Torvalds committed
647

648
	ide_pktcmd_tf_load(drive, IDE_TFLAG_OUT_DEVICE, bcount, dma);
Linus Torvalds's avatar
Linus Torvalds committed
649

650
651
	if (dma) {
		/* Begin DMA, if necessary */
652
		pc->flags |= PC_FLAG_DMA_IN_PROGRESS;
653
		hwif->dma_ops->dma_start(drive);
Linus Torvalds's avatar
Linus Torvalds committed
654
655
	}

656
	if (floppy->flags & IDEFLOPPY_FLAG_DRQ_INTERRUPT) {
Linus Torvalds's avatar
Linus Torvalds committed
657
658
		/* Issue the packet command */
		ide_execute_command(drive, WIN_PACKETCMD,
659
				&idefloppy_transfer_pc1,
Linus Torvalds's avatar
Linus Torvalds committed
660
661
662
663
664
				IDEFLOPPY_WAIT_CMD,
				NULL);
		return ide_started;
	} else {
		/* Issue the packet command */
665
		ide_execute_pkt_cmd(drive);
666
		return idefloppy_transfer_pc1(drive);
Linus Torvalds's avatar
Linus Torvalds committed
667
668
669
	}
}

670
static void idefloppy_rw_callback(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
671
{
672
	debug_log("Reached %s\n", __func__);
Linus Torvalds's avatar
Linus Torvalds committed
673

674
	idefloppy_end_request(drive, 1, 0);
Linus Torvalds's avatar
Linus Torvalds committed
675
676
677
	return;
}

678
static void idefloppy_create_prevent_cmd(struct ide_atapi_pc *pc, int prevent)
Linus Torvalds's avatar
Linus Torvalds committed
679
{
680
	debug_log("creating prevent removal command, prevent = %d\n", prevent);
Linus Torvalds's avatar
Linus Torvalds committed
681
682

	idefloppy_init_pc(pc);
683
	pc->c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
Linus Torvalds's avatar
Linus Torvalds committed
684
685
686
	pc->c[4] = prevent;
}

687
static void idefloppy_create_read_capacity_cmd(struct ide_atapi_pc *pc)
Linus Torvalds's avatar
Linus Torvalds committed
688
689
{
	idefloppy_init_pc(pc);
690
	pc->c[0] = GPCMD_READ_FORMAT_CAPACITIES;
Linus Torvalds's avatar
Linus Torvalds committed
691
692
	pc->c[7] = 255;
	pc->c[8] = 255;
693
	pc->req_xfer = 255;
Linus Torvalds's avatar
Linus Torvalds committed
694
695
}

696
697
static void idefloppy_create_format_unit_cmd(struct ide_atapi_pc *pc, int b,
		int l, int flags)
Linus Torvalds's avatar
Linus Torvalds committed
698
699
{
	idefloppy_init_pc(pc);
700
	pc->c[0] = GPCMD_FORMAT_UNIT;
Linus Torvalds's avatar
Linus Torvalds committed
701
702
	pc->c[1] = 0x17;

703
704
	memset(pc->buf, 0, 12);
	pc->buf[1] = 0xA2;
Linus Torvalds's avatar
Linus Torvalds committed
705
706
707
	/* Default format list header, u8 1: FOV/DCRT/IMM bits set */

	if (flags & 1)				/* Verify bit on... */
708
709
		pc->buf[1] ^= 0x20;		/* ... turn off DCRT bit */
	pc->buf[3] = 8;
Linus Torvalds's avatar
Linus Torvalds committed
710

711
712
713
	put_unaligned(cpu_to_be32(b), (unsigned int *)(&pc->buf[4]));
	put_unaligned(cpu_to_be32(l), (unsigned int *)(&pc->buf[8]));
	pc->buf_size = 12;
714
	pc->flags |= PC_FLAG_WRITING;
Linus Torvalds's avatar
Linus Torvalds committed
715
716
}

717
/* A mode sense command is used to "sense" floppy parameters. */
718
719
static void idefloppy_create_mode_sense_cmd(struct ide_atapi_pc *pc,
		u8 page_code, u8 type)
Linus Torvalds's avatar
Linus Torvalds committed
720
{
721
	u16 length = 8; /* sizeof(Mode Parameter Header) = 8 Bytes */
722

Linus Torvalds's avatar
Linus Torvalds committed
723
	idefloppy_init_pc(pc);
724
	pc->c[0] = GPCMD_MODE_SENSE_10;
Linus Torvalds's avatar
Linus Torvalds committed
725
726
727
728
	pc->c[1] = 0;
	pc->c[2] = page_code + (type << 6);

	switch (page_code) {
729
730
731
732
733
734
735
736
	case IDEFLOPPY_CAPABILITIES_PAGE:
		length += 12;
		break;
	case IDEFLOPPY_FLEXIBLE_DISK_PAGE:
		length += 32;
		break;
	default:
		printk(KERN_ERR "ide-floppy: unsupported page code "
Linus Torvalds's avatar
Linus Torvalds committed
737
738
				"in create_mode_sense_cmd\n");
	}
739
	put_unaligned(cpu_to_be16(length), (u16 *) &pc->c[7]);
740
	pc->req_xfer = length;
Linus Torvalds's avatar
Linus Torvalds committed
741
742
}

743
static void idefloppy_create_start_stop_cmd(struct ide_atapi_pc *pc, int start)
Linus Torvalds's avatar
Linus Torvalds committed
744
745
{
	idefloppy_init_pc(pc);
746
	pc->c[0] = GPCMD_START_STOP_UNIT;
Linus Torvalds's avatar
Linus Torvalds committed
747
748
749
	pc->c[4] = start;
}

750
static void idefloppy_create_test_unit_ready_cmd(struct ide_atapi_pc *pc)
Linus Torvalds's avatar
Linus Torvalds committed
751
752
{
	idefloppy_init_pc(pc);
753
	pc->c[0] = GPCMD_TEST_UNIT_READY;
Linus Torvalds's avatar
Linus Torvalds committed
754
755
}

756
static void idefloppy_create_rw_cmd(idefloppy_floppy_t *floppy,
757
				    struct ide_atapi_pc *pc, struct request *rq,
758
				    unsigned long sector)
Linus Torvalds's avatar
Linus Torvalds committed
759
760
761
762
763
{
	int block = sector / floppy->bs_factor;
	int blocks = rq->nr_sectors / floppy->bs_factor;
	int cmd = rq_data_dir(rq);

764
	debug_log("create_rw10_cmd: block == %d, blocks == %d\n",
Linus Torvalds's avatar
Linus Torvalds committed
765
766
767
		block, blocks);

	idefloppy_init_pc(pc);
768
769
	pc->c[0] = cmd == READ ? GPCMD_READ_10 : GPCMD_WRITE_10;
	put_unaligned(cpu_to_be16(blocks), (unsigned short *)&pc->c[7]);
770
	put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[2]);
771

772
	pc->idefloppy_callback = &idefloppy_rw_callback;
Linus Torvalds's avatar
Linus Torvalds committed
773
774
	pc->rq = rq;
	pc->b_count = cmd == READ ? 0 : rq->bio->bi_size;
775
	if (rq->cmd_flags & REQ_RW)
776
		pc->flags |= PC_FLAG_WRITING;
777
778
	pc->buf = NULL;
	pc->req_xfer = pc->buf_size = blocks * floppy->block_size;
779
	pc->flags |= PC_FLAG_DMA_RECOMMENDED;
Linus Torvalds's avatar
Linus Torvalds committed
780
781
}

782
static void idefloppy_blockpc_cmd(idefloppy_floppy_t *floppy,
783
		struct ide_atapi_pc *pc, struct request *rq)
Linus Torvalds's avatar
Linus Torvalds committed
784
785
{
	idefloppy_init_pc(pc);
786
	pc->idefloppy_callback = &idefloppy_rw_callback;
Linus Torvalds's avatar
Linus Torvalds committed
787
	memcpy(pc->c, rq->cmd, sizeof(pc->c));
788
789
790
	pc->rq = rq;
	pc->b_count = rq->data_len;
	if (rq->data_len && rq_data_dir(rq) == WRITE)
791
		pc->flags |= PC_FLAG_WRITING;
792
	pc->buf = rq->data;
793
	if (rq->bio)
794
		pc->flags |= PC_FLAG_DMA_RECOMMENDED;
795
796
797
798
	/*
	 * possibly problematic, doesn't look like ide-floppy correctly
	 * handled scattered requests if dma fails...
	 */
799
	pc->req_xfer = pc->buf_size = rq->data_len;
Linus Torvalds's avatar
Linus Torvalds committed
800
801
}

802
803
static ide_startstop_t idefloppy_do_request(ide_drive_t *drive,
		struct request *rq, sector_t block_s)
Linus Torvalds's avatar
Linus Torvalds committed
804
805
{
	idefloppy_floppy_t *floppy = drive->driver_data;
806
	struct ide_atapi_pc *pc;
Linus Torvalds's avatar
Linus Torvalds committed
807
808
	unsigned long block = (unsigned long)block_s;

809
	debug_log("dev: %s, cmd_type: %x, errors: %d\n",
810
			rq->rq_disk ? rq->rq_disk->disk_name : "?",
811
812
			rq->cmd_type, rq->errors);
	debug_log("sector: %ld, nr_sectors: %ld, "
Linus Torvalds's avatar
Linus Torvalds committed
813
814
815
816
			"current_nr_sectors: %d\n", (long)rq->sector,
			rq->nr_sectors, rq->current_nr_sectors);

	if (rq->errors >= ERROR_MAX) {
817
818
		if (floppy->failed_pc)
			ide_floppy_report_error(floppy, floppy->failed_pc);
Linus Torvalds's avatar
Linus Torvalds committed
819
820
821
		else
			printk(KERN_ERR "ide-floppy: %s: I/O error\n",
				drive->name);
822
		idefloppy_end_request(drive, 0, 0);
Linus Torvalds's avatar
Linus Torvalds committed
823
824
		return ide_stopped;
	}
825
	if (blk_fs_request(rq)) {
Linus Torvalds's avatar
Linus Torvalds committed
826
827
		if (((long)rq->sector % floppy->bs_factor) ||
		    (rq->nr_sectors % floppy->bs_factor)) {
828
829
			printk(KERN_ERR "%s: unsupported r/w request size\n",
					drive->name);
830
			idefloppy_end_request(drive, 0, 0);
Linus Torvalds's avatar
Linus Torvalds committed
831
832
833
834
			return ide_stopped;
		}
		pc = idefloppy_next_pc_storage(drive);
		idefloppy_create_rw_cmd(floppy, pc, rq, block);
835
	} else if (blk_special_request(rq)) {
836
		pc = (struct ide_atapi_pc *) rq->buffer;
837
	} else if (blk_pc_request(rq)) {
Linus Torvalds's avatar
Linus Torvalds committed
838
		pc = idefloppy_next_pc_storage(drive);
839
		idefloppy_blockpc_cmd(floppy, pc, rq);
Linus Torvalds's avatar
Linus Torvalds committed
840
841
842
	} else {
		blk_dump_rq_flags(rq,
			"ide-floppy: unsupported command in queue");
843
		idefloppy_end_request(drive, 0, 0);
Linus Torvalds's avatar
Linus Torvalds committed
844
845
846
847
848
849
850
851
		return ide_stopped;
	}

	pc->rq = rq;
	return idefloppy_issue_pc(drive, pc);
}

/*
852
853
 * Add a special packet command request to the tail of the request queue,
 * and wait for it to be serviced.
Linus Torvalds's avatar
Linus Torvalds committed
854
 */
855
static int idefloppy_queue_pc_tail(ide_drive_t *drive, struct ide_atapi_pc *pc)
Linus Torvalds's avatar
Linus Torvalds committed
856
857
{
	struct ide_floppy_obj *floppy = drive->driver_data;
858
859
	struct request *rq;
	int error;
Linus Torvalds's avatar
Linus Torvalds committed
860

861
862
863
864
865
	rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
	rq->buffer = (char *) pc;
	rq->cmd_type = REQ_TYPE_SPECIAL;
	error = blk_execute_rq(drive->queue, floppy->disk, rq, 0);
	blk_put_request(rq);
Linus Torvalds's avatar
Linus Torvalds committed
866

867
	return error;
Linus Torvalds's avatar
Linus Torvalds committed
868
869
870
}

/*
871
872
 * Look at the flexible disk page parameters. We ignore the CHS capacity
 * parameters and use the LBA parameters instead.
Linus Torvalds's avatar
Linus Torvalds committed
873
 */
874
static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
875
876
{
	idefloppy_floppy_t *floppy = drive->driver_data;
877
	struct ide_atapi_pc pc;
878
	u8 *page;
Linus Torvalds's avatar
Linus Torvalds committed
879
	int capacity, lba_capacity;
880
881
	u16 transfer_rate, sector_size, cyls, rpm;
	u8 heads, sectors;
Linus Torvalds's avatar
Linus Torvalds committed
882

883
884
885
886
887
888
	idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE,
					MODE_SENSE_CURRENT);

	if (idefloppy_queue_pc_tail(drive, &pc)) {
		printk(KERN_ERR "ide-floppy: Can't get flexible disk page"
				" parameters\n");
Linus Torvalds's avatar
Linus Torvalds committed
889
890
		return 1;
	}
891
	floppy->wp = !!(pc.buf[3] & 0x80);
Linus Torvalds's avatar
Linus Torvalds committed
892
	set_disk_ro(floppy->disk, floppy->wp);
893
	page = &pc.buf[8];
894

895
896
897
898
899
900
	transfer_rate = be16_to_cpu(*(u16 *)&pc.buf[8 + 2]);
	sector_size   = be16_to_cpu(*(u16 *)&pc.buf[8 + 6]);
	cyls          = be16_to_cpu(*(u16 *)&pc.buf[8 + 8]);
	rpm           = be16_to_cpu(*(u16 *)&pc.buf[8 + 28]);
	heads         = pc.buf[8 + 4];
	sectors       = pc.buf[8 + 5];
901
902
903
904

	capacity = cyls * heads * sectors * sector_size;

	if (memcmp(page, &floppy->flexible_disk_page, 32))
Linus Torvalds's avatar
Linus Torvalds committed
905
906
		printk(KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, "
				"%d sector size, %d rpm\n",
907
908
909
910
911
912
913
				drive->name, capacity / 1024, cyls, heads,
				sectors, transfer_rate / 8, sector_size, rpm);

	memcpy(&floppy->flexible_disk_page, page, 32);
	drive->bios_cyl = cyls;
	drive->bios_head = heads;
	drive->bios_sect = sectors;
Linus Torvalds's avatar
Linus Torvalds committed
914
	lba_capacity = floppy->blocks * floppy->block_size;
915

Linus Torvalds's avatar
Linus Torvalds committed
916
917
918
919
	if (capacity < lba_capacity) {
		printk(KERN_NOTICE "%s: The disk reports a capacity of %d "
			"bytes, but the drive only handles %d\n",
			drive->name, lba_capacity, capacity);
920
921
		floppy->blocks = floppy->block_size ?
			capacity / floppy->block_size : 0;
Linus Torvalds's avatar
Linus Torvalds committed
922
923
924
925
	}
	return 0;
}

926
static int idefloppy_get_sfrp_bit(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
927
928
{
	idefloppy_floppy_t *floppy = drive->driver_data;
929
	struct ide_atapi_pc pc;
Linus Torvalds's avatar
Linus Torvalds committed
930
931
932
933
934

	floppy->srfp = 0;
	idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_CAPABILITIES_PAGE,
						 MODE_SENSE_CURRENT);

935
	pc.flags |= PC_FLAG_SUPPRESS_ERROR;
936
	if (idefloppy_queue_pc_tail(drive, &pc))
Linus Torvalds's avatar
Linus Torvalds committed
937
938
		return 1;

939
	floppy->srfp = pc.buf[8 + 2] & 0x40;