📄 ide.c
字号:
/* * linux/drivers/ide/ide.c Version 7.00beta2 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 multiple IDE interface driver, as evolved from hd.c. * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs * (usually 14 & 15). * There can be up to two drives per interface, as per the ATA-2 spec. * * ... * * From hd.c: * | * | It traverses the request-list, using interrupts to jump between functions. * | As nearly all functions can be called within interrupts, we may not sleep. * | Special care is recommended. Have Fun! * | * | modified by Drew Eckhardt to check nr of hd's from the CMOS. * | * | Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug * | in the early extended-partition checks and added DM partitions. * | * | Early work on error handling by Mika Liljeberg (liljeber@cs.Helsinki.FI). * | * | IRQ-unmask, drive-id, multiple-mode, support for ">16 heads", * | and general streamlining by Mark Lord (mlord@pobox.com). * * October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by: * * Mark Lord (mlord@pobox.com) (IDE Perf.Pkg) * Delman Lee (delman@ieee.org) ("Mr. atdisk2") * Scott Snyder (snyder@fnald0.fnal.gov) (ATAPI IDE cd-rom) * * This was a rewrite of just about everything from hd.c, though some original * code is still sprinkled about. Think of it as a major evolution, with * inspiration from lots of linux users, esp. hamish@zot.apana.org.au */#define REVISION "Revision: 7.00alpha2"#define VERSION "Id: ide.c 7.00a2 20020906"#define _IDE_C /* Tell ide.h it's really us */#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/blkpg.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/ide.h>#include <linux/completion.h>#include <linux/reboot.h>#include <linux/cdrom.h>#include <linux/seq_file.h>#include <linux/device.h>#include <linux/bitops.h>#include <asm/byteorder.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/io.h>/* default maximum number of failures */#define IDE_DEFAULT_MAX_FAILURES 1static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR };static int idebus_parameter; /* holds the "idebus=" parameter */static int system_bus_speed; /* holds what we think is VESA/PCI bus speed */DEFINE_MUTEX(ide_cfg_mtx); __cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock);#ifdef CONFIG_IDEPCI_PCIBUS_ORDERstatic int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */#endifint noautodma = 0;#ifdef CONFIG_BLK_DEV_IDEACPIint ide_noacpi = 0;int ide_noacpitfs = 1;int ide_noacpionboot = 1;#endif/* * This is declared extern in ide.h, for access by other IDE modules: */ide_hwif_t ide_hwifs[MAX_HWIFS]; /* master data repository */EXPORT_SYMBOL(ide_hwifs);/* * Do not even *think* about calling this! */static void init_hwif_data(ide_hwif_t *hwif, unsigned int index){ unsigned int unit; /* bulk initialize hwif & drive info with zeros */ memset(hwif, 0, sizeof(ide_hwif_t)); /* fill in any non-zero initial values */ hwif->index = index; hwif->major = ide_hwif_to_major[index]; hwif->name[0] = 'i'; hwif->name[1] = 'd'; hwif->name[2] = 'e'; hwif->name[3] = '0' + index; hwif->bus_state = BUSSTATE_ON; init_completion(&hwif->gendev_rel_comp); default_hwif_iops(hwif); default_hwif_transport(hwif); for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; drive->media = ide_disk; drive->select.all = (unit<<4)|0xa0; drive->hwif = hwif; drive->ctl = 0x08; drive->ready_stat = READY_STAT; drive->bad_wstat = BAD_W_STAT; drive->special.b.recalibrate = 1; drive->special.b.set_geometry = 1; drive->name[0] = 'h'; drive->name[1] = 'd'; drive->name[2] = 'a' + (index * MAX_DRIVES) + unit; drive->max_failures = IDE_DEFAULT_MAX_FAILURES; drive->using_dma = 0; drive->vdma = 0; INIT_LIST_HEAD(&drive->list); init_completion(&drive->gendev_rel_comp); }}static void init_hwif_default(ide_hwif_t *hwif, unsigned int index){ hw_regs_t hw; memset(&hw, 0, sizeof(hw_regs_t)); ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, &hwif->irq); memcpy(hwif->io_ports, hw.io_ports, sizeof(hw.io_ports)); hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];#ifdef CONFIG_BLK_DEV_HD if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) hwif->noprobe = 1; /* may be overridden by ide_setup() */#endif}extern void ide_arm_init(void);/* * init_ide_data() sets reasonable default values into all fields * of all instances of the hwifs and drives, but only on the first call. * Subsequent calls have no effect (they don't wipe out anything). * * This routine is normally called at driver initialization time, * but may also be called MUCH earlier during kernel "command-line" * parameter processing. As such, we cannot depend on any other parts * of the kernel (such as memory allocation) to be functioning yet. * * This is too bad, as otherwise we could dynamically allocate the * ide_drive_t structs as needed, rather than always consuming memory * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them. * * FIXME: We should stuff the setup data into __init and copy the * relevant hwifs/allocate them properly during boot. */#define MAGIC_COOKIE 0x12345678static void __init init_ide_data (void){ ide_hwif_t *hwif; unsigned int index; static unsigned long magic_cookie = MAGIC_COOKIE; if (magic_cookie != MAGIC_COOKIE) return; /* already initialized */ magic_cookie = 0; /* Initialise all interface structures */ for (index = 0; index < MAX_HWIFS; ++index) { hwif = &ide_hwifs[index]; init_hwif_data(hwif, index); init_hwif_default(hwif, index);#if !defined(CONFIG_PPC32) || !defined(CONFIG_PCI) hwif->irq = ide_init_default_irq(hwif->io_ports[IDE_DATA_OFFSET]);#endif }#ifdef CONFIG_IDE_ARM ide_arm_init();#endif}/** * ide_system_bus_speed - guess bus speed * * ide_system_bus_speed() returns what we think is the system VESA/PCI * bus speed (in MHz). This is used for calculating interface PIO timings. * The default is 40 for known PCI systems, 50 otherwise. * The "idebus=xx" parameter can be used to override this value. * The actual value to be used is computed/displayed the first time * through. Drivers should only use this as a last resort. * * Returns a guessed speed in MHz. */static int ide_system_bus_speed(void){#ifdef CONFIG_PCI static struct pci_device_id pci_default[] = { { PCI_DEVICE(PCI_ANY_ID, PCI_ANY_ID) }, { } };#else#define pci_default 0#endif /* CONFIG_PCI */ if (!system_bus_speed) { if (idebus_parameter) { /* user supplied value */ system_bus_speed = idebus_parameter; } else if (pci_dev_present(pci_default)) { /* safe default value for PCI */ system_bus_speed = 33; } else { /* safe default value for VESA and PCI */ system_bus_speed = 50; } printk(KERN_INFO "ide: Assuming %dMHz system bus speed " "for PIO modes%s\n", system_bus_speed, idebus_parameter ? "" : "; override with idebus=xx"); } return system_bus_speed;}ide_hwif_t * ide_find_port(unsigned long base){ ide_hwif_t *hwif; int i; for (i = 0; i < MAX_HWIFS; i++) { hwif = &ide_hwifs[i]; if (hwif->io_ports[IDE_DATA_OFFSET] == base) goto found; } for (i = 0; i < MAX_HWIFS; i++) { hwif = &ide_hwifs[i]; if (hwif->io_ports[IDE_DATA_OFFSET] == 0) goto found; } hwif = NULL;found: return hwif;}EXPORT_SYMBOL_GPL(ide_find_port);static struct resource* hwif_request_region(ide_hwif_t *hwif, unsigned long addr, int num){ struct resource *res = request_region(addr, num, hwif->name); if (!res) printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n", hwif->name, addr, addr+num-1); return res;}/** * ide_hwif_request_regions - request resources for IDE * @hwif: interface to use * * Requests all the needed resources for an interface. * Right now core IDE code does this work which is deeply wrong. * MMIO leaves it to the controller driver, * PIO will migrate this way over time. */int ide_hwif_request_regions(ide_hwif_t *hwif){ unsigned long addr; unsigned int i; if (hwif->mmio) return 0; addr = hwif->io_ports[IDE_CONTROL_OFFSET]; if (addr && !hwif_request_region(hwif, addr, 1)) goto control_region_busy; hwif->straight8 = 0; addr = hwif->io_ports[IDE_DATA_OFFSET]; if ((addr | 7) == hwif->io_ports[IDE_STATUS_OFFSET]) { if (!hwif_request_region(hwif, addr, 8)) goto data_region_busy; hwif->straight8 = 1; return 0; } for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { addr = hwif->io_ports[i]; if (!hwif_request_region(hwif, addr, 1)) { while (--i) release_region(addr, 1); goto data_region_busy; } } return 0;data_region_busy: addr = hwif->io_ports[IDE_CONTROL_OFFSET]; if (addr) release_region(addr, 1);control_region_busy: /* If any errors are return, we drop the hwif interface. */ return -EBUSY;}/** * ide_hwif_release_regions - free IDE resources * * Note that we only release the standard ports, * and do not even try to handle any extra ports * allocated for weird IDE interface chipsets. * * Note also that we don't yet handle mmio resources here. More * importantly our caller should be doing this so we need to * restructure this as a helper function for drivers. */void ide_hwif_release_regions(ide_hwif_t *hwif){ u32 i = 0; if (hwif->mmio) return; if (hwif->io_ports[IDE_CONTROL_OFFSET]) release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); if (hwif->straight8) { release_region(hwif->io_ports[IDE_DATA_OFFSET], 8); return; } for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) if (hwif->io_ports[i]) release_region(hwif->io_ports[i], 1);}/** * ide_hwif_restore - restore hwif to template * @hwif: hwif to update * @tmp_hwif: template * * Restore hwif to a previous state by copying most settings * from the template. */static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif){ hwif->hwgroup = tmp_hwif->hwgroup; hwif->gendev.parent = tmp_hwif->gendev.parent; hwif->proc = tmp_hwif->proc; hwif->major = tmp_hwif->major; hwif->straight8 = tmp_hwif->straight8; hwif->bus_state = tmp_hwif->bus_state; hwif->host_flags = tmp_hwif->host_flags; hwif->pio_mask = tmp_hwif->pio_mask; hwif->ultra_mask = tmp_hwif->ultra_mask; hwif->mwdma_mask = tmp_hwif->mwdma_mask; hwif->swdma_mask = tmp_hwif->swdma_mask; hwif->cbl = tmp_hwif->cbl; hwif->chipset = tmp_hwif->chipset; hwif->hold = tmp_hwif->hold;#ifdef CONFIG_BLK_DEV_IDEPCI hwif->pci_dev = tmp_hwif->pci_dev; hwif->cds = tmp_hwif->cds;#endif hwif->fixup = tmp_hwif->fixup; hwif->set_pio_mode = tmp_hwif->set_pio_mode; hwif->set_dma_mode = tmp_hwif->set_dma_mode; hwif->mdma_filter = tmp_hwif->mdma_filter; hwif->udma_filter = tmp_hwif->udma_filter; hwif->selectproc = tmp_hwif->selectproc; hwif->reset_poll = tmp_hwif->reset_poll; hwif->pre_reset = tmp_hwif->pre_reset; hwif->resetproc = tmp_hwif->resetproc; hwif->intrproc = tmp_hwif->intrproc; hwif->maskproc = tmp_hwif->maskproc; hwif->quirkproc = tmp_hwif->quirkproc; hwif->busproc = tmp_hwif->busproc; hwif->ata_input_data = tmp_hwif->ata_input_data; hwif->ata_output_data = tmp_hwif->ata_output_data; hwif->atapi_input_bytes = tmp_hwif->atapi_input_bytes; hwif->atapi_output_bytes = tmp_hwif->atapi_output_bytes; hwif->dma_setup = tmp_hwif->dma_setup; hwif->dma_exec_cmd = tmp_hwif->dma_exec_cmd; hwif->dma_start = tmp_hwif->dma_start; hwif->ide_dma_end = tmp_hwif->ide_dma_end; hwif->ide_dma_on = tmp_hwif->ide_dma_on; hwif->dma_off_quietly = tmp_hwif->dma_off_quietly; hwif->ide_dma_test_irq = tmp_hwif->ide_dma_test_irq; hwif->ide_dma_clear_irq = tmp_hwif->ide_dma_clear_irq; hwif->dma_host_on = tmp_hwif->dma_host_on; hwif->dma_host_off = tmp_hwif->dma_host_off; hwif->dma_lost_irq = tmp_hwif->dma_lost_irq; hwif->dma_timeout = tmp_hwif->dma_timeout; hwif->OUTB = tmp_hwif->OUTB; hwif->OUTBSYNC = tmp_hwif->OUTBSYNC; hwif->OUTW = tmp_hwif->OUTW; hwif->OUTSW = tmp_hwif->OUTSW; hwif->OUTSL = tmp_hwif->OUTSL; hwif->INB = tmp_hwif->INB; hwif->INW = tmp_hwif->INW; hwif->INSW = tmp_hwif->INSW; hwif->INSL = tmp_hwif->INSL; hwif->sg_max_nents = tmp_hwif->sg_max_nents; hwif->mmio = tmp_hwif->mmio; hwif->rqsize = tmp_hwif->rqsize;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -