X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fide%2Fide-lib.c;h=32e2b166f33f41b4b7f0e6878df256f75cfb73c2;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=b2fa5eccdcad483f8df2218fbf2bf48269d63bb4;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index b2fa5eccd..32e2b166f 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -15,12 +14,12 @@ #include #include #include +#include #include #include #include #include -#include /* * IDE library routines. These are plug in code that most @@ -72,75 +71,96 @@ EXPORT_SYMBOL(ide_xfer_verbose); /** * ide_dma_speed - compute DMA speed * @drive: drive - * @mode; intended mode + * @mode: modes available * * Checks the drive capabilities and returns the speed to use - * for the transfer. Returns -1 if the requested mode is unknown - * (eg PIO) + * for the DMA transfer. Returns 0 if the drive is incapable + * of DMA transfers. */ u8 ide_dma_speed(ide_drive_t *drive, u8 mode) { struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); + u8 ultra_mask, mwdma_mask, swdma_mask; u8 speed = 0; if (drive->media != ide_disk && hwif->atapi_dma == 0) return 0; - switch(mode) { - case 0x04: - if ((id->dma_ultra & 0x0040) && - (id->dma_ultra & hwif->ultra_mask)) - { speed = XFER_UDMA_6; break; } - case 0x03: - if ((id->dma_ultra & 0x0020) && - (id->dma_ultra & hwif->ultra_mask)) - { speed = XFER_UDMA_5; break; } - case 0x02: - if ((id->dma_ultra & 0x0010) && - (id->dma_ultra & hwif->ultra_mask)) - { speed = XFER_UDMA_4; break; } - if ((id->dma_ultra & 0x0008) && - (id->dma_ultra & hwif->ultra_mask)) - { speed = XFER_UDMA_3; break; } - case 0x01: - if ((id->dma_ultra & 0x0004) && - (id->dma_ultra & hwif->ultra_mask)) - { speed = XFER_UDMA_2; break; } - if ((id->dma_ultra & 0x0002) && - (id->dma_ultra & hwif->ultra_mask)) - { speed = XFER_UDMA_1; break; } - if ((id->dma_ultra & 0x0001) && - (id->dma_ultra & hwif->ultra_mask)) - { speed = XFER_UDMA_0; break; } - case 0x00: - if ((id->dma_mword & 0x0004) && - (id->dma_mword & hwif->mwdma_mask)) - { speed = XFER_MW_DMA_2; break; } - if ((id->dma_mword & 0x0002) && - (id->dma_mword & hwif->mwdma_mask)) - { speed = XFER_MW_DMA_1; break; } - if ((id->dma_mword & 0x0001) && - (id->dma_mword & hwif->mwdma_mask)) - { speed = XFER_MW_DMA_0; break; } - if ((id->dma_1word & 0x0004) && - (id->dma_1word & hwif->swdma_mask)) - { speed = XFER_SW_DMA_2; break; } - if ((id->dma_1word & 0x0002) && - (id->dma_1word & hwif->swdma_mask)) - { speed = XFER_SW_DMA_1; break; } - if ((id->dma_1word & 0x0001) && - (id->dma_1word & hwif->swdma_mask)) - { speed = XFER_SW_DMA_0; break; } - } + /* Capable of UltraDMA modes? */ + ultra_mask = id->dma_ultra & hwif->ultra_mask; + + if (!(id->field_valid & 4)) + mode = 0; /* fallback to MW/SW DMA if no UltraDMA */ + + switch (mode) { + case 4: + if (ultra_mask & 0x40) { + speed = XFER_UDMA_6; + break; + } + case 3: + if (ultra_mask & 0x20) { + speed = XFER_UDMA_5; + break; + } + case 2: + if (ultra_mask & 0x10) { + speed = XFER_UDMA_4; + break; + } + if (ultra_mask & 0x08) { + speed = XFER_UDMA_3; + break; + } + case 1: + if (ultra_mask & 0x04) { + speed = XFER_UDMA_2; + break; + } + if (ultra_mask & 0x02) { + speed = XFER_UDMA_1; + break; + } + if (ultra_mask & 0x01) { + speed = XFER_UDMA_0; + break; + } + case 0: + mwdma_mask = id->dma_mword & hwif->mwdma_mask; + + if (mwdma_mask & 0x04) { + speed = XFER_MW_DMA_2; + break; + } + if (mwdma_mask & 0x02) { + speed = XFER_MW_DMA_1; + break; + } + if (mwdma_mask & 0x01) { + speed = XFER_MW_DMA_0; + break; + } -// printk("%s: %s: mode 0x%02x, speed 0x%02x\n", -// __FUNCTION__, drive->name, mode, speed); + swdma_mask = id->dma_1word & hwif->swdma_mask; + + if (swdma_mask & 0x04) { + speed = XFER_SW_DMA_2; + break; + } + if (swdma_mask & 0x02) { + speed = XFER_SW_DMA_1; + break; + } + if (swdma_mask & 0x01) { + speed = XFER_SW_DMA_0; + break; + } + } return speed; } - EXPORT_SYMBOL(ide_dma_speed); @@ -164,8 +184,7 @@ u8 ide_rate_filter (u8 mode, u8 speed) // printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed); /* So that we remember to update this if new modes appear */ - if (mode > 4) - BUG(); + BUG_ON(mode > 4); return min(speed, speed_max[mode]); #else /* !CONFIG_BLK_DEV_IDEDMA */ return min(speed, (u8)XFER_PIO_4); @@ -421,8 +440,6 @@ void ide_toggle_bounce(ide_drive_t *drive, int on) blk_queue_bounce_limit(drive->queue, addr); } -EXPORT_SYMBOL(ide_toggle_bounce); - /** * ide_set_xfer_rate - set transfer rate * @drive: drive to set @@ -447,6 +464,112 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) EXPORT_SYMBOL_GPL(ide_set_xfer_rate); +static void ide_dump_opcode(ide_drive_t *drive) +{ + struct request *rq; + u8 opcode = 0; + int found = 0; + + spin_lock(&ide_lock); + rq = NULL; + if (HWGROUP(drive)) + rq = HWGROUP(drive)->rq; + spin_unlock(&ide_lock); + if (!rq) + return; + if (rq->cmd_type == REQ_TYPE_ATA_CMD || + rq->cmd_type == REQ_TYPE_ATA_TASK) { + char *args = rq->buffer; + if (args) { + opcode = args[0]; + found = 1; + } + } else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { + ide_task_t *args = rq->special; + if (args) { + task_struct_t *tf = (task_struct_t *) args->tfRegister; + opcode = tf->command; + found = 1; + } + } + + printk("ide: failed opcode was: "); + if (!found) + printk("unknown\n"); + else + printk("0x%02x\n", opcode); +} + +static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat) +{ + ide_hwif_t *hwif = HWIF(drive); + unsigned long flags; + u8 err = 0; + + local_irq_save(flags); + printk("%s: %s: status=0x%02x { ", drive->name, msg, stat); + if (stat & BUSY_STAT) + printk("Busy "); + else { + if (stat & READY_STAT) printk("DriveReady "); + if (stat & WRERR_STAT) printk("DeviceFault "); + if (stat & SEEK_STAT) printk("SeekComplete "); + if (stat & DRQ_STAT) printk("DataRequest "); + if (stat & ECC_STAT) printk("CorrectedError "); + if (stat & INDEX_STAT) printk("Index "); + if (stat & ERR_STAT) printk("Error "); + } + printk("}\n"); + if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) { + err = hwif->INB(IDE_ERROR_REG); + printk("%s: %s: error=0x%02x { ", drive->name, msg, err); + if (err & ABRT_ERR) printk("DriveStatusError "); + if (err & ICRC_ERR) + printk((err & ABRT_ERR) ? "BadCRC " : "BadSector "); + if (err & ECC_ERR) printk("UncorrectableError "); + if (err & ID_ERR) printk("SectorIdNotFound "); + if (err & TRK0_ERR) printk("TrackZeroNotFound "); + if (err & MARK_ERR) printk("AddrMarkNotFound "); + printk("}"); + if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || + (err & (ECC_ERR|ID_ERR|MARK_ERR))) { + if (drive->addressing == 1) { + __u64 sectors = 0; + u32 low = 0, high = 0; + low = ide_read_24(drive); + hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG); + high = ide_read_24(drive); + sectors = ((__u64)high << 24) | low; + printk(", LBAsect=%llu, high=%d, low=%d", + (unsigned long long) sectors, + high, low); + } else { + u8 cur = hwif->INB(IDE_SELECT_REG); + if (cur & 0x40) { /* using LBA? */ + printk(", LBAsect=%ld", (unsigned long) + ((cur&0xf)<<24) + |(hwif->INB(IDE_HCYL_REG)<<16) + |(hwif->INB(IDE_LCYL_REG)<<8) + | hwif->INB(IDE_SECTOR_REG)); + } else { + printk(", CHS=%d/%d/%d", + (hwif->INB(IDE_HCYL_REG)<<8) + + hwif->INB(IDE_LCYL_REG), + cur & 0xf, + hwif->INB(IDE_SECTOR_REG)); + } + } + if (HWGROUP(drive) && HWGROUP(drive)->rq) + printk(", sector=%llu", + (unsigned long long)HWGROUP(drive)->rq->sector); + } + printk("\n"); + } + ide_dump_opcode(drive); + local_irq_restore(flags); + return err; +} + /** * ide_dump_atapi_status - print human readable atapi status * @drive: drive that status applies to @@ -455,7 +578,8 @@ EXPORT_SYMBOL_GPL(ide_set_xfer_rate); * * Error reporting, in human readable form (luxurious, but a memory hog). */ -byte ide_dump_atapi_status (ide_drive_t *drive, const char *msg, byte stat) + +static u8 ide_dump_atapi_status(ide_drive_t *drive, const char *msg, u8 stat) { unsigned long flags; @@ -463,9 +587,9 @@ byte ide_dump_atapi_status (ide_drive_t *drive, const char *msg, byte stat) atapi_error_t error; status.all = stat; - local_irq_set(flags); - printk("%s: %s: status=0x%02x", drive->name, msg, stat); - printk(" { "); + error.all = 0; + local_irq_save(flags); + printk("%s: %s: status=0x%02x { ", drive->name, msg, stat); if (status.b.bsy) printk("Busy "); else { @@ -477,21 +601,39 @@ byte ide_dump_atapi_status (ide_drive_t *drive, const char *msg, byte stat) if (status.b.idx) printk("Index "); if (status.b.check) printk("Error "); } - printk("}"); - printk("\n"); - if ((status.all & (status.b.bsy|status.b.check)) == status.b.check) { + printk("}\n"); + if (status.b.check && !status.b.bsy) { error.all = HWIF(drive)->INB(IDE_ERROR_REG); - printk("%s: %s: error=0x%02x", drive->name, msg, error.all); + printk("%s: %s: error=0x%02x { ", drive->name, msg, error.all); if (error.b.ili) printk("IllegalLengthIndication "); if (error.b.eom) printk("EndOfMedia "); - if (error.b.abrt) printk("Aborted Command "); + if (error.b.abrt) printk("AbortedCommand "); if (error.b.mcr) printk("MediaChangeRequested "); - if (error.b.sense_key) printk("LastFailedSense 0x%02x ", + if (error.b.sense_key) printk("LastFailedSense=0x%02x ", error.b.sense_key); - printk("\n"); + printk("}\n"); } + ide_dump_opcode(drive); local_irq_restore(flags); return error.all; } -EXPORT_SYMBOL(ide_dump_atapi_status); +/** + * ide_dump_status - translate ATA/ATAPI error + * @drive: drive the error occured on + * @msg: information string + * @stat: status byte + * + * Error reporting, in human readable form (luxurious, but a memory hog). + * Combines the drive name, message and status byte to provide a + * user understandable explanation of the device error. + */ + +u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat) +{ + if (drive->media == ide_disk) + return ide_dump_ata_status(drive, msg, stat); + return ide_dump_atapi_status(drive, msg, stat); +} + +EXPORT_SYMBOL(ide_dump_status);