This patch adds lba48 support to the TiVo linux-2.1.x sources to support drives > 137MB. It is based on the linux-2.4.x kernel sources as well as Mark Lord's backport of lba48 support to the linux-2.2.x kernel. The diff includes changes to some code that is not compiled, but I wanted things to be consistent wrt lba48. I cranked IDETIVO_DRIVER_VERSION to avoid a panic due to ideturbo and kernel mismatch. This will prevent the existing ideturbo module from working. You can compile a new one, but since ideturbo is not lba48-aware you wouldn't want to use it. I don't know what the lba48 variants of the Western Digital AV opcodes are (they are non-standard). Also be aware that when TiVo pushes out new software you could end up with a non-bootable system. Please be sure you know what you are doing and *make backups*! - todd --- include/linux/tivo-private.h.DIST Fri May 31 16:28:19 2002 +++ include/linux/tivo-private.h Wed May 28 11:55:00 2003 @@ -80,7 +80,7 @@ STATE_UNKNOWN, STATE_KNOWN, STATE_MEDIA, STATE_NOMEDIA, STATE_FLUSHED }; -#define IDETIVO_DRIVER_VERSION 0x00010004 +#define IDETIVO_DRIVER_VERSION 0x00010005 enum drive_family { FAMILY_UNKNOWN, FAMILY_QUANTUM, FAMILY_STREAMWEAVER1, FAMILY_UNSUPPORTED --- drivers/block/ide-disk.c.DIST Fri May 31 16:28:13 2002 +++ drivers/block/ide-disk.c Sat Jun 7 22:02:58 2003 @@ -101,12 +101,25 @@ * Returns: 1 if lba_capacity looks sensible * 0 otherwise */ -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 = id->lba_capacity; unsigned long chs_sects = id->cyls * id->heads * id->sectors; unsigned long _10_percent = chs_sects / 10; + /* Check for 48-bit LBA support in drive (we only support 32-bit LBA) */ + drive->lba48 = 0; + if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) { + if (id->word103 | id->word102) + id->lba_capacity = ~0UL; /* truncate to 2TB */ + else + id->lba_capacity = (id->word101<<16) | id->word100; + if (id->lba_capacity >= 128 * 1024 * 1024 * 2) + drive->lba48 = 1; /* requires lba48 addressing */ + return 1; + } + /* perform a rough sanity check on lba_sects: within 10% is "okay" */ if ((lba_sects - chs_sects) < _10_percent) return 1; /* lba_capacity is good */ @@ -308,13 +321,14 @@ */ static void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) { + int lba48 = 0; #ifdef CONFIG_BLK_DEV_PROMISE ide_hwif_t *hwif = HWIF(drive); int use_promise_io = 0; #endif /* CONFIG_BLK_DEV_PROMISE */ - OUT_BYTE(drive->ctl,IDE_CONTROL_REG); - OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG); + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl,IDE_CONTROL_REG); #ifdef CONFIG_BLK_DEV_PROMISE if (IS_PROMISE_DRIVE) { if (hwif->is_promise2 || rq->cmd == READ) { @@ -330,10 +344,62 @@ drive->name, (rq->cmd==READ)?"read":"writ", block, rq->nr_sectors, (unsigned long) rq->buffer); #endif - OUT_BYTE(block,IDE_SECTOR_REG); - OUT_BYTE(block>>=8,IDE_LCYL_REG); - OUT_BYTE(block>>=8,IDE_HCYL_REG); - OUT_BYTE(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG); + if (drive->lba48) { + unsigned char tasklets[10]; + + tasklets[0] = 0; + tasklets[1] = 0; + tasklets[2] = rq->nr_sectors; + tasklets[3] = (rq->nr_sectors>>8); + if (rq->nr_sectors == 65536) { + tasklets[2] = 0x00; + tasklets[3] = 0x00; + } + tasklets[4] = (unsigned char) block; + tasklets[5] = (unsigned char) (block>>8); + tasklets[6] = (unsigned char) (block>>16); + tasklets[7] = (unsigned char) (block>>24); + tasklets[8] = (unsigned char) 0; + tasklets[9] = (unsigned char) 0; +#ifdef DEBUG + printk("%s: %sing: LBAsect=%lu, sectors=%ld, buffer=0x%08lx, LBAsect=0x%012lx\n", + drive->name, + (rq->cmd==READ)?"read":"writ", + block, + rq->nr_sectors, + (unsigned long) rq->buffer, + block); + printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n", + drive->name, tasklets[3], tasklets[2], + tasklets[9], tasklets[8], tasklets[7], + tasklets[6], tasklets[5], tasklets[4]); +#endif + OUT_BYTE(tasklets[1], IDE_FEATURE_REG); + OUT_BYTE(tasklets[3], IDE_NSECTOR_REG); + OUT_BYTE(tasklets[7], IDE_SECTOR_REG); + OUT_BYTE(tasklets[8], IDE_LCYL_REG); + OUT_BYTE(tasklets[9], IDE_HCYL_REG); + + OUT_BYTE(tasklets[0], IDE_FEATURE_REG); + OUT_BYTE(tasklets[2], IDE_NSECTOR_REG); + OUT_BYTE(tasklets[4], IDE_SECTOR_REG); + OUT_BYTE(tasklets[5], IDE_LCYL_REG); + OUT_BYTE(tasklets[6], IDE_HCYL_REG); + OUT_BYTE(0x00|drive->select.all,IDE_SELECT_REG); + lba48 = 1; + } else { +#ifdef DEBUG + printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n", + drive->name, (rq->cmd==READ)?"read":"writ", + block, rq->nr_sectors, (unsigned long) rq->buffer); +#endif + OUT_BYTE(0x00, IDE_FEATURE_REG); + OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG); + OUT_BYTE(block,IDE_SECTOR_REG); + OUT_BYTE(block>>=8,IDE_LCYL_REG); + OUT_BYTE(block>>=8,IDE_HCYL_REG); + OUT_BYTE(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG); + } } else { unsigned int sect,head,cyl,track; track = block / drive->sect; @@ -341,6 +407,9 @@ OUT_BYTE(sect,IDE_SECTOR_REG); head = track % drive->head; cyl = track / drive->head; + + OUT_BYTE(0x00, IDE_FEATURE_REG); + OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG); OUT_BYTE(cyl,IDE_LCYL_REG); OUT_BYTE(cyl>>8,IDE_HCYL_REG); OUT_BYTE(head|drive->select.all,IDE_SELECT_REG); @@ -358,27 +427,34 @@ #endif /* CONFIG_BLK_DEV_PROMISE */ if (rq->cmd == READ) { #ifdef CONFIG_BLK_DEV_TRITON - 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; #endif /* CONFIG_BLK_DEV_TRITON */ #ifdef CONFIG_TCD_IDE_DMA - 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; #endif /* CONFIG_TCD_IDE_DMA */ ide_set_handler(drive, &read_intr, WAIT_CMD); - 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; } if (rq->cmd == WRITE) { #ifdef CONFIG_BLK_DEV_TRITON - 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; #endif /* CONFIG_BLK_DEV_TRITON */ #ifdef CONFIG_TCD_IDE_DMA - 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; #endif /* CONFIG_BLK_DEV_TRITON */ - 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(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"); @@ -460,7 +536,7 @@ capacity = id->lba_capacity; drive->select.b.lba = 1; #else - if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) { + if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(drive)) { if (id->lba_capacity >= capacity) { capacity = id->lba_capacity; drive->select.b.lba = 1; --- drivers/block/ide-tivodma.c.DIST Fri May 31 16:28:13 2002 +++ drivers/block/ide-tivodma.c Wed May 28 11:55:00 2003 @@ -550,7 +550,6 @@ static int tivo_ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { unsigned long frdwr = DMA_READ; - unsigned long reading = 1; int wait_count; long int flags; unsigned char cmdcode; @@ -599,10 +598,18 @@ ideChFree(); return wait_count; case ide_dma_write: + cmdcode = WIN_WRITEDMA; + frdwr = DMA_WRITE; + break; + case ide_dma_write48: + cmdcode = WIN_WRITEDMA_EXT; frdwr = DMA_WRITE; - reading = 0; break; case ide_dma_read: + cmdcode = WIN_READDMA; + break; + case ide_dma_read48: + cmdcode = WIN_READDMA_EXT; break; case ide_dma_status_bad: wait_count = DmaChIdle(tyDmaChIde); /* verify good DMA status */ @@ -700,7 +707,6 @@ } #endif /* get the drive dma going also. */ - cmdcode = reading ? WIN_READDMA : WIN_WRITEDMA; if (idetivo_cmd_hook) { (*idetivo_cmd_hook)(drive, &cmdcode); } --- drivers/block/triton.c.DIST Fri May 31 16:28:13 2002 +++ drivers/block/triton.c Wed May 28 11:55:00 2003 @@ -458,8 +458,10 @@ case ide_dma_check: return config_drive_for_dma (drive); case ide_dma_write: + case ide_dma_write48: reading = 0; case ide_dma_read: + case ide_dma_read48: break; case ide_dma_status_bad: return ((inb(dma_base+2) & 7) != 4); /* verify good DMA status */ @@ -484,7 +486,10 @@ if (drive->media != ide_disk) return 0; ide_set_handler(drive, &dma_intr, WAIT_CMD); /* issue cmd to drive */ - 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); outb(inb(dma_base)|1, dma_base); /* begin DMA */ return 0; } --- drivers/block/ide-tivo.c.DIST Fri May 31 16:28:13 2002 +++ drivers/block/ide-tivo.c Sat Jun 7 22:03:59 2003 @@ -1223,13 +1223,27 @@ * Returns: 1 if lba_capacity looks sensible * 0 otherwise */ -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 = id->lba_capacity; unsigned long chs_sects = id->cyls * id->heads * id->sectors; unsigned long _10_percent = chs_sects / 10; TIVO_CALL("lba_capacity_is_ok"); + + /* Check for 48-bit LBA support in drive (we only support 32-bit LBA) */ + drive->lba48 = 0; + if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) { + if (id->word103 | id->word102) + id->lba_capacity = ~0UL; /* truncate to 2TB */ + else + id->lba_capacity = (id->word101<<16) | id->word100; + if (id->lba_capacity >= 128 * 1024 * 1024 * 2) + drive->lba48 = 1; /* requires lba48 addressing */ + return 1; + } + /* perform a rough sanity check on lba_sects: within 10% is "okay" */ if ((lba_sects - chs_sects) < _10_percent) return 1; /* lba_capacity is good */ @@ -1581,25 +1595,55 @@ return; /* temporary holdoff */ } - OUT_BYTE(drive->ctl,IDE_CONTROL_REG); - /* when you request 256 sectors, you send "0" to the drive */ - if (req->chunk_num_sectors < MAX_SECTORS) - OUT_BYTE(req->chunk_num_sectors,IDE_NSECTOR_REG); - else - OUT_BYTE(0,IDE_NSECTOR_REG); + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl,IDE_CONTROL_REG); if (drive->select.b.lba) { - unsigned long temp; - temp = req->sector; + unsigned long block; + block = req->sector; #ifdef DEBUG printk("%s: %sing: LBAsect=%ld, sectors=%d\n", drive->name, (req->cmd==READ)?"read":"writ", - temp, req->chunk_num_sectors); + block, req->chunk_num_sectors); #endif - OUT_BYTE(temp,IDE_SECTOR_REG); - OUT_BYTE(temp>>=8,IDE_LCYL_REG); - OUT_BYTE(temp>>=8,IDE_HCYL_REG); - OUT_BYTE(((temp>>8)&0x0f)|(drive->select.all),IDE_SELECT_REG); + if (drive->lba48) { + unsigned char tasklets[10]; + + tasklets[0] = 0; + tasklets[1] = 0; + tasklets[2] = req->chunk_num_sectors; + tasklets[3] = (req->chunk_num_sectors>>8); + if (req->chunk_num_sectors == 65536) { + tasklets[2] = 0x00; + tasklets[3] = 0x00; + } + tasklets[4] = (unsigned char) block; + tasklets[5] = (unsigned char) (block>>8); + tasklets[6] = (unsigned char) (block>>16); + tasklets[7] = (unsigned char) (block>>24); + tasklets[8] = (unsigned char) 0; + tasklets[9] = (unsigned char) 0; + + OUT_BYTE(tasklets[1], IDE_FEATURE_REG); + OUT_BYTE(tasklets[3], IDE_NSECTOR_REG); + OUT_BYTE(tasklets[7], IDE_SECTOR_REG); + OUT_BYTE(tasklets[8], IDE_LCYL_REG); + OUT_BYTE(tasklets[9], IDE_HCYL_REG); + + OUT_BYTE(tasklets[0], IDE_FEATURE_REG); + OUT_BYTE(tasklets[2], IDE_NSECTOR_REG); + OUT_BYTE(tasklets[4], IDE_SECTOR_REG); + OUT_BYTE(tasklets[5], IDE_LCYL_REG); + OUT_BYTE(tasklets[6], IDE_HCYL_REG); + OUT_BYTE(0x00|drive->select.all,IDE_SELECT_REG); + } else { + OUT_BYTE(0x00, IDE_FEATURE_REG); + OUT_BYTE((req->chunk_num_sectors==MAX_SECTORS)?0x00:req->chunk_num_sectors,IDE_NSECTOR_REG); + OUT_BYTE(block,IDE_SECTOR_REG); + OUT_BYTE(block>>=8,IDE_LCYL_REG); + OUT_BYTE(block>>=8,IDE_HCYL_REG); + OUT_BYTE(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG); + } } else { unsigned int sect,head,cyl,track; printk(KERN_WARNING "unexpected CHS mode!\n"); @@ -1608,6 +1652,9 @@ OUT_BYTE(sect,IDE_SECTOR_REG); head = track % drive->head; cyl = track / drive->head; + + OUT_BYTE(0x00, IDE_FEATURE_REG); + OUT_BYTE((req->chunk_num_sectors==MAX_SECTORS)?0x00:req->chunk_num_sectors,IDE_NSECTOR_REG); OUT_BYTE(cyl,IDE_LCYL_REG); OUT_BYTE(cyl>>8,IDE_HCYL_REG); OUT_BYTE(head|(drive->select.all),IDE_SELECT_REG); @@ -1627,7 +1674,7 @@ if (req->cmd == READ) { TIVO_STATUS("idetivo_do_rw_disk" , "READ"); #if defined(CONFIG_BLK_DEV_TRITON)||defined(CONFIG_TCD_IDE_DMA) - if (drive->using_dma && !(HWIF(drive)->dmaproc)(ide_dma_read,drive)) { + if (drive->using_dma && !(HWIF(drive)->dmaproc)(drive->lba48 ? ide_dma_read48 : ide_dma_read,drive)) { TIVO_RETURN("idetivo_do_rw_disk", "READ: DMA proc caled"); return; } @@ -1639,12 +1686,12 @@ idetivo_update_stats(DISKMON_IDLE); return; } - OUT_BYTE(WIN_READ, IDE_COMMAND_REG); + OUT_BYTE(drive->lba48 ? WIN_READ_EXT : WIN_READ, IDE_COMMAND_REG); return; } else if (req->cmd == WRITE) { TIVO_STATUS("idetivo_do_rw_disk" , "WRITE"); #if defined(CONFIG_BLK_DEV_TRITON)||defined(CONFIG_TCD_IDE_DMA) - if (drive->using_dma && !(HWIF(drive)->dmaproc)(ide_dma_write,drive)) { + if (drive->using_dma && !(HWIF(drive)->dmaproc)(drive->lba48 ? ide_dma_write48 : ide_dma_write,drive)) { TIVO_RETURN("idetivo_do_rw_disk", "WRITE: DMA proc caled"); return; } @@ -1656,7 +1703,7 @@ return; } ide_set_handler(drive, &write_intr, WAIT_CMD); - OUT_BYTE(WIN_WRITE, IDE_COMMAND_REG); + OUT_BYTE(drive->lba48 ? WIN_WRITE_EXT : WIN_WRITE, IDE_COMMAND_REG); if (ide_wait_stat(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"); @@ -1693,8 +1740,8 @@ return; } - OUT_BYTE(drive->ctl,IDE_CONTROL_REG); - OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG); + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl,IDE_CONTROL_REG); #ifdef CONFIG_BLK_DEV_PROMISE if (IS_PROMISE_DRIVE) { if (hwif->is_promise2 || rq->cmd == READ) { @@ -1710,10 +1757,44 @@ drive->name, (rq->cmd==READ)?"read":"writ", block, rq->nr_sectors, (unsigned long) rq->buffer); #endif - OUT_BYTE(block,IDE_SECTOR_REG); - OUT_BYTE(block>>=8,IDE_LCYL_REG); - OUT_BYTE(block>>=8,IDE_HCYL_REG); - OUT_BYTE(((block>>8)&0x0f)|(drive->select.all),IDE_SELECT_REG); + if (drive->lba48) { + unsigned char tasklets[10]; + + tasklets[0] = 0; + tasklets[1] = 0; + tasklets[2] = rq->nr_sectors; + tasklets[3] = (rq->nr_sectors>>8); + if (rq->nr_sectors == 65536) { + tasklets[2] = 0x00; + tasklets[3] = 0x00; + } + tasklets[4] = (unsigned char) block; + tasklets[5] = (unsigned char) (block>>8); + tasklets[6] = (unsigned char) (block>>16); + tasklets[7] = (unsigned char) (block>>24); + tasklets[8] = (unsigned char) 0; + tasklets[9] = (unsigned char) 0; + + OUT_BYTE(tasklets[1], IDE_FEATURE_REG); + OUT_BYTE(tasklets[3], IDE_NSECTOR_REG); + OUT_BYTE(tasklets[7], IDE_SECTOR_REG); + OUT_BYTE(tasklets[8], IDE_LCYL_REG); + OUT_BYTE(tasklets[9], IDE_HCYL_REG); + + OUT_BYTE(tasklets[0], IDE_FEATURE_REG); + OUT_BYTE(tasklets[2], IDE_NSECTOR_REG); + OUT_BYTE(tasklets[4], IDE_SECTOR_REG); + OUT_BYTE(tasklets[5], IDE_LCYL_REG); + OUT_BYTE(tasklets[6], IDE_HCYL_REG); + OUT_BYTE(0x00|drive->select.all,IDE_SELECT_REG); + } else { + OUT_BYTE(0x00, IDE_FEATURE_REG); + OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG); + OUT_BYTE(block,IDE_SECTOR_REG); + OUT_BYTE(block>>=8,IDE_LCYL_REG); + OUT_BYTE(block>>=8,IDE_HCYL_REG); + OUT_BYTE(((block>>8)&0x0f)|(drive->select.all),IDE_SELECT_REG); + } } else { unsigned int sect,head,cyl,track; track = block / drive->sect; @@ -1721,6 +1802,9 @@ OUT_BYTE(sect,IDE_SECTOR_REG); head = track % drive->head; cyl = track / drive->head; + + OUT_BYTE(0x00, IDE_FEATURE_REG); + OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG); OUT_BYTE(cyl,IDE_LCYL_REG); OUT_BYTE(cyl>>8,IDE_HCYL_REG); OUT_BYTE(head|(drive->select.all),IDE_SELECT_REG); @@ -1739,7 +1823,7 @@ idetivo_update_stats(DISKMON_LEGACY); if (rq->cmd == READ) { #if defined(CONFIG_BLK_DEV_TRITON)||defined(CONFIG_TCD_IDE_DMA) - if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive))) + if (drive->using_dma && !(HWIF(drive)->dmaproc(drive->lba48 ? ide_dma_read48 : ide_dma_read, drive))) return; #endif /* CONFIG_BLK_DEV_TRITON */ ide_set_handler(drive, &read_intr_legacy, WAIT_CMD); @@ -1749,12 +1833,12 @@ idetivo_update_stats(DISKMON_IDLE); return; } - OUT_BYTE(WIN_READ, IDE_COMMAND_REG); + OUT_BYTE(drive->lba48 ? WIN_READ_EXT : WIN_READ, IDE_COMMAND_REG); return; } if (rq->cmd == WRITE) { #if defined(CONFIG_BLK_DEV_TRITON)||defined(CONFIG_TCD_IDE_DMA) - if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive))) + if (drive->using_dma && !(HWIF(drive)->dmaproc(drive->lba48 ? ide_dma_write48 : ide_dma_write, drive))) return; #endif /* CONFIG_BLK_DEV_TRITON */ if (drive->mult_count) { @@ -1763,7 +1847,7 @@ idetivo_update_stats(DISKMON_IDLE); return; } - OUT_BYTE(WIN_WRITE, IDE_COMMAND_REG); + OUT_BYTE(drive->lba48 ? WIN_WRITE_EXT : WIN_WRITE, IDE_COMMAND_REG); if (ide_wait_stat(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"); @@ -1871,7 +1955,7 @@ #ifdef ORIGINAL drive->select.b.lba = 0; /* Determine capacity, and use LBA if the drive properly supports it */ - if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) { + if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(drive)) { if (id->lba_capacity >= capacity) { capacity = id->lba_capacity; drive->select.b.lba = 1; @@ -1879,22 +1963,35 @@ } #endif drive->select.b.lba = 0; + drive->lba48 = 0; /* Determine capacity, and use LBA if the drive properly supports it */ #if 0 printk(KERN_WARNING "id=%p, id->capability=%d\n", id, id?id->capability:0); #endif +#ifndef ORIGINAL if (id != NULL && (id->capability & 2)) { - capacity = id->lba_capacity; + /* Check for 48-bit LBA support in drive (we only support 32-bit LBA) */ + if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) { + if (id->word103 | id->word102) + capacity = ~0UL; /* truncate to 2TB */ + else + capacity = (id->word101<<16) | id->word100; + if (capacity >= 128 * 1024 * 1024 * 2) + drive->lba48 = 1; /* requires lba48 addressing */ + id->lba_capacity = capacity; + } else + capacity = id->lba_capacity; +#endif drive->select.b.lba = 1; -#if 0 +#if 0 printk(KERN_WARNING "enabling LBA mode\n"); -#endif +#endif } -#if 0 +#if 0 printk(KERN_WARNING "lba mode is %d\n", drive->select.b.lba); -#endif +#endif return (capacity - drive->sect0); } @@ -2678,18 +2775,18 @@ /* Check advanced features */ printk (KERN_INFO "idinfo 82=%04X 83=%04X 85=%04X 86=%04X 87=%04X\n", - id->smart, id->cmdsets_supported, - id->word85, id->cmdsets_enabled, id->word87); + id->command_set_1, id->command_set_2, + id->cfs_enable_1, id->cfs_enable_2, id->csf_default); drive->av_cmdset = 0; drive->SMART = 0; - if ((id->smart != 0x0000 && id->smart != 0xFFFF) || - (id->cmdsets_supported != 0x0000 && id->cmdsets_supported != 0xFFFF)) { - if (id->smart & 0x1) { + if ((id->command_set_1 != 0x0000 && id->command_set_1 != 0xFFFF) || + (id->command_set_2 != 0x0000 && id->command_set_2 != 0xFFFF)) { + if (id->command_set_1 & 0x1) { drive->SMART = 1; } - if (id->cmdsets_supported & 0x80) { + if (id->command_set_2 & 0x80) { drive->av_cmdset = 1; } } @@ -2697,10 +2794,10 @@ (void) idetivo_capacity (drive); /* initialize LBA selection */ printk (KERN_INFO "%s: %.40s, %ldMB w/%dkB Cache, multiple %d, %sCHS=%d/%d/%d%s%s%s\n", - drive->name, id->model, idetivo_capacity(drive)/2048L, + drive->name, id->model, idetivo_capacity(drive)/2048UL, id->buf_size/2, id->max_multsect, - drive->select.b.lba ? "LBA, " : "", + drive->select.b.lba ? (drive->lba48 ? "LBA48, " : "LBA, ") : "", drive->bios_cyl, drive->bios_head, drive->bios_sect, drive->using_dma ? ", DMA" : "", drive->av_cmdset ? ", A/V" : "", --- include/linux/hdreg.h.DIST Fri May 31 16:28:18 2002 +++ include/linux/hdreg.h Sat Jun 7 21:55:20 2003 @@ -73,6 +73,14 @@ #define WIN_SRST 0x08 /* ATAPI soft reset command */ #define WIN_PACKETCMD 0xa0 /* Send a packet command. */ +/* 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 @@ -237,14 +245,29 @@ unsigned short word79; unsigned short word80; unsigned short word81; - unsigned short smart; - unsigned short cmdsets_supported; + unsigned short command_set_1; + unsigned short command_set_2; unsigned short word84; - unsigned short word85; - unsigned short cmdsets_enabled; - unsigned short word87; + unsigned short cfs_enable_1; + unsigned short cfs_enable_2; + unsigned short csf_default; unsigned short dma_ultra; - /* unsigned short reservedxx[39];*/ /* reserved (words 89-127) */ + unsigned short word89; + unsigned short word90; + unsigned short word91; + unsigned short word92; + unsigned short word93; + unsigned short word94; + unsigned short word95; + unsigned short word96; + unsigned short word97; + unsigned short word98; + unsigned short word99; + unsigned short word100; + unsigned short word101; + unsigned short word102; + unsigned short word103; + /* unsigned short reservedxx[24];*/ /* reserved (words 104-127) */ /* unsigned short vendor7 [32];*/ /* vendor unique (words 128-159) */ /* unsigned short reservedyy[96];*/ /* reserved (words 160-255) */ }; --- include/linux/ide.h.DIST Fri May 31 16:28:18 2002 +++ include/linux/ide.h Sat Jun 7 21:55:27 2003 @@ -279,6 +279,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 */ + int lba48; /* drive requires lba48 addressing */ unsigned short bios_cyl; /* BIOS/fdisk/LILO number of cyls */ unsigned short cyl; /* "real" number of cyls */ void *hwif; /* actually (ide_hwif_t *) */ @@ -307,7 +308,8 @@ typedef enum { ide_dma_read = 0, ide_dma_write = 1, ide_dma_abort = 2, ide_dma_check = 3, ide_dma_status_bad = 4, ide_dma_transferred = 5, - ide_dma_begin = 6 } + ide_dma_begin = 6, ide_dma_read48 = 7, + ide_dma_write48 = 8 } ide_dma_action_t; typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *); @@ -631,8 +633,10 @@ #ifdef CONFIG_BLK_DEV_IDEDISK int idedisk_init (void); -int idetivo_init (void); #endif /* CONFIG_BLK_DEV_IDEDISK */ +#ifdef CONFIG_BLK_DEV_IDETIVO +int idetivo_init (void); +#endif /* CONFIG_BLK_DEV_IDETIVO */ #ifdef CONFIG_BLK_DEV_IDECD int ide_cdrom_init (void); #endif /* CONFIG_BLK_DEV_IDECD */ --- drivers/block/Makefile.DIST Fri May 31 16:28:13 2002 +++ drivers/block/Makefile Wed May 28 12:41:08 2003 @@ -88,6 +88,10 @@ L_OBJS += ide-tivodma.o endif +ifeq ($(CONFIG_BLK_DEV_IDETIVO),y) +L_OBJS += ide-tivo.o +endif + ifeq ($(CONFIG_BLK_DEV_PS2),y) L_OBJS += ps2esdi.o endif @@ -122,18 +126,10 @@ endif ifeq ($(CONFIG_BLK_DEV_IDEDISK),y) -L_OBJS += ide-disk.o ide-tivo.o -else - ifeq ($(CONFIG_BLK_DEV_IDEDISK),m) - M_OBJS += ide-disk.o ide-tivo.o - endif -endif - -ifeq ($(CONFIG_BLK_DEV_IDEDISK),y) -L_OBJS += ide-disk.o ide-tivo.o +L_OBJS += ide-disk.o else ifeq ($(CONFIG_BLK_DEV_IDEDISK),m) - M_OBJS += ide-disk.o ide-tivo.o + M_OBJS += ide-disk.o endif endif