/**** vi:set ts=8 sts=8 sw=8:************************************************
 *
 *  Copyright (C) 1994-1998,2002  Linus Torvalds and authors:
 *
 *	Mark Lord	<mlord@pobox.com>
 *	Gadi Oxman	<gadio@netvision.net.il>
 *	Andre Hedrick	<andre@linux-ide.org>
 *	Jens Axboe	<axboe@suse.de>
 *	Marcin Dalecki	<martin@dalecki.de>
 *
 * This is the ATA disk device driver, as evolved from hd.c and ide.c.
 */

#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.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/delay.h>
#include <linux/buffer_head.h>		/* for invalidate_bdev() */
#include <linux/hdreg.h>
#include <linux/ide.h>

#include <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#ifdef CONFIG_BLK_DEV_PDC4030
# define IS_PDC4030_DRIVE (drive->channel->chipset == ide_pdc4030)
#else
# define IS_PDC4030_DRIVE (0)	/* auto-NULLs out pdc4030 code */
#endif

/*
 * for now, taskfile requests are special :/
 */
static inline char *ide_map_rq(struct request *rq, unsigned long *flags)
{
	if (rq->bio)
		return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
	else
		return rq->buffer + ((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE;
}

static inline void ide_unmap_rq(struct request *rq, char *to,
				unsigned long *flags)
{
	if (rq->bio)
		bio_kunmap_irq(to, flags);
}

/*
 * Perform a sanity check on the claimed "lba_capacity"
 * value for this drive (from its reported identification information).
 *
 * Returns:	1 if lba_capacity looks sensible
 *		0 otherwise
 *
 * It is called only once for each drive.
 */
static int lba_capacity_is_ok(struct hd_driveid *id)
{
	unsigned long lba_sects, chs_sects, head, tail;

	if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
		printk("48-bit Drive: %llu \n", id->lba_capacity_2);
		return 1;
	}

	/*
	 * The ATA spec tells large drives to return
	 * C/H/S = 16383/16/63 independent of their size.
	 * Some drives can be jumpered to use 15 heads instead of 16.
	 * Some drives can be jumpered to use 4092 cyls instead of 16383.
	 */
	if ((id->cyls == 16383
	     || (id->cyls == 4092 && id->cur_cyls == 16383)) &&
	    id->sectors == 63 &&
	    (id->heads == 15 || id->heads == 16) &&
	    id->lba_capacity >= 16383*63*id->heads)
		return 1;

	lba_sects   = id->lba_capacity;
	chs_sects   = id->cyls * id->heads * id->sectors;

	/* perform a rough sanity check on lba_sects:  within 10% is OK */
	if ((lba_sects - chs_sects) < chs_sects/10)
		return 1;

	/* some drives have the word order reversed */
	head = ((lba_sects >> 16) & 0xffff);
	tail = (lba_sects & 0xffff);
	lba_sects = (head | (tail << 16));
	if ((lba_sects - chs_sects) < chs_sects/10) {
		id->lba_capacity = lba_sects;
		return 1;	/* lba_capacity is (now) good */
	}

	return 0;	/* lba_capacity value may be bad */
}

/*
 * Handler for command with PIO data-in phase.
 */
static ide_startstop_t task_in_intr(struct ata_device *drive, struct request *rq)
{
	int ret;

	if (!ata_status(drive, DATA_READY, BAD_R_STAT)) {
		if (drive->status & (ERR_STAT | DRQ_STAT))
			return ata_error(drive, rq, __FUNCTION__);

		/* no data yet, so wait for another interrupt */
		ata_set_handler(drive, task_in_intr, WAIT_CMD, NULL);

		ret = ATA_OP_CONTINUES;
	} else {
		//	printk("Read: %p, rq->current_nr_sectors: %d\n", buf, (int) rq->current_nr_sectors);
		{
			unsigned long flags;
			char *buf;

			buf = ide_map_rq(rq, &flags);
			ata_read(drive, buf, SECTOR_WORDS);
			ide_unmap_rq(rq, buf, &flags);
		}

		/* First segment of the request is complete. note that this does not
		 * necessarily mean that the entire request is done!! this is only true
		 * if ata_end_request() returns 0.
		 */
		rq->errors = 0;
		--rq->current_nr_sectors;

		if (rq->current_nr_sectors <= 0) {
			if (!ata_end_request(drive, rq, 1, 0)) {
			//		printk("Request Ended stat: %02x\n", drive->status);

				return ATA_OP_FINISHED;
			}
		}

		/* still data left to transfer */
		ata_set_handler(drive, task_in_intr,  WAIT_CMD, NULL);

		ret = ATA_OP_CONTINUES;
	}

	return ret;
}

/*
 * Handler for command with PIO data-out phase.
 */
static ide_startstop_t task_out_intr(struct ata_device *drive, struct request *rq)
{
	int ret;

	if (!ata_status(drive, DRIVE_READY, drive->bad_wstat))
		return ata_error(drive, rq, __FUNCTION__);

	if (!rq->current_nr_sectors && !ata_end_request(drive, rq, 1, 0)) {
		ret = ATA_OP_FINISHED;
	} else {
		if ((rq->nr_sectors == 1) != (drive->status & DRQ_STAT)) {
			unsigned long flags;
			char *buf;

//			printk("write: %p, rq->current_nr_sectors: %d\n", buf, (int) rq->current_nr_sectors);
			buf = ide_map_rq(rq, &flags);
			ata_write(drive, buf, SECTOR_WORDS);
			ide_unmap_rq(rq, buf, &flags);

			rq->errors = 0;
			--rq->current_nr_sectors;
		}
		ata_set_handler(drive, task_out_intr, WAIT_CMD, NULL);

		ret = ATA_OP_CONTINUES;
	}

	return ret;
}

/*
 * Handler for command with Read Multiple
 */
static ide_startstop_t task_mulin_intr(struct ata_device *drive, struct request *rq)
{
	int ret;

	if (!ata_status(drive, DATA_READY, BAD_R_STAT)) {
		if (drive->status & (ERR_STAT | DRQ_STAT))
			return ata_error(drive, rq, __FUNCTION__);

		/* no data yet, so wait for another interrupt */
		ata_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);

		ret = ATA_OP_CONTINUES;
	} else {
		unsigned int msect;

		/* (ks/hs): Fixed Multi-Sector transfer */
		msect = drive->mult_count;

		do {
			unsigned int nsect;

			nsect = rq->current_nr_sectors;
			if (nsect > msect)
				nsect = msect;

#if 0
			printk("Multiread: %p, nsect: %d , rq->current_nr_sectors: %d\n",
					buf, nsect, rq->current_nr_sectors);
#endif
			{
				unsigned long flags;
				char *buf;

				buf = ide_map_rq(rq, &flags);
				ata_read(drive, buf, nsect * SECTOR_WORDS);
				ide_unmap_rq(rq, buf, &flags);
			}

			rq->errors = 0;
			rq->current_nr_sectors -= nsect;

			/* FIXME: this seems buggy */
			if (rq->current_nr_sectors <= 0) {
				if (!ata_end_request(drive, rq, 1, 0))
					return ATA_OP_FINISHED;
			}
			msect -= nsect;
		} while (msect);

		/* more data left */
		ata_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);

		ret = ATA_OP_CONTINUES;
	}

	return ret;
}

static ide_startstop_t task_mulout_intr(struct ata_device *drive, struct request *rq)
{
	int ok;
	int ret;

	/*
	 * FIXME: the drive->status checks here seem to be messy.
	 *
	 * (ks/hs): Handle last IRQ on multi-sector transfer,
	 * occurs after all data was sent in this chunk
	 */

	ok = ata_status(drive, DATA_READY, BAD_R_STAT);

	if (!ok || !rq->nr_sectors) {
		if (drive->status & (ERR_STAT | DRQ_STAT))
			return ata_error(drive, rq, __FUNCTION__);
	}
	if (!rq->nr_sectors) {
		ata_end_request(drive, rq, 1, rq->hard_nr_sectors);
		rq->bio = NULL;
		ret = ATA_OP_FINISHED;
	} else if (!ok) {
		/* not ready yet, so wait for next IRQ */
		ata_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);

		ret = ATA_OP_CONTINUES;
	} else {
		int mcount = drive->mult_count;

		/* prepare for next IRQ */
		ata_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);

		do {
			char *buf;
			int nsect = rq->current_nr_sectors;
			unsigned long flags;

			if (nsect > mcount)
				nsect = mcount;
			mcount -= nsect;

			buf = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
			rq->sector += nsect;
			rq->nr_sectors -= nsect;
			rq->current_nr_sectors -= nsect;

			/* Do we move to the next bio after this? */
			if (!rq->current_nr_sectors) {
				/* remember to fix this up /jens */
				struct bio *bio = rq->bio->bi_next;

				/* end early if we ran out of requests */
				if (!bio) {
					mcount = 0;
				} else {
					rq->bio = bio;
					rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9;
				}
			}
			rq->errors = 0; /* FIXME: why?  --bzolnier */

			/*
			 * Ok, we're all setup for the interrupt re-entering us on the
			 * last transfer.
			 */
			ata_write(drive, buf, nsect * SECTOR_WORDS);
			bio_kunmap_irq(buf, &flags);
		} while (mcount);

		ret = ATA_OP_CONTINUES;
	}

	return ret;
}

/*
 * Issue a READ or WRITE command to a disk, using LBA if supported, or CHS
 * otherwise, to address sectors.  It also takes care of issuing special
 * DRIVE_CMDs.
 */
static ide_startstop_t idedisk_do_request(struct ata_device *drive, struct request *rq, sector_t block)
{
	struct ata_taskfile args;
	struct ata_taskfile *ar;
	struct hd_driveid *id = drive->id;
	u8 cmd;

	/* Special drive commands don't need any kind of setup.
	 */
	if (rq->flags & REQ_SPECIAL) {
		ar = rq->special;
		cmd  = ar->cmd;
	} else  {
		unsigned int sectors;

		/* FIXME: this check doesn't make sense */
		if (!(rq->flags & REQ_CMD)) {
			blk_dump_rq_flags(rq, "idedisk_do_request - bad command");
			ata_end_request(drive, rq, 0, 0);

			return ATA_OP_FINISHED;
		}

		if (IS_PDC4030_DRIVE) {
			extern ide_startstop_t promise_do_request(struct ata_device *, struct request *, sector_t);

			return promise_do_request(drive, rq, block);
		}

		/*
		 * start a tagged operation
		 */
		if (drive->using_tcq) {
			int st = blk_queue_start_tag(&drive->queue, rq);

			if (ata_pending_commands(drive) > drive->max_depth)
				drive->max_depth = ata_pending_commands(drive);
			if (ata_pending_commands(drive) > drive->max_last_depth)
				drive->max_last_depth = ata_pending_commands(drive);

			if (st) {
				BUG_ON(!ata_pending_commands(drive));

				return ATA_OP_CONTINUES;
			}
		}
		ar = &args;

		memset(&args, 0, sizeof(args));
		sectors = rq->nr_sectors;
		/* Dispatch depending up on the drive access method. */
		if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
			/* LBA 48 bit */
			/*
			 * 268435455  == 137439 MB or 28bit limit
			 * 320173056  == 163929 MB or 48bit addressing
			 * 1073741822 == 549756 MB or 48bit addressing fake drive
			 */
			if (sectors == 65536)
				sectors = 0;

			if (blk_rq_tagged(rq)) {
				args.taskfile.feature = sectors;
				args.hobfile.feature = sectors >> 8;
				args.taskfile.sector_count = rq->tag << 3;
			} else {
				args.taskfile.sector_count = sectors;
				args.hobfile.sector_count = sectors >> 8;
			}

			args.taskfile.sector_number = block;		/* low lba */
			args.taskfile.low_cylinder = (block >>= 8);	/* mid lba */
			args.taskfile.high_cylinder = (block >>= 8);	/* hi  lba */
			args.taskfile.device_head = drive->select.all;

			args.hobfile.sector_number = (block >>= 8);	/* low lba */
			args.hobfile.low_cylinder = (block >>= 8);	/* mid lba */
			args.hobfile.high_cylinder = (block >>= 8);	/* hi  lba */
		} else if (drive->select.b.lba) {
			/* LBA 28 bit  */
			if (sectors == 256)
				sectors = 0;

			if (blk_rq_tagged(rq)) {
				args.taskfile.feature = sectors;
				args.taskfile.sector_count = rq->tag << 3;
			} else
				args.taskfile.sector_count = sectors;

			args.taskfile.sector_number = block;
			args.taskfile.low_cylinder = (block >>= 8);
			args.taskfile.high_cylinder = (block >>= 8);
			args.taskfile.device_head = ((block >> 8) & 0x0f);
		} else {
			/* CHS */
			unsigned int track	= (block / drive->sect);
			unsigned int sect	= (block % drive->sect) + 1;
			unsigned int head	= (track % drive->head);
			unsigned int cyl	= (track / drive->head);

			if (sectors == 256)
				sectors = 0;

			if (blk_rq_tagged(rq)) {
				args.taskfile.feature = sectors;
				args.taskfile.sector_count = rq->tag << 3;
			} else
				args.taskfile.sector_count = sectors;

			args.taskfile.sector_number = sect;
			args.taskfile.low_cylinder = cyl;
			args.taskfile.high_cylinder = (cyl>>8);
			args.taskfile.device_head = head;
		}
		args.taskfile.device_head |= drive->select.all;

		/*
		 * Decode with physical ATA command to use and setup associated data.
		 */

		if (rq_data_dir(rq) == READ) {
			args.command_type = IDE_DRIVE_TASK_IN;
			if (drive->addressing) {
				if (drive->using_tcq) {
					cmd = WIN_READDMA_QUEUED_EXT;
				} else if (drive->using_dma) {
					cmd = WIN_READDMA_EXT;
				} else if (drive->mult_count) {
					args.XXX_handler = task_mulin_intr;
					cmd = WIN_MULTREAD_EXT;
				} else {
					args.XXX_handler = task_in_intr;
					cmd = WIN_READ_EXT;
				}
			} else {
				if (drive->using_tcq) {
					cmd = WIN_READDMA_QUEUED;
				} else if (drive->using_dma) {
					cmd = WIN_READDMA;
				} else if (drive->mult_count) {
					args.XXX_handler = task_mulin_intr;
					cmd = WIN_MULTREAD;
				} else {
					args.XXX_handler = task_in_intr;
					cmd = WIN_READ;
				}
			}
		} else {
			args.command_type = IDE_DRIVE_TASK_RAW_WRITE;
			if (drive->addressing) {
				if (drive->using_tcq) {
					cmd = WIN_WRITEDMA_QUEUED_EXT;
				} else if (drive->using_dma) {
					cmd = WIN_WRITEDMA_EXT;
				} else if (drive->mult_count) {
					args.XXX_handler = task_mulout_intr;
					cmd = WIN_MULTWRITE_EXT;
				} else {
					args.XXX_handler = task_out_intr;
					cmd = WIN_WRITE_EXT;
				}
			} else {
				if (drive->using_tcq) {
					cmd = WIN_WRITEDMA_QUEUED;
				} else if (drive->using_dma) {
					cmd = WIN_WRITEDMA;
				} else if (drive->mult_count) {
					args.XXX_handler = task_mulout_intr;
					cmd = WIN_MULTWRITE;
				} else {
					args.XXX_handler = task_out_intr;
					cmd = WIN_WRITE;
				}
			}
		}
#ifdef DEBUG
		printk("%s: %sing: ", drive->name,
				(rq_data_dir(rq)==READ) ? "read" : "writ");
		if (lba)	printk("LBAsect=%lld, ", block);
		else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
		printk("sectors=%ld, ", rq->nr_sectors);
		printk("buffer=%p\n", rq->buffer);
#endif
		ar->cmd = cmd;
		rq->special = ar;
	}

	/* (ks/hs): Moved to start, do not use for multiple out commands.
	 * FIXME: why not?! */
	if (!(cmd == CFA_WRITE_MULTI_WO_ERASE ||
	      cmd == WIN_MULTWRITE ||
	      cmd == WIN_MULTWRITE_EXT)) {
		ata_irq_enable(drive, 1);
		ata_mask(drive);
	}

	if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400) &&
	    (drive->addressing == 1))
		ata_out_regfile(drive, &ar->hobfile);

	ata_out_regfile(drive, &ar->taskfile);

	OUT_BYTE((ar->taskfile.device_head & (drive->addressing ? 0xE0 : 0xEF)) | drive->select.all,
			IDE_SELECT_REG);

	/* FIXME: this is actually distingushing between PIO and DMA requests.
	 */
	if (ar->XXX_handler) {
		if (ar->command_type == IDE_DRIVE_TASK_IN ||
		    ar->command_type == IDE_DRIVE_TASK_NO_DATA) {

			ata_set_handler(drive, ar->XXX_handler, WAIT_CMD, NULL);
			OUT_BYTE(cmd, IDE_COMMAND_REG);

			return ATA_OP_CONTINUES;
		}

		/* FIXME: Warning check for race between handlers for writing
		 * first block of data.  However since we are well inside the
		 * boundaries of the seek, we should be okay.
		 */
		if (ar->command_type == IDE_DRIVE_TASK_RAW_WRITE) {
			ide_startstop_t ret;

			OUT_BYTE(cmd, IDE_COMMAND_REG);

			ret = ata_status_poll(drive, DATA_READY, drive->bad_wstat,
						WAIT_DRQ, rq);
			if (ret != ATA_OP_READY) {
				printk(KERN_ERR "%s: no DRQ after issuing %s\n",
						drive->name, drive->mult_count ? "MULTWRITE" : "WRITE");

				return ret;
			}

			/* FIXME: This doesn't make the slightest sense.
			 * (ks/hs): Fixed Multi Write
			 */
			if (!(cmd == CFA_WRITE_MULTI_WO_ERASE ||
			      cmd == WIN_MULTWRITE ||
			      cmd == WIN_MULTWRITE_EXT)) {
				unsigned long flags;
				char *buf = ide_map_rq(rq, &flags);

				ata_set_handler(drive, ar->XXX_handler, WAIT_CMD, NULL);

				/* For Write_sectors we need to stuff the first sector */
				/* FIXME: what if !rq->current_nr_sectors  --bzolnier */
				ata_write(drive, buf, SECTOR_WORDS);

				rq->current_nr_sectors--;
				ide_unmap_rq(rq, buf, &flags);

				return ATA_OP_CONTINUES;
			} else {
				int i;

				/* Polling wait until the drive is ready.
				 *
				 * Stuff the first sector(s) by calling the
				 * handler driectly therafter.
				 *
				 * FIXME: Replace hard-coded 100, what about
				 * error handling?
				 *
				 * FIXME: Whatabout the IRE clearing and not clearing case?!
				 */

				for (i = 0; i < 100; ++i) {
					if (ata_status_irq(drive))
						break;
				}
				if (!ata_status_irq(drive)) {
					/* We are compleatly missing an error
					 * return path here.
					 * FIXME: We have only one? -alat
					 */
					printk(KERN_ERR "DISASTER WAITING TO HAPPEN! Try to Stop it!\n");
					return ata_error(drive, rq, __FUNCTION__);
				}

				/* will set handler for us */
				return ar->XXX_handler(drive, rq);
			}
		}
	} else {
		/*
		 * FIXME: This is a gross hack, need to unify tcq dma proc and
		 * regular dma proc. It should now be easier.
		 *
		 * FIXME: Handle the alternateives by a command type.
		 */

		/* FIXME: ATA_OP_CONTINUES?  --bzolnier */
		/* Not started a request - BUG() ot ATA_OP_FINISHED to avoid lockup ? - alat*/
		if (!drive->using_dma)
			return ATA_OP_CONTINUES;

		/* for dma commands we don't set the handler */
		if (cmd == WIN_WRITEDMA ||
		    cmd == WIN_WRITEDMA_EXT ||
		    cmd == WIN_READDMA ||
		    cmd == WIN_READDMA_EXT)
			return udma_init(drive, rq);
#ifdef CONFIG_BLK_DEV_IDE_TCQ
		else if (cmd == WIN_WRITEDMA_QUEUED ||
			 cmd == WIN_WRITEDMA_QUEUED_EXT ||
			 cmd == WIN_READDMA_QUEUED ||
			 cmd == WIN_READDMA_QUEUED_EXT)
			return udma_tcq_init(drive, rq);
#endif
		else {
			printk(KERN_ERR "%s: unknown command %x\n",
					__FUNCTION__, cmd);

			return ATA_OP_FINISHED;
		}
	}

	/* not reached */
	return ATA_OP_CONTINUES;
}

static int idedisk_open(struct inode *inode, struct file *__fp, struct ata_device *drive)
{
	MOD_INC_USE_COUNT;
	if (drive->removable && drive->usage == 1) {
		check_disk_change(inode->i_rdev);

		/*
		 * Ignore the return code from door_lock, since the open() has
		 * already succeeded once, and the door_lock is irrelevant at this
		 * time.
		 */
		if (drive->doorlocking) {
			struct ata_taskfile args;

			memset(&args, 0, sizeof(args));
			args.cmd = WIN_DOORLOCK;
			if (ide_raw_taskfile(drive, &args, NULL))
				drive->doorlocking = 0;
		}
	}

	return 0;
}

static int flush_cache(struct ata_device *drive)
{
	struct ata_taskfile args;

	memset(&args, 0, sizeof(args));

	if (drive->id->cfs_enable_2 & 0x2400)
		args.cmd = WIN_FLUSH_CACHE_EXT;
	else
		args.cmd = WIN_FLUSH_CACHE;

	return ide_raw_taskfile(drive, &args, NULL);
}

static void idedisk_release(struct inode *inode, struct file *filp, struct ata_device *drive)
{
	if (drive->removable && !drive->usage) {
		/* XXX I don't think this is up to the lowlevel drivers..  --hch */
		invalidate_bdev(inode->i_bdev, 0);

		if (drive->doorlocking) {
			struct ata_taskfile args;

			memset(&args, 0, sizeof(args));
			args.cmd = WIN_DOORUNLOCK;
			if (ide_raw_taskfile(drive, &args, NULL))
				drive->doorlocking = 0;
		}
	}
	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
		if (flush_cache(drive))
			printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
				drive->name);
	MOD_DEC_USE_COUNT;
}

static int idedisk_check_media_change(struct ata_device *drive)
{
	/* if removable, always assume it was changed */
	return drive->removable;
}

static sector_t idedisk_capacity(struct ata_device *drive)
{
	return drive->capacity - drive->sect0;
}

/*
 * This is tightly woven into the driver->special can not touch.
 * DON'T do it again until a total personality rewrite is committed.
 */
static int set_multcount(struct ata_device *drive, int arg)
{
	struct ata_taskfile args;

	/* Setting multi mode count on this channel type is not supported/not
	 * handled.
	 */
	if (IS_PDC4030_DRIVE)
		return -EIO;

	/* Hugh, we still didn't detect the devices capabilities.
	 */
	if (!drive->id)
		return -EIO;

	if (arg > drive->id->max_multsect)
		arg = drive->id->max_multsect;

	memset(&args, 0, sizeof(args));
	args.taskfile.sector_count = arg;
	args.cmd = WIN_SETMULT;
	if (!ide_raw_taskfile(drive, &args, NULL)) {
		/* all went well track this setting as valid */
		drive->mult_count = arg;

		return 0;
	} else
		drive->mult_count = 0; /* reset */

	return -EIO;
}

static int set_nowerr(struct ata_device *drive, int arg)
{
	drive->nowerr = arg;
	drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;

	return 0;
}

static int write_cache(struct ata_device *drive, int arg)
{
	struct ata_taskfile args;

	if (!(drive->id->cfs_enable_2 & 0x3000))
		return 1;

	memset(&args, 0, sizeof(args));
	args.taskfile.feature	= (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
	args.cmd = WIN_SETFEATURES;
	ide_raw_taskfile(drive, &args, NULL);

	drive->wcache = arg;

	return 0;
}

static int idedisk_standby(struct ata_device *drive)
{
	struct ata_taskfile args;

	memset(&args, 0, sizeof(args));
	args.cmd = WIN_STANDBYNOW1;
	return ide_raw_taskfile(drive, &args, NULL);
}

static int set_acoustic(struct ata_device *drive, int arg)
{
	struct ata_taskfile args;

	memset(&args, 0, sizeof(args));
	args.taskfile.feature = (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM;
	args.taskfile.sector_count = arg;
	args.cmd = WIN_SETFEATURES;
	ide_raw_taskfile(drive, &args, NULL);

	drive->acoustic = arg;

	return 0;
}

#ifdef CONFIG_BLK_DEV_IDE_TCQ
static int set_using_tcq(struct ata_device *drive, int arg)
{
	if (!drive->driver)
		return -EPERM;

	if (!drive->channel->udma_setup)
		return -EPERM;

	if (arg == drive->queue_depth && drive->using_tcq)
		return 0;

	/*
	 * set depth, but check also id for max supported depth
	 */
	drive->queue_depth = arg ? arg : 1;
	if (drive->id) {
		if (drive->queue_depth > drive->id->queue_depth + 1)
			drive->queue_depth = drive->id->queue_depth + 1;
	}

	if (udma_tcq_enable(drive, arg))
		return -EIO;

	return 0;
}
#endif

static int probe_lba_addressing(struct ata_device *drive, int arg)
{
	drive->addressing =  0;

	if (!(drive->id->cfs_enable_2 & 0x0400))
                return -EIO;

	drive->addressing = arg;
	return 0;
}

static int set_lba_addressing(struct ata_device *drive, int arg)
{
	return (probe_lba_addressing(drive, arg));
}

static int idedisk_suspend(struct device *dev, u32 state, u32 level)
{
	struct ata_device *drive = dev->driver_data;

	/* I hope that every freeze operations from the upper levels have
	 * already been done...
	 */

	BUG_ON(in_interrupt());

	if (level != SUSPEND_SAVE_STATE)
		return 0;

	/* wait until all commands are finished */
	/* FIXME: waiting for spinlocks should be done instead. */
	while (drive->channel->handler)
		yield();

	/* set the drive to standby */
	printk(KERN_INFO "suspending: %s ", drive->name);
	if (ata_ops(drive)) {
		if (ata_ops(drive)->standby)
			ata_ops(drive)->standby(drive);
	}
	drive->blocked = 1;

	return 0;
}

static int idedisk_resume(struct device *dev, u32 level)
{
	struct ata_device *drive = dev->driver_data;

	if (level != RESUME_RESTORE_STATE)
		return 0;
	if (!drive->blocked)
		panic("ide: Resume but not suspended?\n");

	drive->blocked = 0;
	return 0;
}


/* This is just a hook for the overall driver tree.
 */

static struct device_driver disk_devdrv = {
	.lock = RW_LOCK_UNLOCKED,
	.suspend = idedisk_suspend,
	.resume = idedisk_resume,
};

/*
 * Queries for true maximum capacity of the drive.
 * Returns maximum LBA address (> 0) of the drive, 0 if failed.
 */
static unsigned long native_max_address(struct ata_device *drive)
{
	struct ata_taskfile args;
	unsigned long addr = 0;

	if (!(drive->id->command_set_1 & 0x0400) &&
	    !(drive->id->cfs_enable_2 & 0x0100))
		return addr;

	/* Create IDE/ATA command request structure */
	memset(&args, 0, sizeof(args));
	args.taskfile.device_head = 0x40;
	args.cmd = WIN_READ_NATIVE_MAX;
	ide_raw_taskfile(drive, &args, NULL);

	/* if OK, compute maximum address value */
	if (!(drive->status & ERR_STAT)) {
		addr = ((args.taskfile.device_head & 0x0f) << 24)
		     | (args.taskfile.high_cylinder << 16)
		     | (args.taskfile.low_cylinder <<  8)
		     | args.taskfile.sector_number;
	}

	addr++;	/* since the return value is (maxlba - 1), we add 1 */

	return addr;
}

static u64 native_max_address_ext(struct ata_device *drive)
{
	struct ata_taskfile args;
	u64 addr = 0;

	/* Create IDE/ATA command request structure */
	memset(&args, 0, sizeof(args));
	args.taskfile.device_head = 0x40;
	args.cmd = WIN_READ_NATIVE_MAX_EXT;
        ide_raw_taskfile(drive, &args, NULL);

	/* if OK, compute maximum address value */
	if (!(drive->status & ERR_STAT)) {
		u32 high = (args.hobfile.high_cylinder << 16) |
			   (args.hobfile.low_cylinder << 8) |
			    args.hobfile.sector_number;
		u32 low  = (args.taskfile.high_cylinder << 16) |
			   (args.taskfile.low_cylinder << 8) |
			    args.taskfile.sector_number;
		addr = ((u64)high << 24) | low;
	}

	addr++;	/* since the return value is (maxlba - 1), we add 1 */

	return addr;
}

#ifdef CONFIG_IDEDISK_STROKE
/*
 * Sets maximum virtual LBA address of the drive.
 * Returns new maximum virtual LBA address (> 0) or 0 on failure.
 */
static sector_t set_max_address(struct ata_device *drive, sector_t addr_req)
{
	struct ata_taskfile args;
	sector_t addr_set = 0;

	addr_req--;
	/* Create IDE/ATA command request structure */
	memset(&args, 0, sizeof(args));

	args.taskfile.sector_number = (addr_req >> 0);
	args.taskfile.low_cylinder = (addr_req >> 8);
	args.taskfile.high_cylinder = (addr_req >> 16);

	args.taskfile.device_head = ((addr_req >> 24) & 0x0f) | 0x40;
	args.cmd = WIN_SET_MAX;
	ide_raw_taskfile(drive, &args, NULL);

	/* if OK, read new maximum address value */
	if (!(drive->status & ERR_STAT)) {
		addr_set = ((args.taskfile.device_head & 0x0f) << 24)
			 | (args.taskfile.high_cylinder << 16)
			 | (args.taskfile.low_cylinder <<  8)
			 | args.taskfile.sector_number;
	}
	addr_set++;
	return addr_set;
}

static u64 set_max_address_ext(struct ata_device *drive, u64 addr_req)
{
	struct ata_taskfile args;
	u64 addr_set = 0;

	addr_req--;
	/* Create IDE/ATA command request structure */
	memset(&args, 0, sizeof(args));

	args.taskfile.sector_number = (addr_req >>  0);
	args.taskfile.low_cylinder = (addr_req >>= 8);
	args.taskfile.high_cylinder = (addr_req >>= 8);
	args.taskfile.device_head = 0x40;
	args.cmd = WIN_SET_MAX_EXT;

	args.hobfile.sector_number = (addr_req >>= 8);
	args.hobfile.low_cylinder = (addr_req >>= 8);
	args.hobfile.high_cylinder = (addr_req >>= 8);
	args.hobfile.device_head = 0x40;

	ide_raw_taskfile(drive, &args, NULL);

	/* if OK, compute maximum address value */
	if (!(drive->status & ERR_STAT)) {
		u32 high = (args.hobfile.high_cylinder << 16) |
			   (args.hobfile.low_cylinder << 8) |
			    args.hobfile.sector_number;
		u32 low  = (args.taskfile.high_cylinder << 16) |
			   (args.taskfile.low_cylinder << 8) |
			    args.taskfile.sector_number;
		addr_set = ((u64)high << 24) | low;
	}
	return addr_set;
}

#endif

static void idedisk_setup(struct ata_device *drive)
{
	int i;

	struct hd_driveid *id = drive->id;
	sector_t capacity;
	sector_t set_max;
	int drvid = -1;
	struct ata_channel *ch = drive->channel;

	if (id == NULL)
		return;

	/*
	 * CompactFlash cards and their brethern look just like hard drives
	 * to us, but they are removable and don't have a doorlock mechanism.
	 */
	if (drive->removable && !drive_is_flashcard(drive)) {
		/* Removable disks (eg. SYQUEST); ignore 'WD' drives.
		 */
		if (!strncmp(id->model, "WD", 2))
			drive->doorlocking = 1;
	}

	for (i = 0; i < MAX_DRIVES; ++i) {
		if (drive != &ch->drives[i])
		    continue;
		drvid = i;
		ch->gd->de_arr[i] = drive->de;
		if (drive->removable)
			ch->gd->flags[i] |= GENHD_FL_REMOVABLE;
		break;
	}

	/* Register us within the device tree.
	 */
	if (drvid != -1) {
		sprintf(drive->dev.bus_id, "sd@%x,%x", ch->unit, drvid);
		strcpy(drive->dev.name, "ATA-Disk");
		drive->dev.driver = &disk_devdrv;
		drive->dev.parent = &ch->dev;
		drive->dev.driver_data = drive;
		device_register(&drive->dev);
	}

	/* Extract geometry if we did not already have one for the drive */
	if (!drive->cyl || !drive->head || !drive->sect) {
		drive->cyl     = drive->bios_cyl  = id->cyls;
		drive->head    = drive->bios_head = id->heads;
		drive->sect    = drive->bios_sect = id->sectors;
	}

	/* Handle logical geometry translation by the drive. */
	if ((id->field_valid & 1) && id->cur_cyls &&
	    id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
		drive->cyl  = id->cur_cyls;
		drive->head = id->cur_heads;
		drive->sect = id->cur_sectors;
	}

	/* Use physical geometry if what we have still makes no sense. */
	if (drive->head > 16 && id->heads && id->heads <= 16) {
		drive->cyl  = id->cyls;
		drive->head = id->heads;
		drive->sect = id->sectors;
	}

	/* Calculate drive capacity, and select LBA if possible.
	 * drive->id != NULL is spected
	 *
	 * To compute capacity, this uses either of
	 *
	 *    1. CHS value set by user       (whatever user sets will be trusted)
	 *    2. LBA value from target drive (require new ATA feature)
	 *    3. LBA value from system BIOS  (new one is OK, old one may break)
	 *    4. CHS value from system BIOS  (traditional style)
	 *
	 * in above order (i.e., if value of higher priority is available,
	 * reset will be ignored).
	 */
	capacity = drive->cyl * drive->head * drive->sect;
	set_max = native_max_address(drive);

	drive->capacity = 0;
	drive->select.b.lba = 0;

	if (id->cfs_enable_2 & 0x0400) {
		u64 set_max_ext;
		u64 capacity_2;
		capacity_2 = capacity;
		capacity_2 = id->lba_capacity_2;

		drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect);
		drive->head = drive->bios_head = 255;
		drive->sect = drive->bios_sect = 63;

		drive->select.b.lba = 1;
		set_max_ext = native_max_address_ext(drive);
		if (set_max_ext > capacity_2) {
#ifdef CONFIG_IDEDISK_STROKE
			set_max_ext = native_max_address_ext(drive);
			set_max_ext = set_max_address_ext(drive, set_max_ext);
			if (set_max_ext) {
				drive->capacity = capacity_2 = set_max_ext;
				drive->cyl = (unsigned int) set_max_ext / (drive->head * drive->sect);
				drive->select.b.lba = 1;
				drive->id->lba_capacity_2 = capacity_2;
                        }
#else
			printk("%s: setmax_ext LBA %llu, native  %llu\n",
				drive->name,
			       (long long) set_max_ext,
			       (long long) capacity_2);
#endif
		}
		drive->bios_cyl	= drive->cyl;
		drive->capacity	= capacity_2;
	} else {

		/*
		 * Determine capacity, and use LBA if the drive properly
		 * supports it.
		 */

		if ((id->capability & 2) && lba_capacity_is_ok(id)) {
			capacity = id->lba_capacity;
			drive->cyl = capacity / (drive->head * drive->sect);
			drive->select.b.lba = 1;
		}

		if (set_max > capacity) {
#ifdef CONFIG_IDEDISK_STROKE
			set_max = native_max_address(drive);
			set_max = set_max_address(drive, set_max);
			if (set_max) {
				drive->capacity = capacity = set_max;
				drive->cyl = set_max / (drive->head * drive->sect);
				drive->select.b.lba = 1;
				drive->id->lba_capacity = capacity;
			}
#else
			printk("%s: setmax LBA %lu, native  %lu\n",
					drive->name, set_max, capacity);
#endif
		}

		drive->capacity = capacity;

		if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
			drive->capacity = id->lba_capacity_2;
			drive->head = 255;
			drive->sect = 63;
			drive->cyl = (unsigned long)(drive->capacity) / (drive->head * drive->sect);
		}
	}

	/*
	 * If possible, give fdisk access to more of the drive,
	 * by correcting bios_cyls:
	 */
	capacity = idedisk_capacity(drive);
	if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) &&
	    (!drive->forced_geom) && drive->bios_sect && drive->bios_head)
		drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
	printk(KERN_INFO " %s: %ld sectors", drive->name, capacity);

#if 0
	/* Right now we avoid this calculation, since it can result in the
	 * usage of not supported compiler internal functions on 32 bit hosts.
	 * However since the calculation appears to be an interesting piece of
	 * number theory let's preserve the formula here.
	 */

	/* Give size in megabytes (MB), not mebibytes (MiB).
	 * We compute the exact rounded value, avoiding overflow.
	 */
	printk(" (%ld MB)", (capacity - capacity/625 + 974)/1950);
#endif

	/* Only print cache size when it was specified.
	 */
	if (id->buf_size)
		printk (" w/%dKiB Cache", id->buf_size/2);

	printk(", CHS=%d/%d/%d",
	       drive->bios_cyl, drive->bios_head, drive->bios_sect);
#ifdef CONFIG_BLK_DEV_IDEDMA
	if (drive->using_dma)
		udma_print(drive);
#endif
	printk("\n");

	drive->mult_count = 0;
#if 0
	if (id->max_multsect) {

		/* FIXME: reenable this again after making it to use
		 * the same code path as the ioctl stuff.
		 */

#ifdef CONFIG_IDEDISK_MULTI_MODE
		id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;
		id->multsect_valid = id->multsect ? 1 : 0;
		drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT;
		if (drive->mult_req)
			drive->special_cmd |= ATA_SPECIAL_MMODE;
#else
		/* original, pre IDE-NFG, per request of AC */
		drive->mult_req = INITIAL_MULT_COUNT;
		if (drive->mult_req > id->max_multsect)
			drive->mult_req = id->max_multsect;
		if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
			drive->special_cmd |= ATA_SPECIAL_MMODE;
#endif
	}
#endif

	/* FIXME: Nowadays there are many chipsets out there which *require* 32
	 * bit IO. Those will most propably not work properly with drives not
	 * supporting this. But right now we don't do anything about this. We
	 * dont' even *warn* the user!
	 */

	drive->channel->no_io_32bit = id->dword_io ? 1 : 0;

	if (drive->id->cfs_enable_2 & 0x3000)
		write_cache(drive, (id->cfs_enable_2 & 0x3000));

	probe_lba_addressing(drive, 1);
}

static int idedisk_cleanup(struct ata_device *drive)
{
	int ret;

	if (!drive)
	    return 0;

	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache) {
		if (flush_cache(drive))
			printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
				drive->name);
	}
	ret = ata_unregister_device(drive);

	/* FIXME: This is killing the kernel with BUG 185 at asm/spinlocks.h
	 * horribly.  Check whatever we did REGISTER the device properly
	 * in front?
	 */
#if 0
	put_device(&drive->device);
#endif

	return ret;
}

static int idedisk_ioctl(struct ata_device *drive,
		struct inode *inode, struct file *__fp,
		unsigned int cmd, unsigned long arg)
{
	struct hd_driveid *id = drive->id;

	switch (cmd) {
		case HDIO_GET_ADDRESS: {
			unsigned long val = drive->addressing;

			if (put_user(val, (unsigned long *) arg))
				return -EFAULT;
			return 0;
		}

		case HDIO_SET_ADDRESS: {
			int val;

			if (arg < 0 || arg > 2)
				return -EINVAL;

			if (ide_spin_wait_hwgroup(drive))
				return -EBUSY;

			val = set_lba_addressing(drive, arg);
			spin_unlock_irq(drive->channel->lock);

			return val;
		}

		case HDIO_GET_MULTCOUNT: {
			unsigned long val = drive->mult_count & 0xFF;

			if (put_user(val, (unsigned long *) arg))
				return -EFAULT;
			return 0;
		}

		case HDIO_SET_MULTCOUNT: {
			int val;

			if (!id)
				return -EBUSY;

			if (arg < 0 || arg > (id ? id->max_multsect : 0))
				return -EINVAL;

			val = set_multcount(drive, arg);

			return val;
		}

		case HDIO_GET_NOWERR: {
			unsigned long val = drive->nowerr;

			if (put_user(val, (unsigned long *) arg))
				return -EFAULT;

			return 0;
		}

		case HDIO_SET_NOWERR: {
			int val;

			if (arg < 0 || arg > 1)
				return -EINVAL;

			val = set_nowerr(drive, arg);

			return val;
		}

		case HDIO_GET_WCACHE: {
			unsigned long val = drive->wcache;

			if (put_user(val, (unsigned long *) arg))
				return -EFAULT;

			return 0;
		}

		case HDIO_SET_WCACHE: {
			int val;

			if (arg < 0 || arg > 1)
				return -EINVAL;

			val = write_cache(drive, arg);

			return val;
		}

		case HDIO_GET_ACOUSTIC: {
			unsigned long val = drive->acoustic;

			if (put_user(val, (u8 *) arg))
				return -EFAULT;
			return 0;
		}

		case HDIO_SET_ACOUSTIC: {
			int val;

			if (arg < 0 || arg > 254)
				return -EINVAL;

			val = set_acoustic(drive, arg);

			return val;
		}

#ifdef CONFIG_BLK_DEV_IDE_TCQ
		case HDIO_GET_QDMA: {
			/* Foolup hdparm 0 means off 1 on -alat */
			/* FIXME: hdparm have only -Q do we need something like:
			 * hdparm -q 1/0 - TCQ on/off
			 * hdparm -Q 1-MAX - TCQ queue_depth ?
			 */
			u8 val = ( drive->using_tcq ?  drive->queue_depth : 0 );

			if (put_user(val, (u8 *) arg))
				return -EFAULT;

			return 0;
		}

		case HDIO_SET_QDMA: {
			int val;

			if (arg < 0 || arg > IDE_MAX_TAG)
				return -EINVAL;

			if (ide_spin_wait_hwgroup(drive))
				return -EBUSY;

			val = set_using_tcq(drive, arg);
			spin_unlock_irq(drive->channel->lock);

			return val;
		}
#endif
		default:
			return -EINVAL;
	}
}

static void idedisk_attach(struct ata_device *drive);

/*
 * Subdriver functions.
 */
static struct ata_operations idedisk_driver = {
	.owner =		THIS_MODULE,
	.attach =		idedisk_attach,
	.cleanup =		idedisk_cleanup,
	.standby =		idedisk_standby,
	.do_request =		idedisk_do_request,
	.end_request =		NULL,
	.ioctl =		idedisk_ioctl,
	.open =			idedisk_open,
	.release =		idedisk_release,
	.check_media_change =	idedisk_check_media_change,
	.revalidate =		NULL, /* use default method */
	.capacity =		idedisk_capacity,
};

static void idedisk_attach(struct ata_device *drive)
{
	char *req;
	struct ata_channel *channel;
	int unit;

	if (drive->type != ATA_DISK)
		return;

	req = drive->driver_req;
	if (req[0] != '\0' && strcmp(req, "ide-disk"))
		return;

	if (ata_register_device(drive, &idedisk_driver)) {
		printk(KERN_ERR "%s: Failed to register the driver with ide.c\n", drive->name);
		return;
	}

	idedisk_setup(drive);
	if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
		printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
		idedisk_cleanup(drive);
		return;
	}

	channel = drive->channel;
	unit = drive - channel->drives;

	ata_revalidate(mk_kdev(channel->major, unit << PARTN_BITS));
}

static void __exit idedisk_exit(void)
{
	unregister_ata_driver(&idedisk_driver);
}

int __init idedisk_init(void)
{
	return ata_driver_module(&idedisk_driver);
}

module_init(idedisk_init);
module_exit(idedisk_exit);

MODULE_DESCRIPTION("ATA DISK Driver");
MODULE_LICENSE("GPL");