ide-probe.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,324 行 · 第 1/3 页

C
1,324
字号
	 *	that is 64K segmenting, standard PRD setup	 *	and LBA28. Some drivers then impose their own	 *	limits and LBA48 we could raise it but as yet	 *	do not.	 */	 	q = blk_init_queue(do_ide_request, &ide_lock);	if (!q)		return 1;	q->queuedata = drive;	blk_queue_segment_boundary(q, 0xffff);	if (!hwif->rqsize) {		if (hwif->no_lba48 || hwif->no_lba48_dma)			hwif->rqsize = 256;		else			hwif->rqsize = 65536;	}	if (hwif->rqsize < max_sectors)		max_sectors = hwif->rqsize;	blk_queue_max_sectors(q, max_sectors);#ifdef CONFIG_PCI	/* When we have an IOMMU, we may have a problem where pci_map_sg()	 * creates segments that don't completely match our boundary	 * requirements and thus need to be broken up again. Because it	 * doesn't align properly either, we may actually have to break up	 * to more segments than what was we got in the first place, a max	 * worst case is twice as many.	 * This will be fixed once we teach pci_map_sg() about our boundary	 * requirements, hopefully soon. *FIXME*	 */	if (!PCI_DMA_BUS_IS_PHYS)		max_sg_entries >>= 1;#endif /* CONFIG_PCI */	blk_queue_max_hw_segments(q, max_sg_entries);	blk_queue_max_phys_segments(q, max_sg_entries);	/* assign drive and gendisk queue */	drive->queue = q;	if (drive->disk)		drive->disk->queue = drive->queue;	/* needs drive->queue to be set */	ide_toggle_bounce(drive, 1);	/* enable led activity for disk drives only */	if (drive->media == ide_disk && hwif->led_act)		blk_queue_activity_fn(q, hwif->led_act, drive);	return 0;}/* * This routine sets up the irq for an ide interface, and creates a new * hwgroup for the irq/hwif if none was previously assigned. * * Much of the code is for correctly detecting/handling irq sharing * and irq serialization situations.  This is somewhat complex because * it handles static as well as dynamic (PCMCIA) IDE interfaces. * * The SA_INTERRUPT in sa_flags means ide_intr() is always entered with * interrupts completely disabled.  This can be bad for interrupt latency, * but anything else has led to problems on some machines.  We re-enable * interrupts as much as we can safely do in most places. */static int init_irq (ide_hwif_t *hwif){	unsigned int index;	ide_hwgroup_t *hwgroup;	ide_hwif_t *match = NULL;	BUG_ON(in_interrupt());	BUG_ON(irqs_disabled());		down(&ide_cfg_sem);	hwif->hwgroup = NULL;#if MAX_HWIFS > 1	/*	 * Group up with any other hwifs that share our irq(s).	 */	for (index = 0; index < MAX_HWIFS; index++) {		ide_hwif_t *h = &ide_hwifs[index];		if (h->hwgroup) {  /* scan only initialized hwif's */			if (hwif->irq == h->irq) {				hwif->sharing_irq = h->sharing_irq = 1;				if (hwif->chipset != ide_pci ||				    h->chipset != ide_pci) {					save_match(hwif, h, &match);				}			}			if (hwif->serialized) {				if (hwif->mate && hwif->mate->irq == h->irq)					save_match(hwif, h, &match);			}			if (h->serialized) {				if (h->mate && hwif->irq == h->mate->irq)					save_match(hwif, h, &match);			}		}	}#endif /* MAX_HWIFS > 1 */	/*	 * If we are still without a hwgroup, then form a new one	 */	if (match) {		hwgroup = match->hwgroup;		hwif->hwgroup = hwgroup;		/*		 * Link us into the hwgroup.		 * This must be done early, do ensure that unexpected_intr		 * can find the hwif and prevent irq storms.		 * No drives are attached to the new hwif, choose_drive		 * can't do anything stupid (yet).		 * Add ourself as the 2nd entry to the hwgroup->hwif		 * linked list, the first entry is the hwif that owns		 * hwgroup->handler - do not change that.		 */		spin_lock_irq(&ide_lock);		hwif->next = hwgroup->hwif->next;		hwgroup->hwif->next = hwif;		spin_unlock_irq(&ide_lock);	} else {		hwgroup = kmalloc(sizeof(ide_hwgroup_t),GFP_KERNEL);		if (!hwgroup)	       		goto out_up;		hwif->hwgroup = hwgroup;		memset(hwgroup, 0, sizeof(ide_hwgroup_t));		hwgroup->hwif     = hwif->next = hwif;		hwgroup->rq       = NULL;		hwgroup->handler  = NULL;		hwgroup->drive    = NULL;		hwgroup->busy     = 0;		init_timer(&hwgroup->timer);		hwgroup->timer.function = &ide_timer_expiry;		hwgroup->timer.data = (unsigned long) hwgroup;	}	/*	 * Allocate the irq, if not already obtained for another hwif	 */	if (!match || match->irq != hwif->irq) {		int sa = SA_INTERRUPT;#if defined(__mc68000__) || defined(CONFIG_APUS)		sa = SA_SHIRQ;#endif /* __mc68000__ || CONFIG_APUS */		if (IDE_CHIPSET_IS_PCI(hwif->chipset)) {			sa = SA_SHIRQ;#ifndef CONFIG_IDEPCI_SHARE_IRQ			sa |= SA_INTERRUPT;#endif /* CONFIG_IDEPCI_SHARE_IRQ */		}		if (hwif->io_ports[IDE_CONTROL_OFFSET])			/* clear nIEN */			hwif->OUTB(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]);		if (request_irq(hwif->irq,&ide_intr,sa,hwif->name,hwgroup))	       		goto out_unlink;	}	/*	 * For any present drive:	 * - allocate the block device queue	 * - link drive into the hwgroup	 */	for (index = 0; index < MAX_DRIVES; ++index) {		ide_drive_t *drive = &hwif->drives[index];		if (!drive->present)			continue;		if (ide_init_queue(drive)) {			printk(KERN_ERR "ide: failed to init %s\n",drive->name);			continue;		}		spin_lock_irq(&ide_lock);		if (!hwgroup->drive) {			/* first drive for hwgroup. */			drive->next = drive;			hwgroup->drive = drive;			hwgroup->hwif = HWIF(hwgroup->drive);		} else {			drive->next = hwgroup->drive->next;			hwgroup->drive->next = drive;		}		spin_unlock_irq(&ide_lock);	}#if !defined(__mc68000__) && !defined(CONFIG_APUS) && !defined(__sparc__)	printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,		hwif->io_ports[IDE_DATA_OFFSET],		hwif->io_ports[IDE_DATA_OFFSET]+7,		hwif->io_ports[IDE_CONTROL_OFFSET], hwif->irq);#elif defined(__sparc__)	printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %s", hwif->name,		hwif->io_ports[IDE_DATA_OFFSET],		hwif->io_ports[IDE_DATA_OFFSET]+7,		hwif->io_ports[IDE_CONTROL_OFFSET], __irq_itoa(hwif->irq));#else	printk("%s at 0x%08lx on irq %d", hwif->name,		hwif->io_ports[IDE_DATA_OFFSET], hwif->irq);#endif /* __mc68000__ && CONFIG_APUS */	if (match)		printk(" (%sed with %s)",			hwif->sharing_irq ? "shar" : "serializ", match->name);	printk("\n");	up(&ide_cfg_sem);	return 0;out_unlink:	spin_lock_irq(&ide_lock);	if (hwif->next == hwif) {		BUG_ON(match);		BUG_ON(hwgroup->hwif != hwif);		kfree(hwgroup);	} else {		ide_hwif_t *g;		g = hwgroup->hwif;		while (g->next != hwif)			g = g->next;		g->next = hwif->next;		if (hwgroup->hwif == hwif) {			/* Impossible. */			printk(KERN_ERR "Duh. Uninitialized hwif listed as active hwif.\n");			hwgroup->hwif = g;		}		BUG_ON(hwgroup->hwif == hwif);	}	spin_unlock_irq(&ide_lock);out_up:	up(&ide_cfg_sem);	return 1;}static int ata_lock(dev_t dev, void *data){	/* FIXME: we want to pin hwif down */	return 0;}extern ide_driver_t idedefault_driver;struct kobject *ata_probe(dev_t dev, int *part, void *data){	ide_hwif_t *hwif = data;	int unit = *part >> PARTN_BITS;	ide_drive_t *drive = &hwif->drives[unit];	if (!drive->present)		return NULL;	if (drive->driver == &idedefault_driver) {		if (drive->media == ide_disk)			(void) request_module("ide-disk");		if (drive->scsi)			(void) request_module("ide-scsi");		if (drive->media == ide_cdrom || drive->media == ide_optical)			(void) request_module("ide-cd");		if (drive->media == ide_tape)			(void) request_module("ide-tape");		if (drive->media == ide_floppy)			(void) request_module("ide-floppy");	}	if (drive->driver == &idedefault_driver)		return NULL;	*part &= (1 << PARTN_BITS) - 1;	return get_disk(drive->disk);}static int alloc_disks(ide_hwif_t *hwif){	unsigned int unit;	struct gendisk *disks[MAX_DRIVES];	for (unit = 0; unit < MAX_DRIVES; unit++) {		disks[unit] = alloc_disk(1 << PARTN_BITS);		if (!disks[unit])			goto Enomem;	}	for (unit = 0; unit < MAX_DRIVES; ++unit) {		ide_drive_t *drive = &hwif->drives[unit];		struct gendisk *disk = disks[unit];		disk->major  = hwif->major;		disk->first_minor = unit << PARTN_BITS;		sprintf(disk->disk_name,"hd%c",'a'+hwif->index*MAX_DRIVES+unit);		disk->fops = ide_fops;		disk->private_data = drive;		drive->disk = disk;	}	return 0;Enomem:	printk(KERN_WARNING "(ide::init_gendisk) Out of memory\n");	while (unit--)		put_disk(disks[unit]);	return -ENOMEM;}static void drive_release_dev (struct device *dev){	ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);	up(&drive->gendev_rel_sem);}/* * init_gendisk() (as opposed to ide_geninit) is called for each major device, * after probing for drives, to allocate partition tables and other data * structures needed for the routines in genhd.c.  ide_geninit() gets called * somewhat later, during the partition check. */static void init_gendisk (ide_hwif_t *hwif){	unsigned int unit;	for (unit = 0; unit < MAX_DRIVES; ++unit) {		ide_drive_t * drive = &hwif->drives[unit];		ide_add_generic_settings(drive);		snprintf(drive->gendev.bus_id,BUS_ID_SIZE,"%u.%u",			 hwif->index,unit);		drive->gendev.parent = &hwif->gendev;		drive->gendev.bus = &ide_bus_type;		drive->gendev.driver_data = drive;		drive->gendev.release = drive_release_dev;		if (drive->present) {			device_register(&drive->gendev);			sprintf(drive->devfs_name, "ide/host%d/bus%d/target%d/lun%d",				(hwif->channel && hwif->mate) ?				hwif->mate->index : hwif->index,				hwif->channel, unit, drive->lun);		}	}	blk_register_region(MKDEV(hwif->major, 0), MAX_DRIVES << PARTN_BITS,			THIS_MODULE, ata_probe, ata_lock, hwif);}static int hwif_init(ide_hwif_t *hwif){	int old_irq, unit;	if (!hwif->present)		return 0;	if (!hwif->irq) {		if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET])))		{			printk("%s: DISABLED, NO IRQ\n", hwif->name);			return (hwif->present = 0);		}	}#ifdef CONFIG_BLK_DEV_HD	if (hwif->irq == HD_IRQ && hwif->io_ports[IDE_DATA_OFFSET] != HD_DATA) {		printk("%s: CANNOT SHARE IRQ WITH OLD "			"HARDDISK DRIVER (hd.c)\n", hwif->name);		return (hwif->present = 0);	}#endif /* CONFIG_BLK_DEV_HD */	/* we set it back to 1 if all is ok below */		hwif->present = 0;	if (register_blkdev(hwif->major, hwif->name))		return 0;	if (alloc_disks(hwif) < 0)		goto out;		if (init_irq(hwif) == 0)		goto done;	old_irq = hwif->irq;	/*	 *	It failed to initialise. Find the default IRQ for 	 *	this port and try that.	 */	if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) {		printk("%s: Disabled unable to get IRQ %d.\n",			hwif->name, old_irq);		goto out_disks;	}	if (init_irq(hwif)) {		printk("%s: probed IRQ %d and default IRQ %d failed.\n",			hwif->name, old_irq, hwif->irq);		goto out_disks;	}	printk("%s: probed IRQ %d failed, using default.\n",		hwif->name, hwif->irq);done:	init_gendisk(hwif);	hwif->present = 1;	/* success */	return 1;out_disks:	for (unit = 0; unit < MAX_DRIVES; unit++) {		struct gendisk *disk = hwif->drives[unit].disk;		hwif->drives[unit].disk = NULL;		put_disk(disk);	}out:	unregister_blkdev(hwif->major, hwif->name);	return 0;}int ideprobe_init (void){	unsigned int index;	int probe[MAX_HWIFS];	memset(probe, 0, MAX_HWIFS * sizeof(int));	for (index = 0; index < MAX_HWIFS; ++index)		probe[index] = !ide_hwifs[index].present;	/*	 * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports	 */	for (index = 0; index < MAX_HWIFS; ++index)		if (probe[index])			probe_hwif(&ide_hwifs[index]);	for (index = 0; index < MAX_HWIFS; ++index)		if (probe[index])			hwif_init(&ide_hwifs[index]);	for (index = 0; index < MAX_HWIFS; ++index) {		if (probe[index]) {			ide_hwif_t *hwif = &ide_hwifs[index];			int unit;			if (!hwif->present)				continue;			if (hwif->chipset == ide_unknown || hwif->chipset == ide_forced)				hwif->chipset = ide_generic;			for (unit = 0; unit < MAX_DRIVES; ++unit)				if (hwif->drives[unit].present)					ata_attach(&hwif->drives[unit]);		}	}	return 0;}EXPORT_SYMBOL_GPL(ideprobe_init);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?