--- sos-code-article10//drivers/ide.c 2006-01-22 12:48:28.000000000 +0100 +++ 10_mafat/drivers/ide.c 2008-03-08 12:59:44.000000000 +0100 @@ -16,6 +16,29 @@ USA. */ +/* + Modification: + 1- number of heads computation: + In LBA mode, the field bearing the number of head is erroneously + assumed to span over 3 bits. It actually spans over 4 bits + + 2. interrupt signal inadvertently reset. + In several occasion, after the io operation is fired and before the process + is set waiting,some read acces are issued to the status register. When + the io is fast enough, these status read reset any interrupt signal. It + caused the process to hang in the ensuing sleep stage, waiting for some + event inadvertently acknowledged. + To circumvent the problem , the alternate status register is used instead of + the nominal status register. + + + 3. Weak LBA mode determination algorithm + In the real world, it seems that the driver fails to assess the LBA + capability. No robust alternate algorithm is available. + Suggestion is brought to remove the algorithm and to force LBA mode ... + +*/ + #include #include #include @@ -390,6 +413,8 @@ dev->cyls = info->nb_logical_cylinders; dev->sectors = info->nb_logical_sectors; + dev->blocks = info->lba_capacity; + dev->support_lba = FALSE; /* Determines if device supports LBA. The method is a bit ugly, but @@ -514,7 +539,8 @@ sect = (block & 0xff); cyl_lo = (block >> 8) & 0xff; cyl_hi = (block >> 16) & 0xff; - head = ((block >> 24) & 0x7) | 0x40; + head = ((block >> 24) & 0xF) | 0x40; + /* head = ((block >> 24) & 0x7) | 0x40; */ } else { @@ -553,11 +579,15 @@ outb(ATA_C_READ, dev->ctrl->ioaddr + ATA_CMD); /* Wait for the device ready to transfer */ - do { udelay(1); } while (inb(dev->ctrl->ioaddr + ATA_STATUS) & ATA_S_BSY); + /*do { udelay(1); } while (inb(dev->ctrl->ioaddr + ATA_STATUS) & ATA_S_BSY); */ + + do { udelay(1); } while (inb(dev->ctrl->ioaddr + ATA_ALTPORT) & ATA_S_BSY); /* If an error was detected, stop here */ - if (inb(dev->ctrl->ioaddr + ATA_STATUS) & ATA_S_ERROR) + /* if (inb(dev->ctrl->ioaddr + ATA_STATUS) & ATA_S_ERROR) */ + if (inb(dev->ctrl->ioaddr + ATA_ALTPORT) & ATA_S_ERROR) { + inb(dev->ctrl->ioaddr + ATA_STATUS); sos_kmutex_unlock (& dev->ctrl->mutex); return -SOS_EFATAL; } @@ -570,7 +600,8 @@ /* Wait for the DRQ bit to be set */ while (1) { - status = inb(dev->ctrl->ioaddr + ATA_STATUS); + /* status = inb(dev->ctrl->ioaddr + ATA_STATUS); */ + status = inb(dev->ctrl->ioaddr + ATA_ALTPORT); if (status & ATA_S_ERROR) { sos_kmutex_unlock (& dev->ctrl->mutex); @@ -589,7 +620,8 @@ /* Wait for the device to have received all the data */ while (1) { - status = inb(dev->ctrl->ioaddr + ATA_STATUS); + /* status = inb(dev->ctrl->ioaddr + ATA_STATUS); */ + status = inb(dev->ctrl->ioaddr + ATA_ALTPORT); if (status & ATA_S_ERROR) { sos_kmutex_unlock (& dev->ctrl->mutex);