18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci *  IDE DMA support (including IDE PCI BM-DMA).
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *  Copyright (C) 1995-1998   Mark Lord
58c2ecf20Sopenharmony_ci *  Copyright (C) 1999-2000   Andre Hedrick <andre@linux-ide.org>
68c2ecf20Sopenharmony_ci *  Copyright (C) 2004, 2007  Bartlomiej Zolnierkiewicz
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci *  May be copied or modified under the terms of the GNU General Public License
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *  DMA is supported for all IDE devices (disk drives, cdroms, tapes, floppies).
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci/*
148c2ecf20Sopenharmony_ci *  Special Thanks to Mark for his Six years of work.
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/*
188c2ecf20Sopenharmony_ci * Thanks to "Christopher J. Reimer" <reimer@doe.carleton.ca> for
198c2ecf20Sopenharmony_ci * fixing the problem with the BIOS on some Acer motherboards.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * Thanks to "Benoit Poulot-Cazajous" <poulot@chorus.fr> for testing
228c2ecf20Sopenharmony_ci * "TX" chipset compatibility and for providing patches for the "TX" chipset.
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * Thanks to Christian Brunner <chb@muc.de> for taking a good first crack
258c2ecf20Sopenharmony_ci * at generic DMA -- his patches were referred to when preparing this code.
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci * Most importantly, thanks to Robert Bringman <rob@mars.trion.com>
288c2ecf20Sopenharmony_ci * for supplying a Promise UDMA board & WD UDMA drive for this work!
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include <linux/types.h>
328c2ecf20Sopenharmony_ci#include <linux/gfp.h>
338c2ecf20Sopenharmony_ci#include <linux/kernel.h>
348c2ecf20Sopenharmony_ci#include <linux/export.h>
358c2ecf20Sopenharmony_ci#include <linux/ide.h>
368c2ecf20Sopenharmony_ci#include <linux/scatterlist.h>
378c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic const struct drive_list_entry drive_whitelist[] = {
408c2ecf20Sopenharmony_ci	{ "Micropolis 2112A"	,       NULL		},
418c2ecf20Sopenharmony_ci	{ "CONNER CTMA 4000"	,       NULL		},
428c2ecf20Sopenharmony_ci	{ "CONNER CTT8000-A"	,       NULL		},
438c2ecf20Sopenharmony_ci	{ "ST34342A"		,	NULL		},
448c2ecf20Sopenharmony_ci	{ NULL			,	NULL		}
458c2ecf20Sopenharmony_ci};
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic const struct drive_list_entry drive_blacklist[] = {
488c2ecf20Sopenharmony_ci	{ "WDC AC11000H"	,	NULL 		},
498c2ecf20Sopenharmony_ci	{ "WDC AC22100H"	,	NULL 		},
508c2ecf20Sopenharmony_ci	{ "WDC AC32500H"	,	NULL 		},
518c2ecf20Sopenharmony_ci	{ "WDC AC33100H"	,	NULL 		},
528c2ecf20Sopenharmony_ci	{ "WDC AC31600H"	,	NULL 		},
538c2ecf20Sopenharmony_ci	{ "WDC AC32100H"	,	"24.09P07"	},
548c2ecf20Sopenharmony_ci	{ "WDC AC23200L"	,	"21.10N21"	},
558c2ecf20Sopenharmony_ci	{ "Compaq CRD-8241B"	,	NULL 		},
568c2ecf20Sopenharmony_ci	{ "CRD-8400B"		,	NULL 		},
578c2ecf20Sopenharmony_ci	{ "CRD-8480B",			NULL 		},
588c2ecf20Sopenharmony_ci	{ "CRD-8482B",			NULL 		},
598c2ecf20Sopenharmony_ci	{ "CRD-84"		,	NULL 		},
608c2ecf20Sopenharmony_ci	{ "SanDisk SDP3B"	,	NULL 		},
618c2ecf20Sopenharmony_ci	{ "SanDisk SDP3B-64"	,	NULL 		},
628c2ecf20Sopenharmony_ci	{ "SANYO CD-ROM CRD"	,	NULL 		},
638c2ecf20Sopenharmony_ci	{ "HITACHI CDR-8"	,	NULL 		},
648c2ecf20Sopenharmony_ci	{ "HITACHI CDR-8335"	,	NULL 		},
658c2ecf20Sopenharmony_ci	{ "HITACHI CDR-8435"	,	NULL 		},
668c2ecf20Sopenharmony_ci	{ "Toshiba CD-ROM XM-6202B"	,	NULL 		},
678c2ecf20Sopenharmony_ci	{ "TOSHIBA CD-ROM XM-1702BC",	NULL 		},
688c2ecf20Sopenharmony_ci	{ "CD-532E-A"		,	NULL 		},
698c2ecf20Sopenharmony_ci	{ "E-IDE CD-ROM CR-840",	NULL 		},
708c2ecf20Sopenharmony_ci	{ "CD-ROM Drive/F5A",	NULL 		},
718c2ecf20Sopenharmony_ci	{ "WPI CDD-820",		NULL 		},
728c2ecf20Sopenharmony_ci	{ "SAMSUNG CD-ROM SC-148C",	NULL 		},
738c2ecf20Sopenharmony_ci	{ "SAMSUNG CD-ROM SC",	NULL 		},
748c2ecf20Sopenharmony_ci	{ "ATAPI CD-ROM DRIVE 40X MAXIMUM",	NULL 		},
758c2ecf20Sopenharmony_ci	{ "_NEC DV5800A",               NULL            },
768c2ecf20Sopenharmony_ci	{ "SAMSUNG CD-ROM SN-124",	"N001" },
778c2ecf20Sopenharmony_ci	{ "Seagate STT20000A",		NULL  },
788c2ecf20Sopenharmony_ci	{ "CD-ROM CDR_U200",		"1.09" },
798c2ecf20Sopenharmony_ci	{ NULL			,	NULL		}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci};
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci/**
848c2ecf20Sopenharmony_ci *	ide_dma_intr	-	IDE DMA interrupt handler
858c2ecf20Sopenharmony_ci *	@drive: the drive the interrupt is for
868c2ecf20Sopenharmony_ci *
878c2ecf20Sopenharmony_ci *	Handle an interrupt completing a read/write DMA transfer on an
888c2ecf20Sopenharmony_ci *	IDE device
898c2ecf20Sopenharmony_ci */
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ciide_startstop_t ide_dma_intr(ide_drive_t *drive)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
948c2ecf20Sopenharmony_ci	struct ide_cmd *cmd = &hwif->cmd;
958c2ecf20Sopenharmony_ci	u8 stat = 0, dma_stat = 0;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	drive->waiting_for_dma = 0;
988c2ecf20Sopenharmony_ci	dma_stat = hwif->dma_ops->dma_end(drive);
998c2ecf20Sopenharmony_ci	ide_dma_unmap_sg(drive, cmd);
1008c2ecf20Sopenharmony_ci	stat = hwif->tp_ops->read_status(hwif);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	if (OK_STAT(stat, DRIVE_READY, drive->bad_wstat | ATA_DRQ)) {
1038c2ecf20Sopenharmony_ci		if (!dma_stat) {
1048c2ecf20Sopenharmony_ci			if ((cmd->tf_flags & IDE_TFLAG_FS) == 0)
1058c2ecf20Sopenharmony_ci				ide_finish_cmd(drive, cmd, stat);
1068c2ecf20Sopenharmony_ci			else
1078c2ecf20Sopenharmony_ci				ide_complete_rq(drive, BLK_STS_OK,
1088c2ecf20Sopenharmony_ci						blk_rq_sectors(cmd->rq) << 9);
1098c2ecf20Sopenharmony_ci			return ide_stopped;
1108c2ecf20Sopenharmony_ci		}
1118c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: %s: bad DMA status (0x%02x)\n",
1128c2ecf20Sopenharmony_ci			drive->name, __func__, dma_stat);
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci	return ide_error(drive, "dma_intr", stat);
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ciint ide_dma_good_drive(ide_drive_t *drive)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	return ide_in_drive_list(drive->id, drive_whitelist);
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci/**
1238c2ecf20Sopenharmony_ci *	ide_dma_map_sg	-	map IDE scatter gather for DMA I/O
1248c2ecf20Sopenharmony_ci *	@drive: the drive to map the DMA table for
1258c2ecf20Sopenharmony_ci *	@cmd: command
1268c2ecf20Sopenharmony_ci *
1278c2ecf20Sopenharmony_ci *	Perform the DMA mapping magic necessary to access the source or
1288c2ecf20Sopenharmony_ci *	target buffers of a request via DMA.  The lower layers of the
1298c2ecf20Sopenharmony_ci *	kernel provide the necessary cache management so that we can
1308c2ecf20Sopenharmony_ci *	operate in a portable fashion.
1318c2ecf20Sopenharmony_ci */
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic int ide_dma_map_sg(ide_drive_t *drive, struct ide_cmd *cmd)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
1368c2ecf20Sopenharmony_ci	struct scatterlist *sg = hwif->sg_table;
1378c2ecf20Sopenharmony_ci	int i;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	if (cmd->tf_flags & IDE_TFLAG_WRITE)
1408c2ecf20Sopenharmony_ci		cmd->sg_dma_direction = DMA_TO_DEVICE;
1418c2ecf20Sopenharmony_ci	else
1428c2ecf20Sopenharmony_ci		cmd->sg_dma_direction = DMA_FROM_DEVICE;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	i = dma_map_sg(hwif->dev, sg, cmd->sg_nents, cmd->sg_dma_direction);
1458c2ecf20Sopenharmony_ci	if (i) {
1468c2ecf20Sopenharmony_ci		cmd->orig_sg_nents = cmd->sg_nents;
1478c2ecf20Sopenharmony_ci		cmd->sg_nents = i;
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return i;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci/**
1548c2ecf20Sopenharmony_ci *	ide_dma_unmap_sg	-	clean up DMA mapping
1558c2ecf20Sopenharmony_ci *	@drive: The drive to unmap
1568c2ecf20Sopenharmony_ci *
1578c2ecf20Sopenharmony_ci *	Teardown mappings after DMA has completed. This must be called
1588c2ecf20Sopenharmony_ci *	after the completion of each use of ide_build_dmatable and before
1598c2ecf20Sopenharmony_ci *	the next use of ide_build_dmatable. Failure to do so will cause
1608c2ecf20Sopenharmony_ci *	an oops as only one mapping can be live for each target at a given
1618c2ecf20Sopenharmony_ci *	time.
1628c2ecf20Sopenharmony_ci */
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_civoid ide_dma_unmap_sg(ide_drive_t *drive, struct ide_cmd *cmd)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	dma_unmap_sg(hwif->dev, hwif->sg_table, cmd->orig_sg_nents,
1698c2ecf20Sopenharmony_ci		     cmd->sg_dma_direction);
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_dma_unmap_sg);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci/**
1748c2ecf20Sopenharmony_ci *	ide_dma_off_quietly	-	Generic DMA kill
1758c2ecf20Sopenharmony_ci *	@drive: drive to control
1768c2ecf20Sopenharmony_ci *
1778c2ecf20Sopenharmony_ci *	Turn off the current DMA on this IDE controller.
1788c2ecf20Sopenharmony_ci */
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_civoid ide_dma_off_quietly(ide_drive_t *drive)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	drive->dev_flags &= ~IDE_DFLAG_USING_DMA;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	drive->hwif->dma_ops->dma_host_set(drive, 0);
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ide_dma_off_quietly);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci/**
1898c2ecf20Sopenharmony_ci *	ide_dma_off	-	disable DMA on a device
1908c2ecf20Sopenharmony_ci *	@drive: drive to disable DMA on
1918c2ecf20Sopenharmony_ci *
1928c2ecf20Sopenharmony_ci *	Disable IDE DMA for a device on this IDE controller.
1938c2ecf20Sopenharmony_ci *	Inform the user that DMA has been disabled.
1948c2ecf20Sopenharmony_ci */
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_civoid ide_dma_off(ide_drive_t *drive)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	printk(KERN_INFO "%s: DMA disabled\n", drive->name);
1998c2ecf20Sopenharmony_ci	ide_dma_off_quietly(drive);
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ide_dma_off);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci/**
2048c2ecf20Sopenharmony_ci *	ide_dma_on		-	Enable DMA on a device
2058c2ecf20Sopenharmony_ci *	@drive: drive to enable DMA on
2068c2ecf20Sopenharmony_ci *
2078c2ecf20Sopenharmony_ci *	Enable IDE DMA for a device on this IDE controller.
2088c2ecf20Sopenharmony_ci */
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_civoid ide_dma_on(ide_drive_t *drive)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	drive->dev_flags |= IDE_DFLAG_USING_DMA;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	drive->hwif->dma_ops->dma_host_set(drive, 1);
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ciint __ide_dma_bad_drive(ide_drive_t *drive)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	u16 *id = drive->id;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	int blacklist = ide_in_drive_list(id, drive_blacklist);
2228c2ecf20Sopenharmony_ci	if (blacklist) {
2238c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: Disabling (U)DMA for %s (blacklisted)\n",
2248c2ecf20Sopenharmony_ci				    drive->name, (char *)&id[ATA_ID_PROD]);
2258c2ecf20Sopenharmony_ci		return blacklist;
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci	return 0;
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ide_dma_bad_drive);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic const u8 xfer_mode_bases[] = {
2328c2ecf20Sopenharmony_ci	XFER_UDMA_0,
2338c2ecf20Sopenharmony_ci	XFER_MW_DMA_0,
2348c2ecf20Sopenharmony_ci	XFER_SW_DMA_0,
2358c2ecf20Sopenharmony_ci};
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	u16 *id = drive->id;
2408c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
2418c2ecf20Sopenharmony_ci	const struct ide_port_ops *port_ops = hwif->port_ops;
2428c2ecf20Sopenharmony_ci	unsigned int mask = 0;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	switch (base) {
2458c2ecf20Sopenharmony_ci	case XFER_UDMA_0:
2468c2ecf20Sopenharmony_ci		if ((id[ATA_ID_FIELD_VALID] & 4) == 0)
2478c2ecf20Sopenharmony_ci			break;
2488c2ecf20Sopenharmony_ci		mask = id[ATA_ID_UDMA_MODES];
2498c2ecf20Sopenharmony_ci		if (port_ops && port_ops->udma_filter)
2508c2ecf20Sopenharmony_ci			mask &= port_ops->udma_filter(drive);
2518c2ecf20Sopenharmony_ci		else
2528c2ecf20Sopenharmony_ci			mask &= hwif->ultra_mask;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci		/*
2558c2ecf20Sopenharmony_ci		 * avoid false cable warning from eighty_ninty_three()
2568c2ecf20Sopenharmony_ci		 */
2578c2ecf20Sopenharmony_ci		if (req_mode > XFER_UDMA_2) {
2588c2ecf20Sopenharmony_ci			if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
2598c2ecf20Sopenharmony_ci				mask &= 0x07;
2608c2ecf20Sopenharmony_ci		}
2618c2ecf20Sopenharmony_ci		break;
2628c2ecf20Sopenharmony_ci	case XFER_MW_DMA_0:
2638c2ecf20Sopenharmony_ci		mask = id[ATA_ID_MWDMA_MODES];
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci		/* Also look for the CF specific MWDMA modes... */
2668c2ecf20Sopenharmony_ci		if (ata_id_is_cfa(id) && (id[ATA_ID_CFA_MODES] & 0x38)) {
2678c2ecf20Sopenharmony_ci			u8 mode = ((id[ATA_ID_CFA_MODES] & 0x38) >> 3) - 1;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci			mask |= ((2 << mode) - 1) << 3;
2708c2ecf20Sopenharmony_ci		}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci		if (port_ops && port_ops->mdma_filter)
2738c2ecf20Sopenharmony_ci			mask &= port_ops->mdma_filter(drive);
2748c2ecf20Sopenharmony_ci		else
2758c2ecf20Sopenharmony_ci			mask &= hwif->mwdma_mask;
2768c2ecf20Sopenharmony_ci		break;
2778c2ecf20Sopenharmony_ci	case XFER_SW_DMA_0:
2788c2ecf20Sopenharmony_ci		mask = id[ATA_ID_SWDMA_MODES];
2798c2ecf20Sopenharmony_ci		if (!(mask & ATA_SWDMA2) && (id[ATA_ID_OLD_DMA_MODES] >> 8)) {
2808c2ecf20Sopenharmony_ci			u8 mode = id[ATA_ID_OLD_DMA_MODES] >> 8;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci			/*
2838c2ecf20Sopenharmony_ci			 * if the mode is valid convert it to the mask
2848c2ecf20Sopenharmony_ci			 * (the maximum allowed mode is XFER_SW_DMA_2)
2858c2ecf20Sopenharmony_ci			 */
2868c2ecf20Sopenharmony_ci			if (mode <= 2)
2878c2ecf20Sopenharmony_ci				mask = (2 << mode) - 1;
2888c2ecf20Sopenharmony_ci		}
2898c2ecf20Sopenharmony_ci		mask &= hwif->swdma_mask;
2908c2ecf20Sopenharmony_ci		break;
2918c2ecf20Sopenharmony_ci	default:
2928c2ecf20Sopenharmony_ci		BUG();
2938c2ecf20Sopenharmony_ci		break;
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	return mask;
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci/**
3008c2ecf20Sopenharmony_ci *	ide_find_dma_mode	-	compute DMA speed
3018c2ecf20Sopenharmony_ci *	@drive: IDE device
3028c2ecf20Sopenharmony_ci *	@req_mode: requested mode
3038c2ecf20Sopenharmony_ci *
3048c2ecf20Sopenharmony_ci *	Checks the drive/host capabilities and finds the speed to use for
3058c2ecf20Sopenharmony_ci *	the DMA transfer.  The speed is then limited by the requested mode.
3068c2ecf20Sopenharmony_ci *
3078c2ecf20Sopenharmony_ci *	Returns 0 if the drive/host combination is incapable of DMA transfers
3088c2ecf20Sopenharmony_ci *	or if the requested mode is not a DMA mode.
3098c2ecf20Sopenharmony_ci */
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ciu8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
3148c2ecf20Sopenharmony_ci	unsigned int mask;
3158c2ecf20Sopenharmony_ci	int x, i;
3168c2ecf20Sopenharmony_ci	u8 mode = 0;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	if (drive->media != ide_disk) {
3198c2ecf20Sopenharmony_ci		if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA)
3208c2ecf20Sopenharmony_ci			return 0;
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(xfer_mode_bases); i++) {
3248c2ecf20Sopenharmony_ci		if (req_mode < xfer_mode_bases[i])
3258c2ecf20Sopenharmony_ci			continue;
3268c2ecf20Sopenharmony_ci		mask = ide_get_mode_mask(drive, xfer_mode_bases[i], req_mode);
3278c2ecf20Sopenharmony_ci		x = fls(mask) - 1;
3288c2ecf20Sopenharmony_ci		if (x >= 0) {
3298c2ecf20Sopenharmony_ci			mode = xfer_mode_bases[i] + x;
3308c2ecf20Sopenharmony_ci			break;
3318c2ecf20Sopenharmony_ci		}
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if (hwif->chipset == ide_acorn && mode == 0) {
3358c2ecf20Sopenharmony_ci		/*
3368c2ecf20Sopenharmony_ci		 * is this correct?
3378c2ecf20Sopenharmony_ci		 */
3388c2ecf20Sopenharmony_ci		if (ide_dma_good_drive(drive) &&
3398c2ecf20Sopenharmony_ci		    drive->id[ATA_ID_EIDE_DMA_TIME] < 150)
3408c2ecf20Sopenharmony_ci			mode = XFER_MW_DMA_1;
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	mode = min(mode, req_mode);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	printk(KERN_INFO "%s: %s mode selected\n", drive->name,
3468c2ecf20Sopenharmony_ci			  mode ? ide_xfer_verbose(mode) : "no DMA");
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	return mode;
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_cistatic int ide_tune_dma(ide_drive_t *drive)
3528c2ecf20Sopenharmony_ci{
3538c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
3548c2ecf20Sopenharmony_ci	u8 speed;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (ata_id_has_dma(drive->id) == 0 ||
3578c2ecf20Sopenharmony_ci	    (drive->dev_flags & IDE_DFLAG_NODMA))
3588c2ecf20Sopenharmony_ci		return 0;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	/* consult the list of known "bad" drives */
3618c2ecf20Sopenharmony_ci	if (__ide_dma_bad_drive(drive))
3628c2ecf20Sopenharmony_ci		return 0;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
3658c2ecf20Sopenharmony_ci		return config_drive_for_dma(drive);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	speed = ide_max_dma_mode(drive);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	if (!speed)
3708c2ecf20Sopenharmony_ci		return 0;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	if (ide_set_dma_mode(drive, speed))
3738c2ecf20Sopenharmony_ci		return 0;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	return 1;
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic int ide_dma_check(ide_drive_t *drive)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	if (ide_tune_dma(drive))
3838c2ecf20Sopenharmony_ci		return 0;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	/* TODO: always do PIO fallback */
3868c2ecf20Sopenharmony_ci	if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
3878c2ecf20Sopenharmony_ci		return -1;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	ide_set_max_pio(drive);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	return -1;
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ciint ide_set_dma(ide_drive_t *drive)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	int rc;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	/*
3998c2ecf20Sopenharmony_ci	 * Force DMAing for the beginning of the check.
4008c2ecf20Sopenharmony_ci	 * Some chipsets appear to do interesting
4018c2ecf20Sopenharmony_ci	 * things, if not checked and cleared.
4028c2ecf20Sopenharmony_ci	 *   PARANOIA!!!
4038c2ecf20Sopenharmony_ci	 */
4048c2ecf20Sopenharmony_ci	ide_dma_off_quietly(drive);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	rc = ide_dma_check(drive);
4078c2ecf20Sopenharmony_ci	if (rc)
4088c2ecf20Sopenharmony_ci		return rc;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	ide_dma_on(drive);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	return 0;
4138c2ecf20Sopenharmony_ci}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_civoid ide_check_dma_crc(ide_drive_t *drive)
4168c2ecf20Sopenharmony_ci{
4178c2ecf20Sopenharmony_ci	u8 mode;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	ide_dma_off_quietly(drive);
4208c2ecf20Sopenharmony_ci	drive->crc_count = 0;
4218c2ecf20Sopenharmony_ci	mode = drive->current_speed;
4228c2ecf20Sopenharmony_ci	/*
4238c2ecf20Sopenharmony_ci	 * Don't try non Ultra-DMA modes without iCRC's.  Force the
4248c2ecf20Sopenharmony_ci	 * device to PIO and make the user enable SWDMA/MWDMA modes.
4258c2ecf20Sopenharmony_ci	 */
4268c2ecf20Sopenharmony_ci	if (mode > XFER_UDMA_0 && mode <= XFER_UDMA_7)
4278c2ecf20Sopenharmony_ci		mode--;
4288c2ecf20Sopenharmony_ci	else
4298c2ecf20Sopenharmony_ci		mode = XFER_PIO_4;
4308c2ecf20Sopenharmony_ci	ide_set_xfer_rate(drive, mode);
4318c2ecf20Sopenharmony_ci	if (drive->current_speed >= XFER_SW_DMA_0)
4328c2ecf20Sopenharmony_ci		ide_dma_on(drive);
4338c2ecf20Sopenharmony_ci}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_civoid ide_dma_lost_irq(ide_drive_t *drive)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	printk(KERN_ERR "%s: DMA interrupt recovery\n", drive->name);
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_dma_lost_irq);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci/*
4428c2ecf20Sopenharmony_ci * un-busy the port etc, and clear any pending DMA status. we want to
4438c2ecf20Sopenharmony_ci * retry the current request in pio mode instead of risking tossing it
4448c2ecf20Sopenharmony_ci * all away
4458c2ecf20Sopenharmony_ci */
4468c2ecf20Sopenharmony_ciide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
4498c2ecf20Sopenharmony_ci	const struct ide_dma_ops *dma_ops = hwif->dma_ops;
4508c2ecf20Sopenharmony_ci	struct ide_cmd *cmd = &hwif->cmd;
4518c2ecf20Sopenharmony_ci	ide_startstop_t ret = ide_stopped;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	/*
4548c2ecf20Sopenharmony_ci	 * end current dma transaction
4558c2ecf20Sopenharmony_ci	 */
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	if (error < 0) {
4588c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: DMA timeout error\n", drive->name);
4598c2ecf20Sopenharmony_ci		drive->waiting_for_dma = 0;
4608c2ecf20Sopenharmony_ci		(void)dma_ops->dma_end(drive);
4618c2ecf20Sopenharmony_ci		ide_dma_unmap_sg(drive, cmd);
4628c2ecf20Sopenharmony_ci		ret = ide_error(drive, "dma timeout error",
4638c2ecf20Sopenharmony_ci				hwif->tp_ops->read_status(hwif));
4648c2ecf20Sopenharmony_ci	} else {
4658c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name);
4668c2ecf20Sopenharmony_ci		if (dma_ops->dma_clear)
4678c2ecf20Sopenharmony_ci			dma_ops->dma_clear(drive);
4688c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
4698c2ecf20Sopenharmony_ci		if (dma_ops->dma_test_irq(drive) == 0) {
4708c2ecf20Sopenharmony_ci			ide_dump_status(drive, "DMA timeout",
4718c2ecf20Sopenharmony_ci					hwif->tp_ops->read_status(hwif));
4728c2ecf20Sopenharmony_ci			drive->waiting_for_dma = 0;
4738c2ecf20Sopenharmony_ci			(void)dma_ops->dma_end(drive);
4748c2ecf20Sopenharmony_ci			ide_dma_unmap_sg(drive, cmd);
4758c2ecf20Sopenharmony_ci		}
4768c2ecf20Sopenharmony_ci	}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	/*
4798c2ecf20Sopenharmony_ci	 * disable dma for now, but remember that we did so because of
4808c2ecf20Sopenharmony_ci	 * a timeout -- we'll reenable after we finish this next request
4818c2ecf20Sopenharmony_ci	 * (or rather the first chunk of it) in pio.
4828c2ecf20Sopenharmony_ci	 */
4838c2ecf20Sopenharmony_ci	drive->dev_flags |= IDE_DFLAG_DMA_PIO_RETRY;
4848c2ecf20Sopenharmony_ci	drive->retry_pio++;
4858c2ecf20Sopenharmony_ci	ide_dma_off_quietly(drive);
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	/*
4888c2ecf20Sopenharmony_ci	 * make sure request is sane
4898c2ecf20Sopenharmony_ci	 */
4908c2ecf20Sopenharmony_ci	if (hwif->rq)
4918c2ecf20Sopenharmony_ci		scsi_req(hwif->rq)->result = 0;
4928c2ecf20Sopenharmony_ci	return ret;
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_civoid ide_release_dma_engine(ide_hwif_t *hwif)
4968c2ecf20Sopenharmony_ci{
4978c2ecf20Sopenharmony_ci	if (hwif->dmatable_cpu) {
4988c2ecf20Sopenharmony_ci		int prd_size = hwif->prd_max_nents * hwif->prd_ent_size;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci		dma_free_coherent(hwif->dev, prd_size,
5018c2ecf20Sopenharmony_ci				  hwif->dmatable_cpu, hwif->dmatable_dma);
5028c2ecf20Sopenharmony_ci		hwif->dmatable_cpu = NULL;
5038c2ecf20Sopenharmony_ci	}
5048c2ecf20Sopenharmony_ci}
5058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_release_dma_engine);
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ciint ide_allocate_dma_engine(ide_hwif_t *hwif)
5088c2ecf20Sopenharmony_ci{
5098c2ecf20Sopenharmony_ci	int prd_size;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	if (hwif->prd_max_nents == 0)
5128c2ecf20Sopenharmony_ci		hwif->prd_max_nents = PRD_ENTRIES;
5138c2ecf20Sopenharmony_ci	if (hwif->prd_ent_size == 0)
5148c2ecf20Sopenharmony_ci		hwif->prd_ent_size = PRD_BYTES;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	prd_size = hwif->prd_max_nents * hwif->prd_ent_size;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	hwif->dmatable_cpu = dma_alloc_coherent(hwif->dev, prd_size,
5198c2ecf20Sopenharmony_ci						&hwif->dmatable_dma,
5208c2ecf20Sopenharmony_ci						GFP_ATOMIC);
5218c2ecf20Sopenharmony_ci	if (hwif->dmatable_cpu == NULL) {
5228c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: unable to allocate PRD table\n",
5238c2ecf20Sopenharmony_ci			hwif->name);
5248c2ecf20Sopenharmony_ci		return -ENOMEM;
5258c2ecf20Sopenharmony_ci	}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	return 0;
5288c2ecf20Sopenharmony_ci}
5298c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_allocate_dma_engine);
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ciint ide_dma_prepare(ide_drive_t *drive, struct ide_cmd *cmd)
5328c2ecf20Sopenharmony_ci{
5338c2ecf20Sopenharmony_ci	const struct ide_dma_ops *dma_ops = drive->hwif->dma_ops;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 ||
5368c2ecf20Sopenharmony_ci	    (dma_ops->dma_check && dma_ops->dma_check(drive, cmd)))
5378c2ecf20Sopenharmony_ci		goto out;
5388c2ecf20Sopenharmony_ci	ide_map_sg(drive, cmd);
5398c2ecf20Sopenharmony_ci	if (ide_dma_map_sg(drive, cmd) == 0)
5408c2ecf20Sopenharmony_ci		goto out_map;
5418c2ecf20Sopenharmony_ci	if (dma_ops->dma_setup(drive, cmd))
5428c2ecf20Sopenharmony_ci		goto out_dma_unmap;
5438c2ecf20Sopenharmony_ci	drive->waiting_for_dma = 1;
5448c2ecf20Sopenharmony_ci	return 0;
5458c2ecf20Sopenharmony_ciout_dma_unmap:
5468c2ecf20Sopenharmony_ci	ide_dma_unmap_sg(drive, cmd);
5478c2ecf20Sopenharmony_ciout_map:
5488c2ecf20Sopenharmony_ci	ide_map_sg(drive, cmd);
5498c2ecf20Sopenharmony_ciout:
5508c2ecf20Sopenharmony_ci	return 1;
5518c2ecf20Sopenharmony_ci}
552