📄 ide-probe.c
字号:
/* * linux/drivers/ide/ide-probe.c Version 1.07 March 18, 2001 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) *//* * Mostly written by Mark Lord <mlord@pobox.com> * and Gadi Oxman <gadio@netvision.net.il> * and Andre Hedrick <andre@linux-ide.org> * * See linux/MAINTAINERS for address of current maintainer. * * This is the IDE probe module, as evolved from hd.c and ide.c. * * Version 1.00 move drive probing code from ide.c to ide-probe.c * Version 1.01 fix compilation problem for m68k * Version 1.02 increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot * by Andrea Arcangeli * Version 1.03 fix for (hwif->chipset == ide_4drives) * Version 1.04 fixed buggy treatments of known flash memory cards * * Version 1.05 fix for (hwif->chipset == ide_pdc4030) * added ide6/7/8/9 * allowed for secondary flash card to be detectable * with new flag : drive->ata_flash : 1; * Version 1.06 stream line request queue and prep for cascade project. * Version 1.07 max_sect <= 255; slower disks would get behind and * then fall over when they get to 256. Paul G. */#undef REALLY_SLOW_IO /* most systems can safely undef this */#include <linux/config.h>#include <linux/module.h>#include <linux/types.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/timer.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/major.h>#include <linux/errno.h>#include <linux/genhd.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/ide.h>#include <linux/spinlock.h>#include <asm/byteorder.h>#include <asm/dma.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/io.h>static inline void do_identify (ide_drive_t *drive, byte cmd){ int bswap = 1; struct hd_driveid *id; id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_ATOMIC); /* called with interrupts disabled! */ ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */ ide__sti(); /* local CPU only */ ide_fix_driveid(id); if (id->word156 == 0x4d42) { printk("%s: drive->id->word156 == 0x%04x \n", drive->name, drive->id->word156); } if (!drive->forced_lun) drive->last_lun = id->last_lun & 0x7;#if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA) /* * EATA SCSI controllers do a hardware ATA emulation: * Ignore them if there is a driver for them available. */ if ((id->model[0] == 'P' && id->model[1] == 'M') || (id->model[0] == 'S' && id->model[1] == 'K')) { printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model); drive->present = 0; return; }#endif /* CONFIG_SCSI_EATA_DMA || CONFIG_SCSI_EATA_PIO */ /* * WIN_IDENTIFY returns little-endian info, * WIN_PIDENTIFY *usually* returns little-endian info. */ if (cmd == WIN_PIDENTIFY) { if ((id->model[0] == 'N' && id->model[1] == 'E') /* NEC */ || (id->model[0] == 'F' && id->model[1] == 'X') /* Mitsumi */ || (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */ bswap ^= 1; /* Vertos drives may still be weird */ } ide_fixstring (id->model, sizeof(id->model), bswap); ide_fixstring (id->fw_rev, sizeof(id->fw_rev), bswap); ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap); if (strstr(id->model, "E X A B Y T E N E S T")) return; id->model[sizeof(id->model)-1] = '\0'; /* we depend on this a lot! */ printk("%s: %s, ", drive->name, id->model); drive->present = 1; /* * Check for an ATAPI device */ if (cmd == WIN_PIDENTIFY) { byte type = (id->config >> 8) & 0x1f; printk("ATAPI ");#ifdef CONFIG_BLK_DEV_PDC4030 if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) { printk(" -- not supported on 2nd Promise port\n"); drive->present = 0; return; }#endif /* CONFIG_BLK_DEV_PDC4030 */ switch (type) { case ide_floppy: if (!strstr(id->model, "CD-ROM")) { if (!strstr(id->model, "oppy") && !strstr(id->model, "poyp") && !strstr(id->model, "ZIP")) printk("cdrom or floppy?, assuming "); if (drive->media != ide_cdrom) { printk ("FLOPPY"); break; } } type = ide_cdrom; /* Early cdrom models used zero */ case ide_cdrom: drive->removable = 1;#ifdef CONFIG_PPC /* kludge for Apple PowerBook internal zip */ if (!strstr(id->model, "CD-ROM") && strstr(id->model, "ZIP")) { printk ("FLOPPY"); type = ide_floppy; break; }#endif printk ("CD/DVD-ROM"); break; case ide_tape: printk ("TAPE"); break; case ide_optical: printk ("OPTICAL"); drive->removable = 1; break; default: printk("UNKNOWN (type %d)", type); break; } printk (" drive\n"); drive->media = type; return; } /* * Not an ATAPI device: looks like a "regular" hard disk */ if (id->config & (1<<7)) drive->removable = 1; /* * Prevent long system lockup probing later for non-existant * slave drive if the hwif is actually a flash memory card of some variety: */ if (drive_is_flashcard(drive)) { ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit]; if (!mate->ata_flash) { mate->present = 0; mate->noprobe = 1; } } drive->media = ide_disk; printk("ATA DISK drive\n"); QUIRK_LIST(HWIF(drive),drive); return;}/* * try_to_identify() sends an ATA(PI) IDENTIFY request to a drive * and waits for a response. It also monitors irqs while this is * happening, in hope of automatically determining which one is * being used by the interface. * * Returns: 0 device was identified * 1 device timed-out (no response to identify request) * 2 device aborted the command (refused to identify itself) */static int actual_try_to_identify (ide_drive_t *drive, byte cmd){ int rc; ide_ioreg_t hd_status; unsigned long timeout; byte s, a;// int i; if (IDE_CONTROL_REG) { /* take a deep breath */ ide_delay_50ms(); a = IN_BYTE(IDE_ALTSTATUS_REG); s = IN_BYTE(IDE_STATUS_REG); if ((a ^ s) & ~INDEX_STAT) { printk("%s: probing with STATUS(0x%02x) instead of ALTSTATUS(0x%02x)\n", drive->name, s, a); hd_status = IDE_STATUS_REG; /* ancient Seagate drives, broken interfaces */ } else { hd_status = IDE_ALTSTATUS_REG; /* use non-intrusive polling */ } } else { ide_delay_50ms(); hd_status = IDE_STATUS_REG; }/* for(i=0; i<10; i++)*/ ide_delay_50ms(); /* set features register for atapi identify command to be sure of reply */ if ((cmd == WIN_PIDENTIFY)) OUT_BYTE(0,IDE_FEATURE_REG); /* disable dma & overlap *//* for(i=0; i<10; i++)*/ ide_delay_50ms();#if CONFIG_BLK_DEV_PDC4030 if (HWIF(drive)->chipset == ide_pdc4030) { /* DC4030 hosted drives need their own identify... */ extern int pdc4030_identify(ide_drive_t *); if (pdc4030_identify(drive)) { return 1; } } else#endif /* CONFIG_BLK_DEV_PDC4030 */ OUT_BYTE(cmd,IDE_COMMAND_REG); /* ask drive for ID */// for(i=0; i<10; i++) ide_delay_50ms(); timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2; timeout += jiffies; do { if (0 < (signed long)(jiffies - timeout)) { return 1; /* drive timed-out */ } ide_delay_50ms(); /* give drive a breather */ } while (IN_BYTE(hd_status) & BUSY_STAT); ide_delay_50ms(); /* wait for IRQ and DRQ_STAT */ if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) { unsigned long flags; __save_flags(flags); /* local CPU only */ __cli(); /* local CPU only; some systems need this */ do_identify(drive, cmd); /* drive returned ID */ rc = 0; /* drive responded with ID */ (void) GET_STAT(); /* clear drive IRQ */ __restore_flags(flags); /* local CPU only */ } else rc = 2; /* drive refused ID */ return rc;}static int try_to_identify (ide_drive_t *drive, byte cmd){ int retval; int autoprobe = 0; unsigned long cookie = 0; if (IDE_CONTROL_REG && !HWIF(drive)->hw.irq) { autoprobe = 1; cookie = probe_irq_on(); OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* enable device irq */ } retval = actual_try_to_identify(drive, cmd); if (autoprobe) { int irq; OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* mask device irq */ (void) GET_STAT(); /* clear drive IRQ */ udelay(5); irq = probe_irq_off(cookie); if (!HWIF(drive)->hw.irq) { if (irq > 0) { HWIF(drive)->hw.irq = irq; } else { /* Mmmm.. multiple IRQs.. don't know which was ours */ printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie);#ifdef CONFIG_BLK_DEV_CMD640#ifdef CMD640_DUMP_REGS if (HWIF(drive)->chipset == ide_cmd640) { printk("%s: Hmmm.. probably a driver problem.\n", drive->name); CMD640_DUMP_REGS; }#endif /* CMD640_DUMP_REGS */#endif /* CONFIG_BLK_DEV_CMD640 */ } } } return retval;}/* * do_probe() has the difficult job of finding a drive if it exists, * without getting hung up if it doesn't exist, without trampling on * ethernet cards, and without leaving any IRQs dangling to haunt us later. * * If a drive is "known" to exist (from CMOS or kernel parameters), * but does not respond right away, the probe will "hang in there" * for the maximum wait time (about 30 seconds), otherwise it will * exit much more quickly. * * Returns: 0 device was identified * 1 device timed-out (no response to identify request) * 2 device aborted the command (refused to identify itself) * 3 bad status from device (possible for ATAPI drives) * 4 probe was not attempted because failure was obvious */static int do_probe (ide_drive_t *drive, byte cmd){ int rc; ide_hwif_t *hwif = HWIF(drive); if (drive->present) { /* avoid waiting for inappropriate probes */ if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY)) return 4; }#ifdef DEBUG printk("probing for %s: present=%d, media=%d, probetype=%s\n", drive->name, drive->present, drive->media, (cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");#endif ide_delay_50ms(); /* needed for some systems (e.g. crw9624 as drive0 with disk as slave) */ SELECT_DRIVE(hwif,drive); ide_delay_50ms();#ifdef CONFIG_COLDFIRE /* * ColdFire platforms boot up so quick that most hard drives * have not completed there own self tests. Pause here for * a couple of seconds if it looks like there is a drive * present... */ if (IN_BYTE(IDE_SELECT_REG) != drive->select.all) { printk("IDE: waiting for drives to settle...\n"); for (rc = 0; (rc < 400); rc++) { SELECT_DRIVE(hwif,drive); ide_delay_50ms(); if (IN_BYTE(IDE_SELECT_REG) == drive->select.all) break; } }#endif if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) { if (drive->select.b.unit != 0) { SELECT_DRIVE(hwif,&hwif->drives[0]); /* exit with drive0 selected */ ide_delay_50ms(); /* allow BUSY_STAT to assert & clear */ } return 3; /* no i/f present: mmm.. this should be a 4 -ml */ } if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT) || drive->present || cmd == WIN_PIDENTIFY) { if ((rc = try_to_identify(drive,cmd))) /* send cmd and wait */ rc = try_to_identify(drive,cmd); /* failed: try again */ if (rc == 1 && cmd == WIN_PIDENTIFY && drive->autotune != 2) { unsigned long timeout; printk("%s: no response (status = 0x%02x), resetting drive\n", drive->name, GET_STAT()); ide_delay_50ms(); OUT_BYTE (drive->select.all, IDE_SELECT_REG); ide_delay_50ms(); OUT_BYTE(WIN_SRST, IDE_COMMAND_REG); timeout = jiffies; while ((GET_STAT() & BUSY_STAT) && time_before(jiffies, timeout + WAIT_WORSTCASE)) ide_delay_50ms(); rc = try_to_identify(drive, cmd); } if (rc == 1) printk("%s: no response (status = 0x%02x)\n", drive->name, GET_STAT()); (void) GET_STAT(); /* ensure drive irq is clear */ } else { rc = 3; /* not present or maybe ATAPI */ } if (drive->select.b.unit != 0) { SELECT_DRIVE(hwif,&hwif->drives[0]); /* exit with drive0 selected */ ide_delay_50ms(); (void) GET_STAT(); /* ensure drive irq is clear */ } return rc;}/* * */static void enable_nest (ide_drive_t *drive){ unsigned long timeout; printk("%s: enabling %s -- ", HWIF(drive)->name, drive->id->model); SELECT_DRIVE(HWIF(drive), drive); ide_delay_50ms(); OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG); timeout = jiffies + WAIT_WORSTCASE; do { if (jiffies > timeout) { printk("failed (timeout)\n"); return; } ide_delay_50ms(); } while (GET_STAT() & BUSY_STAT); ide_delay_50ms(); if (!OK_STAT(GET_STAT(), 0, BAD_STAT)) printk("failed (status = 0x%02x)\n", GET_STAT()); else printk("success\n"); if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */ (void) do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */ }}/* * probe_for_drive() tests for existence of a given drive using do_probe(). * * Returns: 0 no device was found * 1 device was found (note: drive->present might still be 0) */static inline byte probe_for_drive (ide_drive_t *drive){ if (drive->noprobe) /* skip probing? */ return drive->present; if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */ (void) do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */ } if (drive->id && strstr(drive->id->model, "E X A B Y T E N E S T")) enable_nest(drive); if (!drive->present) return 0; /* drive not found */ if (drive->id == NULL) { /* identification failed? */ if (drive->media == ide_disk) { printk ("%s: non-IDE drive, CHS=%d/%d/%d\n", drive->name, drive->cyl, drive->head, drive->sect); } else if (drive->media == ide_cdrom) { printk("%s: ATAPI cdrom (?)\n", drive->name); } else { drive->present = 0; /* nuke it */ } } return 1; /* drive was found */}/* * Calculate the region that this interface occupies, * handling interfaces where the registers may not be * ordered sanely. We deal with the CONTROL register * separately. */static int hwif_check_regions (ide_hwif_t *hwif){ int region_errors = 0; hwif->straight8 = 0; region_errors = ide_check_region(hwif->hw.io_ports[IDE_DATA_OFFSET], 1); region_errors += ide_check_region(hwif->hw.io_ports[IDE_ERROR_OFFSET], 1); region_errors += ide_check_region(hwif->hw.io_ports[IDE_NSECTOR_OFFSET], 1); region_errors += ide_check_region(hwif->hw.io_ports[IDE_SECTOR_OFFSET], 1); region_errors += ide_check_region(hwif->hw.io_ports[IDE_LCYL_OFFSET], 1); region_errors += ide_check_region(hwif->hw.io_ports[IDE_HCYL_OFFSET], 1); region_errors += ide_check_region(hwif->hw.io_ports[IDE_SELECT_OFFSET], 1); region_errors += ide_check_region(hwif->hw.io_ports[IDE_STATUS_OFFSET], 1); if (hwif->hw.io_ports[IDE_CONTROL_OFFSET]) region_errors += ide_check_region(hwif->hw.io_ports[IDE_CONTROL_OFFSET], 1);#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC) if (hwif->hw.io_ports[IDE_IRQ_OFFSET]) region_errors += ide_check_region(hwif->hw.io_ports[IDE_IRQ_OFFSET], 1);#endif /* * If any errors are return, we drop the hwif interface. */ return(region_errors);}static void hwif_register (ide_hwif_t *hwif){ if (((unsigned long)hwif->hw.io_ports[IDE_DATA_OFFSET] | 7) == ((unsigned long)hwif->hw.io_ports[IDE_STATUS_OFFSET])) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -