📄 ide-probe.c
字号:
/* * linux/drivers/ide/ide-probe.c Version 1.11 Mar 05, 2003 * * 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. * * -- increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot * by Andrea Arcangeli */#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 <linux/kmod.h>#include <linux/pci.h>#include <linux/scatterlist.h>#include <asm/byteorder.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/io.h>/** * generic_id - add a generic drive id * @drive: drive to make an ID block for * * Add a fake id field to the drive we are passed. This allows * use to skip a ton of NULL checks (which people always miss) * and make drive properties unconditional outside of this file */ static void generic_id(ide_drive_t *drive){ drive->id->cyls = drive->cyl; drive->id->heads = drive->head; drive->id->sectors = drive->sect; drive->id->cur_cyls = drive->cyl; drive->id->cur_heads = drive->head; drive->id->cur_sectors = drive->sect;}static void ide_disk_init_chs(ide_drive_t *drive){ struct hd_driveid *id = drive->id; /* Extract geometry if we did not already have one for the drive */ if (!drive->cyl || !drive->head || !drive->sect) { drive->cyl = drive->bios_cyl = id->cyls; drive->head = drive->bios_head = id->heads; drive->sect = drive->bios_sect = id->sectors; } /* Handle logical geometry translation by the drive */ if ((id->field_valid & 1) && id->cur_cyls && id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) { drive->cyl = id->cur_cyls; drive->head = id->cur_heads; drive->sect = id->cur_sectors; } /* Use physical geometry if what we have still makes no sense */ if (drive->head > 16 && id->heads && id->heads <= 16) { drive->cyl = id->cyls; drive->head = id->heads; drive->sect = id->sectors; }}static void ide_disk_init_mult_count(ide_drive_t *drive){ struct hd_driveid *id = drive->id; drive->mult_count = 0; if (id->max_multsect) {#ifdef CONFIG_IDEDISK_MULTI_MODE id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0; id->multsect_valid = id->multsect ? 1 : 0; drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT; drive->special.b.set_multmode = drive->mult_req ? 1 : 0;#else /* original, pre IDE-NFG, per request of AC */ drive->mult_req = INITIAL_MULT_COUNT; if (drive->mult_req > id->max_multsect) drive->mult_req = id->max_multsect; if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect)) drive->special.b.set_multmode = 1;#endif }}/** * do_identify - identify a drive * @drive: drive to identify * @cmd: command used * * Called when we have issued a drive identify command to * read and parse the results. This function is run with * interrupts disabled. */ static inline void do_identify (ide_drive_t *drive, u8 cmd){ ide_hwif_t *hwif = HWIF(drive); int bswap = 1; struct hd_driveid *id; id = drive->id; /* read 512 bytes of id info */ hwif->ata_input_data(drive, id, SECTOR_WORDS); drive->id_read = 1; local_irq_enable(); ide_fix_driveid(id);#if 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); goto err_misc; }#endif /* CONFIG_SCSI_EATA || 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 */ /* Vertos drives may still be weird */ bswap ^= 1; } 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); /* we depend on this a lot! */ id->model[sizeof(id->model)-1] = '\0'; if (strstr(id->model, "E X A B Y T E N E S T")) goto err_misc; printk("%s: %s, ", drive->name, id->model); drive->present = 1; drive->dead = 0; /* * Check for an ATAPI device */ if (cmd == WIN_PIDENTIFY) { u8 type = (id->config >> 8) & 0x1f; printk("ATAPI "); 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"); drive->removable = 1; break; } } /* Early cdrom models used zero */ type = ide_cdrom; 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; /* an ATAPI device ignores DRDY */ drive->ready_stat = 0; return; } /* * Not an ATAPI device: looks like a "regular" hard disk */ /* * 0x848a = CompactFlash device * These are *not* removable in Linux definition of the term */ if ((id->config != 0x848a) && (id->config & (1<<7))) drive->removable = 1; drive->media = ide_disk; printk("%s DISK drive\n", (id->config == 0x848a) ? "CFA" : "ATA" ); QUIRK_LIST(drive); return;err_misc: kfree(id); drive->present = 0; return;}/** * actual_try_to_identify - send ata/atapi identify * @drive: drive to identify * @cmd: command to use * * 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, u8 cmd){ ide_hwif_t *hwif = HWIF(drive); int rc; unsigned long hd_status; unsigned long timeout; u8 s = 0, a = 0; /* take a deep breath */ msleep(50); if (IDE_CONTROL_REG) { a = hwif->INB(IDE_ALTSTATUS_REG); s = hwif->INB(IDE_STATUS_REG); if ((a ^ s) & ~INDEX_STAT) { printk(KERN_INFO "%s: probing with STATUS(0x%02x) instead of " "ALTSTATUS(0x%02x)\n", drive->name, s, a); /* ancient Seagate drives, broken interfaces */ hd_status = IDE_STATUS_REG; } else { /* use non-intrusive polling */ hd_status = IDE_ALTSTATUS_REG; } } else hd_status = IDE_STATUS_REG; /* set features register for atapi * identify command to be sure of reply */ if ((cmd == WIN_PIDENTIFY)) /* disable dma & overlap */ hwif->OUTB(0, IDE_FEATURE_REG); /* ask drive for ID */ hwif->OUTB(cmd, IDE_COMMAND_REG); timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2; timeout += jiffies; do { if (time_after(jiffies, timeout)) { /* drive timed-out */ return 1; } /* give drive a breather */ msleep(50); } while ((hwif->INB(hd_status)) & BUSY_STAT); /* wait for IRQ and DRQ_STAT */ msleep(50); if (OK_STAT((hwif->INB(IDE_STATUS_REG)), DRQ_STAT, BAD_R_STAT)) { unsigned long flags; /* local CPU only; some systems need this */ local_irq_save(flags); /* drive returned ID */ do_identify(drive, cmd); /* drive responded with ID */ rc = 0; /* clear drive IRQ */ (void) hwif->INB(IDE_STATUS_REG); local_irq_restore(flags); } else { /* drive refused ID */ rc = 2; } return rc;}/** * try_to_identify - try to identify a drive * @drive: drive to probe * @cmd: command to use * * Issue the identify command and then do IRQ probing to * complete the identification when needed by finding the * IRQ the drive is attached to */ static int try_to_identify (ide_drive_t *drive, u8 cmd){ ide_hwif_t *hwif = HWIF(drive); int retval; int autoprobe = 0; unsigned long cookie = 0; /* * Disable device irq unless we need to * probe for it. Otherwise we'll get spurious * interrupts during the identify-phase that * the irq handler isn't expecting. */ if (IDE_CONTROL_REG) { u8 ctl = drive->ctl | 2; if (!hwif->irq) { autoprobe = 1; cookie = probe_irq_on(); /* enable device irq */ ctl &= ~2; } hwif->OUTB(ctl, IDE_CONTROL_REG); } retval = actual_try_to_identify(drive, cmd); if (autoprobe) { int irq; /* mask device irq */ hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG); /* clear drive IRQ */ (void) hwif->INB(IDE_STATUS_REG); udelay(5); irq = probe_irq_off(cookie); if (!hwif->irq) { if (irq > 0) { hwif->irq = irq; } else { /* Mmmm.. multiple IRQs.. * don't know which was ours */ printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie); } } } return retval;}/** * do_probe - probe an IDE device * @drive: drive to probe * @cmd: command to use * * 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, u8 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 /* needed for some systems * (e.g. crw9624 as drive0 with disk as slave) */ msleep(50); SELECT_DRIVE(drive); msleep(50); if (hwif->INB(IDE_SELECT_REG) != drive->select.all && !drive->present) { if (drive->select.b.unit != 0) { /* exit with drive0 selected */ SELECT_DRIVE(&hwif->drives[0]); /* allow BUSY_STAT to assert & clear */ msleep(50); } /* no i/f present: mmm.. this should be a 4 -ml */ return 3; } if (OK_STAT((hwif->INB(IDE_STATUS_REG)), READY_STAT, BUSY_STAT) || drive->present || cmd == WIN_PIDENTIFY) { /* send cmd and wait */ if ((rc = try_to_identify(drive, cmd))) { /* failed: try again */ rc = try_to_identify(drive,cmd); } if (hwif->INB(IDE_STATUS_REG) == (BUSY_STAT|READY_STAT)) return 4; if ((rc == 1 && cmd == WIN_PIDENTIFY) && ((drive->autotune == IDE_TUNE_DEFAULT) || (drive->autotune == IDE_TUNE_AUTO))) { unsigned long timeout; printk("%s: no response (status = 0x%02x), " "resetting drive\n", drive->name, hwif->INB(IDE_STATUS_REG)); msleep(50); hwif->OUTB(drive->select.all, IDE_SELECT_REG); msleep(50); hwif->OUTB(WIN_SRST, IDE_COMMAND_REG); timeout = jiffies; while (((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && time_before(jiffies, timeout + WAIT_WORSTCASE)) msleep(50); rc = try_to_identify(drive, cmd); } if (rc == 1) printk("%s: no response (status = 0x%02x)\n", drive->name, hwif->INB(IDE_STATUS_REG)); /* ensure drive irq is clear */ (void) hwif->INB(IDE_STATUS_REG); } else { /* not present or maybe ATAPI */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -