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) {
441 442
				printk(KERN_ERR "%s: I/O error in request sense"
						" command\n", drive->name);
Linus Torvalds's avatar
Linus Torvalds committed
443 444 445 446 447 448 449 450 451 452 453
				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;
460 461
		printk(KERN_ERR "%s: The device wants to issue more interrupts "
				"in DMA mode\n", drive->name);
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 "%s: CoD != 0 in %s\n", drive->name, __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
		/* Hopefully, we will never get here */
478 479 480
		printk(KERN_ERR "%s: We wanted to %s, but the device wants us "
				"to %s!\n", drive->name,
				(ireason & IO) ? "Write" : "Read",
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) {
489 490 491 492
				printk(KERN_ERR "%s: The device wants to send "
						"us more data than expected - "
						"discarding data\n",
						drive->name);
493
				ide_pad_transfer(drive, 0, bcount);
494

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

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

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

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

/*
526 527 528 529
 * 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
530
 *
531 532 533
 * 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
534
 */
535
static int idefloppy_transfer_pc2(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
536 537 538 539
{
	idefloppy_floppy_t *floppy = drive->driver_data;

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

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

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

	if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
556 557
		printk(KERN_ERR "%s: Strange, packet command initiated yet "
				"DRQ isn't asserted\n", drive->name);
Linus Torvalds's avatar
Linus Torvalds committed
558 559
		return startstop;
	}
560
	ireason = hwif->INB(hwif->io_ports.nsect_addr);
561
	if ((ireason & CD) == 0 || (ireason & IO)) {
562 563
		printk(KERN_ERR "%s: (IO,CoD) != (0,1) while issuing "
				"a packet command\n", drive->name);
Linus Torvalds's avatar
Linus Torvalds committed
564 565
		return ide_do_reset(drive);
	}
566
	/*
Linus Torvalds's avatar
Linus Torvalds committed
567 568 569 570 571 572 573
	 * 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.
	 */
574 575 576 577 578 579 580 581 582 583 584 585 586
	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);
587

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

697 698
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
699 700
{
	idefloppy_init_pc(pc);
701
	pc->c[0] = GPCMD_FORMAT_UNIT;
Linus Torvalds's avatar
Linus Torvalds committed
702 703
	pc->c[1] = 0x17;

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

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

712 713 714
	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;
715
	pc->flags |= PC_FLAG_WRITING;
Linus Torvalds's avatar
Linus Torvalds committed
716 717
}

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

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

	switch (page_code) {
730 731 732 733 734 735 736 737
	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
738 739
				"in create_mode_sense_cmd\n");
	}
740
	put_unaligned(cpu_to_be16(length), (u16 *) &pc->c[7]);
741
	pc->req_xfer = length;
Linus Torvalds's avatar
Linus Torvalds committed
742 743
}

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

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

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

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

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

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

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

803 804
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
805 806
{
	idefloppy_floppy_t *floppy = drive->driver_data;
807
	struct ide_atapi_pc *pc;
Linus Torvalds's avatar
Linus Torvalds committed
808 809
	unsigned long block = (unsigned long)block_s;

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

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

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

/*
853 854
 * 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
855
 */
856
static int idefloppy_queue_pc_tail(ide_drive_t *drive, struct ide_atapi_pc *pc)
Linus Torvalds's avatar
Linus Torvalds committed
857 858
{
	struct ide_floppy_obj *floppy = drive->driver_data;
859 860
	struct request *rq;
	int error;
Linus Torvalds's avatar
Linus Torvalds committed
861

862 863 864 865 866
	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
867

868
	return error;