diff -u --recursive --new-file --exclude='.*' linux-2.4.18/Makefile linux-2.4.18-lba48/Makefile
--- linux-2.4.18/Makefile	Fri Mar 15 17:32:48 2002
+++ linux-2.4.18-lba48/Makefile	Mon Jul 15 18:22:01 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 18
-EXTRAVERSION =
+EXTRAVERSION = lba48
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -u --recursive --new-file --exclude='.*' linux-2.4.18/drivers/ide/hpt34x.c linux-2.4.18-lba48/drivers/ide/hpt34x.c
--- linux-2.4.18/drivers/ide/hpt34x.c	Sat May 19 20:43:06 2001
+++ linux-2.4.18-lba48/drivers/ide/hpt34x.c	Mon Jul 15 18:13:38 2002
@@ -323,8 +323,10 @@
 	switch (func) {
 		case ide_dma_check:
 			return config_drive_xfer_rate(drive);
+		case ide_dma_read48:
 		case ide_dma_read:
 			reading = 1 << 3;
+		case ide_dma_write48:
 		case ide_dma_write:
 			if (!(count = ide_build_dmatable(drive, func)))
 				return 1;	/* try PIO instead of DMA */
@@ -336,7 +338,10 @@
 			if (drive->media != ide_disk)
 				return 0;
 			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);	/* issue cmd to drive */
-			OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+			if (func == ide_dma_read || func == ide_dma_write)
+				OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+			else
+				OUT_BYTE((reading == 9) ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
 			return 0;
 		case ide_dma_end:	/* returns 1 on error, 0 otherwise */
 			drive->waiting_for_dma = 0;
diff -u --recursive --new-file --exclude='.*' linux-2.4.18/drivers/ide/icside.c linux-2.4.18-lba48/drivers/ide/icside.c
--- linux-2.4.18/drivers/ide/icside.c	Thu Oct 25 16:53:47 2001
+++ linux-2.4.18-lba48/drivers/ide/icside.c	Mon Jul 15 18:16:09 2002
@@ -508,8 +508,10 @@
 	case ide_dma_check:
 		return icside_dma_check(drive);
 
+	case ide_dma_read48:
 	case ide_dma_read:
 		reading = 1;
+	case ide_dma_write48:
 	case ide_dma_write:
 		count = icside_build_dmatable(drive, reading);
 		if (!count)
@@ -535,8 +537,10 @@
 			return 0;
 
 		ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
-		OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA,
-			 IDE_COMMAND_REG);
+		if (func == ide_dma_read || func == ide_dma_write)
+			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+		else
+			OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
 
 	case ide_dma_begin:
 		enable_dma(hwif->hw.dma);
diff -u --recursive --new-file --exclude='.*' linux-2.4.18/drivers/ide/ide-disk.c linux-2.4.18-lba48/drivers/ide/ide-disk.c
--- linux-2.4.18/drivers/ide/ide-disk.c	Fri Dec 21 12:41:54 2001
+++ linux-2.4.18-lba48/drivers/ide/ide-disk.c	Mon Jul 15 18:19:40 2002
@@ -95,10 +95,23 @@
  *
  * It is called only once for each drive.
  */
-static int lba_capacity_is_ok (struct hd_driveid *id)
+static int lba_capacity_is_ok (ide_drive_t *drive)
 {
+	struct hd_driveid *id = drive->id;
 	unsigned long lba_sects, chs_sects, head, tail;
+	unsigned short *idw = (unsigned short *)id; 
 
+	if ((idw[83] & 0xc400) == 0x4400) { 		// Does drive support 48-bit LBA?
+		unsigned long capacity;
+		drive->lba28_limit = (idw[61]<<16) | idw[60];	// limit == "normal" lba_capacity value
+		capacity = (idw[101]<<16) | idw[100];
+		// The rest of the kernel can only support 32-bit LBA, so round down:
+		if (idw[103] | idw[102])
+			capacity = ~0;			// 32-bit kernel limit of 2TB
+		id->lba_capacity = capacity;
+		return 1;
+	}
+	drive->lba28_limit = ~0;			// no limit unless 48-bit is supported
 	/*
 	 * The ATA spec tells large drives to return
 	 * C/H/S = 16383/16/63 independent of their size.
@@ -367,6 +380,7 @@
  */
 static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
+	int lba48 = 0;
 	if (IDE_CONTROL_REG)
 		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
 	OUT_BYTE(0x00, IDE_FEATURE_REG);
@@ -381,6 +395,12 @@
 			drive->name, (rq->cmd==READ)?"read":"writ",
 			block, rq->nr_sectors, (unsigned long) rq->buffer);
 #endif
+		if ((block + rq->nr_sectors - 1) > drive->lba28_limit) {	// need to use 48-bit LBA?
+			OUT_BYTE(block>>24,IDE_SECTOR_REG);
+			OUT_BYTE(0,IDE_LCYL_REG);
+			OUT_BYTE(0,IDE_HCYL_REG);
+			lba48 = 1;
+		}
 		OUT_BYTE(block,IDE_SECTOR_REG);
 		OUT_BYTE(block>>=8,IDE_LCYL_REG);
 		OUT_BYTE(block>>=8,IDE_HCYL_REG);
@@ -409,20 +429,26 @@
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 	if (rq->cmd == READ) {
 #ifdef CONFIG_BLK_DEV_IDEDMA
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
+		if (drive->using_dma && !(HWIF(drive)->dmaproc(lba48 ? ide_dma_read48 : ide_dma_read, drive)))
 			return ide_started;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
-		OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
+		if (lba48)
+			OUT_BYTE(drive->mult_count ? WIN_MULTREAD_EXT : WIN_READ_EXT, IDE_COMMAND_REG);
+		else
+			OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
 		return ide_started;
 	}
 	if (rq->cmd == WRITE) {
 		ide_startstop_t startstop;
 #ifdef CONFIG_BLK_DEV_IDEDMA
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive)))
+		if (drive->using_dma && !(HWIF(drive)->dmaproc(lba48 ? ide_dma_write48 : ide_dma_write, drive)))
 			return ide_started;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-		OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
+		if (lba48)
+			OUT_BYTE(drive->mult_count ? WIN_MULTWRITE_EXT : WIN_WRITE_EXT, IDE_COMMAND_REG);
+		else
+			OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
 		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
 			printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name,
 				drive->mult_count ? "MULTWRITE" : "WRITE");
@@ -512,7 +538,7 @@
 	drive->select.b.lba = 0;
 
 	/* Determine capacity, and use LBA if the drive properly supports it */
-	if ((id->capability & 2) && lba_capacity_is_ok(id)) {
+	if ((id->capability & 2) && lba_capacity_is_ok(drive)) {
 		capacity = id->lba_capacity;
 		drive->cyl = capacity / (drive->head * drive->sect);
 		drive->select.b.lba = 1;
diff -u --recursive --new-file --exclude='.*' linux-2.4.18/drivers/ide/ide-dma.c linux-2.4.18-lba48/drivers/ide/ide-dma.c
--- linux-2.4.18/drivers/ide/ide-dma.c	Sun Sep  9 13:43:02 2001
+++ linux-2.4.18-lba48/drivers/ide/ide-dma.c	Mon Jul 15 17:53:14 2002
@@ -569,8 +569,10 @@
 			return 0;
 		case ide_dma_check:
 			return config_drive_for_dma (drive);
+		case ide_dma_read48:
 		case ide_dma_read:
 			reading = 1 << 3;
+		case ide_dma_write48:
 		case ide_dma_write:
 			SELECT_READ_WRITE(hwif,drive,func);
 			if (!(count = ide_build_dmatable(drive, func)))
@@ -586,7 +588,10 @@
 #else /* !CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
 			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry);	/* issue cmd to drive */
 #endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
-			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+			if (func == ide_dma_read || func == ide_dma_write)
+				OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+			else
+				OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
 		case ide_dma_begin:
 			/* Note that this is done *after* the cmd has
 			 * been issued to the drive, as per the BM-IDE spec.
diff -u --recursive --new-file --exclude='.*' linux-2.4.18/drivers/ide/ide-pmac.c linux-2.4.18-lba48/drivers/ide/ide-pmac.c
--- linux-2.4.18/drivers/ide/ide-pmac.c	Fri Mar 15 17:32:49 2002
+++ linux-2.4.18-lba48/drivers/ide/ide-pmac.c	Mon Jul 15 18:17:04 2002
@@ -1237,6 +1237,7 @@
 	volatile struct dbdma_regs *dma;
 	byte unit = (drive->select.b.unit & 0x01);
 	byte ata4;
+	int reading = 0;
 
 	/* Can we stuff a pointer to our intf structure in config_data
 	 * or select_data in hwif ?
@@ -1258,7 +1259,10 @@
 	case ide_dma_check:
 		pmac_ide_check_dma(drive);
 		break;
+	case ide_dma_read48:
 	case ide_dma_read:
+		reading = 1;
+	case ide_dma_write48:
 	case ide_dma_write:
 		if (!pmac_ide_build_dmatable(drive, ix, func==ide_dma_write))
 			return 1;
@@ -1273,8 +1277,10 @@
 		if (drive->media != ide_disk)
 			return 0;
 		ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
-		OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA,
-			 IDE_COMMAND_REG);
+		if (func == ide_dma_read || func == ide_dma_write)
+			OUT_BYTE(reading ? WIN_READDMA: WIN_WRITEDMA, IDE_COMMAND_REG);
+		else
+			OUT_BYTE(reading ? WIN_READDMA_EXT: WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
 	case ide_dma_begin:
 		out_le32(&dma->control, (RUN << 16) | RUN);
 		/* Make sure it gets to the controller right now */
diff -u --recursive --new-file --exclude='.*' linux-2.4.18/drivers/ide/ns87415.c linux-2.4.18-lba48/drivers/ide/ns87415.c
--- linux-2.4.18/drivers/ide/ns87415.c	Tue Jun 20 10:52:36 2000
+++ linux-2.4.18-lba48/drivers/ide/ns87415.c	Mon Jul 15 17:40:43 2002
@@ -95,7 +95,9 @@
 			outb(inb(hwif->dma_base)|6, hwif->dma_base);	/* from ERRATA: clear the INTR & ERROR bits */
 			ide_destroy_dmatable(drive);			/* and free any DMA resources */
 			return (dma_stat & 7) != 4;		/* verify good DMA status */
+		case ide_dma_write48:
 		case ide_dma_write:
+		case ide_dma_read48:
 		case ide_dma_read:
 			ns87415_prepare_drive(drive, 1);	/* select DMA xfer */
 			if (!ide_dmaproc(func, drive))		/* use standard DMA stuff */
diff -u --recursive --new-file --exclude='.*' linux-2.4.18/drivers/ide/trm290.c linux-2.4.18-lba48/drivers/ide/trm290.c
--- linux-2.4.18/drivers/ide/trm290.c	Tue Jun 20 10:52:36 2000
+++ linux-2.4.18-lba48/drivers/ide/trm290.c	Mon Jul 15 18:18:07 2002
@@ -179,12 +179,14 @@
 	unsigned int count, reading = 2, writing = 0;
 
 	switch (func) {
+		case ide_dma_write48:
 		case ide_dma_write:
 			reading = 0;
 			writing = 1;
 #ifdef TRM290_NO_DMA_WRITES
 			break;	/* always use PIO for writes */
 #endif
+		case ide_dma_read48:
 		case ide_dma_read:
 			if (!(count = ide_build_dmatable(drive, func)))
 				break;		/* try PIO instead of DMA */
@@ -195,7 +197,7 @@
 			if (drive->media != ide_disk)
 				return 0;
 			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
-			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+			OUT_BYTE(func == ide_dma_read ? WIN_READDMA : WIN_READDMA_EXT, IDE_COMMAND_REG);
 			return 0;
 		case ide_dma_begin:
 			return 0;
diff -u --recursive --new-file --exclude='.*' linux-2.4.18/include/linux/hdreg.h linux-2.4.18-lba48/include/linux/hdreg.h
--- linux-2.4.18/include/linux/hdreg.h	Thu Nov 22 14:46:18 2001
+++ linux-2.4.18-lba48/include/linux/hdreg.h	Mon Jul 15 17:40:48 2002
@@ -89,6 +89,14 @@
 #define DISABLE_SEAGATE		0xFB
 #define EXABYTE_ENABLE_NEST	0xF0
 
+/* 48-bit LBA commands */
+#define WIN_READ_EXT		0x24
+#define WIN_READDMA_EXT		0x25
+#define WIN_MULTREAD_EXT	0x29
+#define WIN_WRITE_EXT		0x34
+#define WIN_WRITEDMA_EXT	0x35
+#define WIN_MULTWRITE_EXT	0x39
+
 /* WIN_SMART sub-commands */
 
 #define SMART_READ_VALUES	0xd0
diff -u --recursive --new-file --exclude='.*' linux-2.4.18/include/linux/ide.h linux-2.4.18-lba48/include/linux/ide.h
--- linux-2.4.18/include/linux/ide.h	Thu Nov 22 14:48:07 2001
+++ linux-2.4.18-lba48/include/linux/ide.h	Mon Jul 15 17:42:28 2002
@@ -345,6 +345,7 @@
 	byte		sect;		/* "real" sectors per track */
 	byte		bios_head;	/* BIOS/fdisk/LILO number of heads */
 	byte		bios_sect;	/* BIOS/fdisk/LILO sectors per track */
+	unsigned int	lba28_limit;
 	unsigned int	bios_cyl;	/* BIOS/fdisk/LILO number of cyls */
 	unsigned int	cyl;		/* "real" number of cyls */
 	unsigned long	capacity;	/* total number of sectors */
@@ -389,7 +390,8 @@
 		ide_dma_off,	ide_dma_off_quietly,	ide_dma_test_irq,
 		ide_dma_bad_drive,			ide_dma_good_drive,
 		ide_dma_verbose,			ide_dma_retune,
-		ide_dma_lostirq,			ide_dma_timeout
+		ide_dma_lostirq,			ide_dma_timeout,
+		ide_dma_read48,				ide_dma_write48
 } ide_dma_action_t;
 
 typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
