diff --git a/core/diskstart.inc b/core/diskstart.inc
index c24b64a..1438477 100644
--- a/core/diskstart.inc
+++ b/core/diskstart.inc
@@ -456,7 +456,6 @@ bailmsg:	db 'Boot error', 0Dh, 0Ah, 0
 		zb 1F8h-($-$$)
 
 FirstSector	dd 0xDEADBEEF			; Location of sector 1
-		global MaxTransfer
 MaxTransfer	dw 0x007F			; Max transfer size
 
 ; This field will be filled in 0xAA55 by the installer, but we abuse it
@@ -746,5 +745,6 @@ expand_super:
 		xor ebx,ebx
 		mov si,[bsHeads]
 		mov di,[bsSecPerTrack]
+		movzx ebp,word [MaxTransfer]
 		pm_call fs_init
 		popad
diff --git a/core/fs/diskio.c b/core/fs/diskio.c
index cdbed79..3edc1b6 100644
--- a/core/fs/diskio.c
+++ b/core/fs/diskio.c
@@ -8,8 +8,6 @@
 
 #define RETRY_COUNT 6
 
-static uint16_t MaxTransfer = 1 << (16 - 9);
-
 static int chs_rdwr_sectors(struct disk *disk, void *buf,
 			    sector_t lba, size_t count, bool is_write)
 {
@@ -32,8 +30,8 @@ static int chs_rdwr_sectors(struct disk *disk, void *buf,
 
     while (count) {
 	chunk = count;
-	if (chunk > MaxTransfer)
-	    chunk = MaxTransfer;
+	if (chunk > disk->maxtransfer)
+	    chunk = disk->maxtransfer;
 
 	freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift;
 
@@ -77,7 +75,7 @@ static int chs_rdwr_sectors(struct disk *disk, void *buf,
 	    /* For any starting value, this will always end with ..., 1, 0 */
 	    chunk >>= 1;
             if (chunk) {
-		MaxTransfer = chunk;
+		disk->maxtransfer = chunk;
 		retry = RETRY_COUNT;
                 ireg.eax.b[0] = chunk;
                 continue;
@@ -129,8 +127,8 @@ static int edd_rdwr_sectors(struct disk *disk, void *buf,
     lba += disk->part_start;
     while (count) {
 	chunk = count;
-	if (chunk > MaxTransfer)
-	    chunk = MaxTransfer;
+	if (chunk > disk->maxtransfer)
+	    chunk = disk->maxtransfer;
 
 	freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift;
 
@@ -150,14 +148,14 @@ static int edd_rdwr_sectors(struct disk *disk, void *buf,
 	if (tptr != ptr && is_write)
 	    memcpy(tptr, ptr, bytes);
 
-	pkt.size   = sizeof pkt;
-	pkt.blocks = chunk;
-	pkt.buf    = FAR_PTR(tptr);
-	pkt.lba    = lba;
-        
 	retry = RETRY_COUNT;
 
 	for (;;) {
+	    pkt.size   = sizeof pkt;
+	    pkt.blocks = chunk;
+	    pkt.buf    = FAR_PTR(tptr);
+	    pkt.lba    = lba;
+
 	    __intcall(0x13, &ireg, &oreg);
 	    if (!(oreg.eflags.l & EFLAGS_CF))
 		break;
@@ -167,9 +165,8 @@ static int edd_rdwr_sectors(struct disk *disk, void *buf,
 	    /* For any starting value, this will always end with ..., 1, 0 */
 	    chunk >>= 1;
 	    if (chunk) {
-		MaxTransfer = chunk;
+		disk->maxtransfer = chunk;
 		retry = RETRY_COUNT;
-                pkt.blocks = chunk;
 		continue;
 	    }
 
@@ -237,13 +234,15 @@ void getoneblk(struct disk *disk, char *buf, block_t block, int block_size)
 
 
 struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start,
-                       uint16_t bsHeads, uint16_t bsSecPerTrack)
+                       uint16_t bsHeads, uint16_t bsSecPerTrack,
+		       uint32_t MaxTransfer)
 {
     static struct disk disk;
     static __lowmem struct edd_disk_params edd_params;
     com32sys_t ireg, oreg;
     bool ebios = cdrom;
     int sector_size = cdrom ? 2048 : 512;
+    unsigned int hard_max_transfer = ebios ? 127 : 63;
 
     memset(&ireg, 0, sizeof ireg);
 
@@ -258,6 +257,7 @@ struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start,
     if (cdrom || (!(oreg.eflags.l & EFLAGS_CF) &&
 		  oreg.ebx.w[0] == 0xaa55 && (oreg.ecx.b[0] & 1))) {
 	ebios = true;
+	hard_max_transfer = 127;
 
 	/* Query EBIOS parameters */
 	edd_params.len = sizeof edd_params;
@@ -300,6 +300,11 @@ struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start,
     disk.part_start    = part_start;
     disk.rdwr_sectors  = ebios ? edd_rdwr_sectors : chs_rdwr_sectors;
 
+    if (!MaxTransfer || MaxTransfer > hard_max_transfer)
+	MaxTransfer = hard_max_transfer;
+
+    disk.maxtransfer   = MaxTransfer;
+
     return &disk;
 }
 
@@ -310,12 +315,14 @@ struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start,
  * NOTE: the disk cache needs to be revamped to support multiple devices...
  */
 struct device * device_init(uint8_t devno, bool cdrom, sector_t part_start,
-                            uint16_t bsHeads, uint16_t bsSecPerTrack)
+                            uint16_t bsHeads, uint16_t bsSecPerTrack,
+			    uint32_t MaxTransfer)
 {
     static struct device dev;
     static __hugebss char diskcache[128*1024];
 
-    dev.disk = disk_init(devno, cdrom, part_start, bsHeads, bsSecPerTrack);
+    dev.disk = disk_init(devno, cdrom, part_start,
+			 bsHeads, bsSecPerTrack, MaxTransfer);
         
     dev.cache_data = diskcache;
     dev.cache_size = sizeof diskcache;
diff --git a/core/fs/fs.c b/core/fs/fs.c
index 6ea74bf..792da02 100644
--- a/core/fs/fs.c
+++ b/core/fs/fs.c
@@ -363,6 +363,7 @@ void fs_init(com32sys_t *regs)
     sector_t disk_offset = regs->ecx.l | ((sector_t)regs->ebx.l << 32);
     uint16_t disk_heads = regs->esi.w[0];
     uint16_t disk_sectors = regs->edi.w[0];
+    uint32_t maxtransfer = regs->ebp.l;
     int blk_shift = -1;
     struct device *dev = NULL;
     /* ops is a ptr list for several fs_ops */
@@ -387,7 +388,7 @@ void fs_init(com32sys_t *regs)
 	} else {
 	    if (!dev)
 		dev = device_init(disk_devno, disk_cdrom, disk_offset,
-				  disk_heads, disk_sectors);
+				  disk_heads, disk_sectors, maxtransfer);
 	    fs.fs_dev = dev;
 	}
 	/* invoke the fs-specific init code */
diff --git a/core/include/disk.h b/core/include/disk.h
index da6555a..df0476a 100644
--- a/core/include/disk.h
+++ b/core/include/disk.h
@@ -23,6 +23,8 @@ struct disk {
 
     sector_t part_start;   /* the start address of this partition(in sectors) */
     
+    uint32_t maxtransfer;	/* Max sectors per transfer */
+
     int (*rdwr_sectors)(struct disk *, void *, sector_t, size_t, bool);
 };
 
@@ -30,7 +32,7 @@ extern void read_sectors(char *, sector_t, int);
 extern void getoneblk(struct disk *, char *, block_t, int);
 
 /* diskio.c */
-struct disk *disk_init(uint8_t, bool, sector_t, uint16_t, uint16_t);
-struct device *device_init(uint8_t, bool, sector_t, uint16_t, uint16_t);                           
+struct disk *disk_init(uint8_t, bool, sector_t, uint16_t, uint16_t, uint32_t);
+struct device *device_init(uint8_t, bool, sector_t, uint16_t, uint16_t, uint32_t);
 
 #endif /* DISK_H */
diff --git a/core/isolinux.asm b/core/isolinux.asm
index d1d5bf8..d2ba81d 100644
--- a/core/isolinux.asm
+++ b/core/isolinux.asm
@@ -1093,7 +1093,6 @@ bios_ebios:	dw getlinsec_ebios, bios_ebios_str
 %endif
 
 ; Maximum transfer size
-                global MaxTransfer          
 MaxTransfer	dw 127				; Hard disk modes
 MaxTransferCD	dw 32				; CD mode
 
@@ -1154,11 +1153,18 @@ all_read:
 ; (which will be at 16 only for a single-session disk!); from the PVD
 ; we should be able to find the rest of what we need to know.
 ;
+init_fs:
 		pushad
 	        mov eax,ROOT_FS_OPS
 	        mov dl,[DriveNumber]
                	cmp word [BIOSType],bios_cdrom
                 sete dh                        ; 1 for cdrom, 0 for hybrid mode
+		jne .hybrid
+		movzx ebp,word [MaxTransferCD]
+		jmp .common
+.hybrid:
+		movzx ebp,word [MaxTransfer]
+.common:
 	        mov ecx,[bsHidden]
 	        mov ebx,[bsHidden+4]
                 mov si,[bsHeads]
diff --git a/core/pxelinux.asm b/core/pxelinux.asm
index 2e7e607..204b09c 100644
--- a/core/pxelinux.asm
+++ b/core/pxelinux.asm
@@ -221,6 +221,7 @@ adhcp_copy:
 ; do fs initialize
 ;
 	        mov eax,ROOT_FS_OPS
+		xor ebp,ebp
                 pm_call fs_init
 
 		section .rodata
