/*
       * linux/drivers/block/ide-features.c	Version 0.04	June 9, 2000
       *
       *  Copyright (C) 1999-2000	Linus Torvalds & authors (see below)
       *  
       *  Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
       *
       *  Extracts if ide.c to address the evolving transfer rate code for
       *  the SETFEATURES_XFER callouts.  Various parts of any given function
       *  are credited to previous ATA-IDE maintainers.
       *
       *  Auto-CRC downgrade for Ultra DMA(ing)
       *
       *  May be copied or modified under the terms of the GNU General Public License
       */
      
      #include <linux/config.h>
      #define __NO_VERSION__
      #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/blkpg.h>
      #include <linux/malloc.h>
      #include <linux/pci.h>
      #include <linux/delay.h>
      #include <linux/hdreg.h>
      #include <linux/ide.h>
      
      #include <asm/byteorder.h>
      #include <asm/irq.h>
      #include <asm/uaccess.h>
      #include <asm/io.h>
      #include <asm/bitops.h>
      
      /*
       * A Verbose noise maker for debugging on the attempted transfer rates.
       */
  45  char *ide_xfer_verbose (byte xfer_rate)
      {
  47  	switch(xfer_rate) {
  48  		case XFER_UDMA_7:	return("UDMA 7");
  49  		case XFER_UDMA_6:	return("UDMA 6");
  50  		case XFER_UDMA_5:	return("UDMA 5");
  51  		case XFER_UDMA_4:	return("UDMA 4");
  52  		case XFER_UDMA_3:	return("UDMA 3");
  53  		case XFER_UDMA_2:	return("UDMA 2");
  54  		case XFER_UDMA_1:	return("UDMA 1");
  55  		case XFER_UDMA_0:	return("UDMA 0");
  56  		case XFER_MW_DMA_2:	return("MW DMA 2");
  57  		case XFER_MW_DMA_1:	return("MW DMA 1");
  58  		case XFER_MW_DMA_0:	return("MW DMA 0");
  59  		case XFER_SW_DMA_2:	return("SW DMA 2");
  60  		case XFER_SW_DMA_1:	return("SW DMA 1");
  61  		case XFER_SW_DMA_0:	return("SW DMA 0");
  62  		case XFER_PIO_4:	return("PIO 4");
  63  		case XFER_PIO_3:	return("PIO 3");
  64  		case XFER_PIO_2:	return("PIO 2");
  65  		case XFER_PIO_1:	return("PIO 1");
  66  		case XFER_PIO_0:	return("PIO 0");
  67  		case XFER_PIO_SLOW:	return("PIO SLOW");
  68  		default:		return("XFER ERROR");
      	}
      }
      
      /*
       *
       */
  75  char *ide_media_verbose (ide_drive_t *drive)
      {
  77  	switch (drive->media) {
  78  		case ide_scsi:		return("scsi   ");
  79  		case ide_disk:		return("disk   ");
  80  		case ide_optical:	return("optical");
  81  		case ide_cdrom:		return("cdrom  ");
  82  		case ide_tape:		return("tape   ");
  83  		case ide_floppy:	return("floppy ");
  84  		default:		return("???????");
      	}
      }
      
      /*
       * A Verbose noise maker for debugging on the attempted dmaing calls.
       */
  91  char *ide_dmafunc_verbose (ide_dma_action_t dmafunc)
      {
  93  	switch (dmafunc) {
  94  		case ide_dma_read:		return("ide_dma_read");
  95  		case ide_dma_write:		return("ide_dma_write");
  96  		case ide_dma_begin:		return("ide_dma_begin");
  97  		case ide_dma_end:		return("ide_dma_end:");
  98  		case ide_dma_check:		return("ide_dma_check");
  99  		case ide_dma_on:		return("ide_dma_on");
 100  		case ide_dma_off:		return("ide_dma_off");
 101  		case ide_dma_off_quietly:	return("ide_dma_off_quietly");
 102  		case ide_dma_test_irq:		return("ide_dma_test_irq");
 103  		case ide_dma_bad_drive:		return("ide_dma_bad_drive");
 104  		case ide_dma_good_drive:	return("ide_dma_good_drive");
 105  		case ide_dma_verbose:		return("ide_dma_verbose");
 106  		case ide_dma_retune:		return("ide_dma_retune");
 107  		case ide_dma_lostirq:		return("ide_dma_lostirq");
 108  		case ide_dma_timeout:		return("ide_dma_timeout");
 109  		default:			return("unknown");
      	}
      }
      
      /*
       *
       */
 116  byte ide_auto_reduce_xfer (ide_drive_t *drive)
      {
 118  	if (!drive->crc_count)
 119  		return drive->current_speed;
      	drive->crc_count = 0;
      
 122  	switch(drive->current_speed) {
 123  		case XFER_UDMA_7:	return XFER_UDMA_6;
 124  		case XFER_UDMA_6:	return XFER_UDMA_5;
 125  		case XFER_UDMA_5:	return XFER_UDMA_4;
 126  		case XFER_UDMA_4:	return XFER_UDMA_3;
 127  		case XFER_UDMA_3:	return XFER_UDMA_2;
 128  		case XFER_UDMA_2:	return XFER_UDMA_1;
 129  		case XFER_UDMA_1:	return XFER_UDMA_0;
 130  		case XFER_UDMA_0:
 131  			if (drive->id->dma_mword & 0x0004) return XFER_MW_DMA_2;
 132  			else if (drive->id->dma_mword & 0x0002) return XFER_MW_DMA_1;
 133  			else if (drive->id->dma_mword & 0x0001) return XFER_MW_DMA_0;
 134  			else return XFER_PIO_4;
 135  		case XFER_MW_DMA_2:	return XFER_MW_DMA_1;
 136  		case XFER_MW_DMA_1:	return XFER_MW_DMA_0;
 137  		case XFER_MW_DMA_0:
 138  			if (drive->id->dma_1word & 0x0004) return XFER_SW_DMA_2;
 139  			else if (drive->id->dma_1word & 0x0002) return XFER_SW_DMA_1;
 140  			else if (drive->id->dma_1word & 0x0001) return XFER_SW_DMA_0;
 141  			else return XFER_PIO_4;
 142  		case XFER_SW_DMA_2:	return XFER_SW_DMA_1;
 143  		case XFER_SW_DMA_1:	return XFER_SW_DMA_0;
 144  		case XFER_SW_DMA_0:
      			{
 146  				return XFER_PIO_4;
      			}
 148  		case XFER_PIO_4:	return XFER_PIO_3;
 149  		case XFER_PIO_3:	return XFER_PIO_2;
 150  		case XFER_PIO_2:	return XFER_PIO_1;
 151  		case XFER_PIO_1:	return XFER_PIO_0;
 152  		case XFER_PIO_0:
 153  		default:		return XFER_PIO_SLOW;
      	}
      }
      
      /*
       * Update the 
       */
 160  int ide_driveid_update (ide_drive_t *drive)
      {
      	/*
      	 * Re-read drive->id for possible DMA mode
      	 * change (copied from ide-probe.c)
      	 */
      	struct hd_driveid *id;
      	unsigned long timeout, flags;
      
 169  	SELECT_MASK(HWIF(drive), drive, 1);
 170  	if (IDE_CONTROL_REG)
      		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
      	ide_delay_50ms();
      	OUT_BYTE(WIN_IDENTIFY, IDE_COMMAND_REG);
      	timeout = jiffies + WAIT_WORSTCASE;
 175  	do {
 176  		if (0 < (signed long)(jiffies - timeout)) {
 177  			SELECT_MASK(HWIF(drive), drive, 0);
 178  			return 0;	/* drive timed-out */
      		}
      		ide_delay_50ms();	/* give drive a breather */
 181  	} while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT);
      	ide_delay_50ms();	/* wait for IRQ and DRQ_STAT */
 183  	if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
 184  		SELECT_MASK(HWIF(drive), drive, 0);
      		printk("%s: CHECK for good STATUS\n", drive->name);
 186  		return 0;
      	}
      	__save_flags(flags);	/* local CPU only */
      	__cli();		/* local CPU only; some systems need this */
 190  	SELECT_MASK(HWIF(drive), drive, 0);
      	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
      	ide_input_data(drive, id, SECTOR_WORDS);
      	(void) GET_STAT();	/* clear drive IRQ */
      	ide__sti();		/* local CPU only */
      	__restore_flags(flags);	/* local CPU only */
 196  	ide_fix_driveid(id);
 197  	if (id) {
      		drive->id->dma_ultra = id->dma_ultra;
      		drive->id->dma_mword = id->dma_mword;
      		drive->id->dma_1word = id->dma_1word;
      		/* anything more ? */
      		kfree(id);
      	}
      
 205  	return 1;
      }
      
      /*
       * Verify that we are doing an approved SETFEATURES_XFER with respect
       * to the hardware being able to support request.  Since some hardware
       * can improperly report capabilties, we check to see if the host adapter
       * in combination with the device (usually a disk) properly detect
       * and acknowledge each end of the ribbon.
       */
 215  int ide_ata66_check (ide_drive_t *drive, byte cmd, byte nsect, byte feature)
      {
      	if ((cmd == WIN_SETFEATURES) &&
      	    (nsect > XFER_UDMA_2) &&
 219  	    (feature == SETFEATURES_XFER)) {
 220  		if (!HWIF(drive)->udma_four) {
      			printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", HWIF(drive)->name);
 222  			return 1;
      		}
      #ifndef CONFIG_IDEDMA_IVB
 225  		if ((drive->id->hw_config & 0x6000) == 0) {
      #else /* !CONFIG_IDEDMA_IVB */
      		if (((drive->id->hw_config & 0x2000) == 0) ||
      		    ((drive->id->hw_config & 0x4000) == 0)) {
      #endif /* CONFIG_IDEDMA_IVB */
      			printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", drive->name);
 231  			return 1;
      		}
      	}
 234  	return 0;
      }
      
      /*
       * Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER.
       * 1 : Safe to update drive->id DMA registers.
       * 0 : OOPs not allowed.
       */
 242  int set_transfer (ide_drive_t *drive, byte cmd, byte nsect, byte feature)
      {
      	if ((cmd == WIN_SETFEATURES) &&
      	    (nsect >= XFER_SW_DMA_0) &&
      	    (feature == SETFEATURES_XFER) &&
      	    (drive->id->dma_ultra ||
      	     drive->id->dma_mword ||
 249  	     drive->id->dma_1word))
 250  		return 1;
      
 252  	return 0;
      }
      
      /*
       *  All hosts that use the 80c ribbon mus use!
       */
 258  byte eighty_ninty_three (ide_drive_t *drive)
      {
      	return ((byte) ((HWIF(drive)->udma_four) &&
      #ifndef CONFIG_IDEDMA_IVB
      			(drive->id->hw_config & 0x4000) &&
      #endif /* CONFIG_IDEDMA_IVB */
 264  			(drive->id->hw_config & 0x6000)) ? 1 : 0);
      }
      
      /*
       * Similar to ide_wait_stat(), except it never calls ide_error internally.
       * This is a kludge to handle the new ide_config_drive_speed() function,
       * and should not otherwise be used anywhere.  Eventually, the tuneproc's
       * should be updated to return ide_startstop_t, in which case we can get
       * rid of this abomination again.  :)   -ml
       *
       * It is gone..........
       *
       * const char *msg == consider adding for verbose errors.
       */
 278  int ide_config_drive_speed (ide_drive_t *drive, byte speed)
      {
      	ide_hwif_t *hwif = HWIF(drive);
      	int	i, error = 1;
      	byte stat;
      
      #if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
      	byte unit = (drive->select.b.unit & 0x01);
      	outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2);
      #endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
      
      	/*
      	 * Don't use ide_wait_cmd here - it will
      	 * attempt to set_geometry and recalibrate,
      	 * but for some reason these don't work at
      	 * this point (lost interrupt).
      	 */
              /*
               * Select the drive, and issue the SETFEATURES command
               */
      	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
      	udelay(1);
 300  	SELECT_DRIVE(HWIF(drive), drive);
 301  	SELECT_MASK(HWIF(drive), drive, 0);
      	udelay(1);
 303  	if (IDE_CONTROL_REG)
      		OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
      	OUT_BYTE(speed, IDE_NSECTOR_REG);
      	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
      	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
 308  	if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
      		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
      	udelay(1);
      	/*
      	 * Wait for drive to become non-BUSY
      	 */
 314  	if ((stat = GET_STAT()) & BUSY_STAT) {
      		unsigned long flags, timeout;
      		__save_flags(flags);	/* local CPU only */
      		ide__sti();		/* local CPU only -- for jiffies */
      		timeout = jiffies + WAIT_CMD;
 319  		while ((stat = GET_STAT()) & BUSY_STAT) {
 320  			if (0 < (signed long)(jiffies - timeout))
 321  				break;
      		}
      		__restore_flags(flags); /* local CPU only */
      	}
      
      	/*
      	 * Allow status to settle, then read it again.
      	 * A few rare drives vastly violate the 400ns spec here,
      	 * so we'll wait up to 10usec for a "good" status
      	 * rather than expensively fail things immediately.
      	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
      	 */
 333  	for (i = 0; i < 10; i++) {
      		udelay(1);
 335  		if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
      			error = 0;
 337  			break;
      		}
      	}
      
 341  	SELECT_MASK(HWIF(drive), drive, 0);
      
      	enable_irq(hwif->irq);
      
 345  	if (error) {
      		(void) ide_dump_status(drive, "set_drive_speed_status", stat);
 347  		return error;
      	}
      
      	drive->id->dma_ultra &= ~0xFF00;
      	drive->id->dma_mword &= ~0x0F00;
      	drive->id->dma_1word &= ~0x0F00;
      
      #if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
      	if (speed > XFER_PIO_4) {
      		outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2);
      	} else {
      		outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2);
      	}
      #endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
      
 362  	switch(speed) {
 363  		case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
 364  		case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
 365  		case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
 366  		case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
 367  		case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
 368  		case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
 369  		case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
 370  		case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
 371  		case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
 372  		case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
 373  		case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
 374  		case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
 375  		case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
 376  		case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
 377  		default: break;
      	}
 379  	return error;
      }
      
      EXPORT_SYMBOL(ide_auto_reduce_xfer);
      EXPORT_SYMBOL(ide_driveid_update);
      EXPORT_SYMBOL(ide_ata66_check);
      EXPORT_SYMBOL(set_transfer);
      EXPORT_SYMBOL(eighty_ninty_three);
      EXPORT_SYMBOL(ide_config_drive_speed);