diff options
| author | Linus Torvalds <torvalds@athlon.transmeta.com> | 2002-02-04 20:20:19 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@athlon.transmeta.com> | 2002-02-04 20:20:19 -0800 |
| commit | 0a97b16afbcaadbe4410d78adfe8967398454945 (patch) | |
| tree | a840d4dfa366d426d9063041a6d663386e4c71ac | |
| parent | 5bf3be033f504f5fd79690fbb13d720407314e40 (diff) | |
v2.4.10.2 -> v2.4.10.3
- Al Viro: superblock cleanups, partition handling fixes and cleanups
- Ben Collins: firewire update
- Jeff Garzik: network driver updates
- Urban Widmark: smbfs updates
- Kai Mäkisara: SCSI tape driver update
- various: embarrassing lack of error checking in ELF loader
- Neil Brown: md formatting cleanup.
95 files changed, 4121 insertions, 3820 deletions
@@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 11 -EXTRAVERSION =-pre2 +EXTRAVERSION =-pre3 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c index 657bd0344971..9fee4ad0c33d 100644 --- a/arch/ppc/mm/fault.c +++ b/arch/ppc/mm/fault.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fault.c 1.13 06/28/01 15:50:17 paulus + * BK Id: SCCS/s.fault.c 1.15 09/24/01 16:35:10 paulus */ /* * arch/ppc/mm/fault.c @@ -150,6 +150,7 @@ good_area: * make sure we exit gracefully rather than endlessly redo * the fault. */ + survive: switch (handle_mm_fault(mm, vma, address, is_write)) { case 1: current->min_flt++; @@ -195,6 +196,12 @@ bad_area: */ out_of_memory: up_read(&mm->mmap_sem); + if (current->pid == 1) { + current->policy |= SCHED_YIELD; + schedule(); + down_read(&mm->mmap_sem); + goto survive; + } printk("VM: killing process %s\n", current->comm); if (user_mode(regs)) do_exit(SIGKILL); @@ -346,34 +353,3 @@ get_8xx_pte(struct mm_struct *mm, unsigned long addr) return(retval); } #endif /* CONFIG_8xx */ - -#if 0 -/* - * Misc debugging functions. Please leave them here. -- Cort - */ -void print_pte(struct _PTE p) -{ - printk( -"%08x %08x vsid: %06x h: %01x api: %02x rpn: %05x rcwimg: %d%d%d%d%d%d pp: %02x\n", - *((unsigned long *)(&p)), *((long *)&p+1), - p.vsid, p.h, p.api, p.rpn, - p.r,p.c,p.w,p.i,p.m,p.g,p.pp); -} - -/* - * Search the hw hash table for a mapping to the given physical - * address. -- Cort - */ -unsigned long htab_phys_to_va(unsigned long address) -{ - extern PTE *Hash, *Hash_end; - PTE *ptr; - - for ( ptr = Hash ; ptr < Hash_end ; ptr++ ) - { - if ( ptr->rpn == (address>>12) ) - printk("phys %08lX -> va ???\n", - address); - } -} -#endif diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index b31b61a897a4..2c8fb53a871c 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.init.c 1.34 08/20/01 22:12:43 paulus + * BK Id: SCCS/s.init.c 1.36 09/22/01 14:03:09 paulus */ /* * PowerPC version @@ -44,12 +44,15 @@ #include <asm/smp.h> #include <asm/machdep.h> #include <asm/btext.h> +#include <asm/tlb.h> #include "mem_pieces.h" #include "mmu_decl.h" #define MAX_LOW_MEM (0xF0000000UL - KERNELBASE) +mmu_gather_t mmu_gathers[NR_CPUS]; + void *end_of_DRAM; unsigned long total_memory; unsigned long total_lowmem; diff --git a/arch/ppc/mm/mmu_context.c b/arch/ppc/mm/mmu_context.c index cae4b53c7d1a..ba6784ec812e 100644 --- a/arch/ppc/mm/mmu_context.c +++ b/arch/ppc/mm/mmu_context.c @@ -36,7 +36,7 @@ #include <asm/mmu_context.h> mm_context_t next_mmu_context; -unsigned long context_map[(LAST_CONTEXT+1) / (8*sizeof(unsigned long))]; +unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1]; #ifdef FEW_CONTEXTS atomic_t nr_free_contexts; struct mm_struct *context_mm[LAST_CONTEXT+1]; @@ -57,7 +57,7 @@ void __init mmu_context_init(void) context_map[0] = (1 << FIRST_CONTEXT) - 1; next_mmu_context = FIRST_CONTEXT; #ifdef FEW_CONTEXTS - atomic_set(&nr_free_contexts, LAST_CONTEXT); + atomic_set(&nr_free_contexts, LAST_CONTEXT - FIRST_CONTEXT + 1); #endif /* FEW_CONTEXTS */ } diff --git a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c index d3f35ebbe860..d3630a8c1491 100644 --- a/arch/ppc/mm/pgtable.c +++ b/arch/ppc/mm/pgtable.c @@ -211,12 +211,12 @@ void __init mapin_ram(void) #else if ((char *) v < _stext || (char *) v >= etext) f |= _PAGE_RW | _PAGE_DIRTY; -#ifndef CONFIG_8xx +#ifdef CONFIG_PPC_STD_MMU else - /* On the powerpc (not 8xx), no user access + /* On the powerpc (not all), no user access forces R/W kernel access */ f |= _PAGE_USER; -#endif /* CONFIG_8xx */ +#endif /* CONFIG_PPC_STD_MMU */ #endif /* CONFIG_KGDB */ map_page(v, p, f); v += PAGE_SIZE; diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index ebca79af8ce3..07e235f166b4 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -231,12 +231,12 @@ static struct sysrq_key_op sysrq_sync_op = { static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs, struct kbd_struct *kbd, struct tty_struct *tty) { emergency_sync_scheduled = EMERG_REMOUNT; - wakeup_bdflush(0); + wakeup_bdflush(); } static struct sysrq_key_op sysrq_mountro_op = { handler: sysrq_handle_mountro, help_msg: "Unmount", - action_msg: "Emergency Remount R/0", + action_msg: "Emergency Remount R/O", }; /* END SYNC SYSRQ HANDLERS BLOCK */ diff --git a/drivers/ide/ide-pmac.c b/drivers/ide/ide-pmac.c index 590645be879d..af7603af9e84 100644 --- a/drivers/ide/ide-pmac.c +++ b/drivers/ide/ide-pmac.c @@ -5,9 +5,7 @@ * These IDE interfaces are memory-mapped and have a DBDMA channel * for doing DMA. * - * Copyright (C) 1998 Paul Mackerras. - * - * Bits from Benjamin Herrenschmidt + * Copyright (C) 1998-2001 Paul Mackerras & Ben. Herrenschmidt * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -99,13 +97,13 @@ static pmac_ide_timing udma_timings[] = /* allow up to 256 DBDMA commands per xfer */ #define MAX_DCMDS 256 -/* Wait 1.5s for disk to answer on IDE bus after +/* Wait 2s for disk to answer on IDE bus after * enable operation. * NOTE: There is at least one case I know of a disk that needs about 10sec * before anwering on the bus. I beleive we could add a kernel command * line arg to override this delay for such cases. */ -#define IDE_WAKEUP_DELAY_MS 1500 +#define IDE_WAKEUP_DELAY_MS 2000 static void pmac_ide_setup_dma(struct device_node *np, int ix); static int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive); @@ -236,13 +234,21 @@ wait_for_ready(ide_drive_t *drive) } if((stat & ERR_STAT) || timeout <= 0) { if (stat & ERR_STAT) { - printk("ide_pmace: wait_for_ready, error status: %x\n", stat); + printk(KERN_ERR "ide_pmac: wait_for_ready, error status: %x\n", stat); } return 1; } return 0; } +/* Note: We don't use the generic routine here because some of Apple's + * controller seem to be very sensitive about how things are done. + * We should probably set the NIEN bit, but that's an example of thing + * that can cause the controller to hang under some circumstances when + * done on the media-bay CD-ROM during boot. We do get occasional + * spurrious interrupts because of that. + * --BenH + */ static int pmac_ide_do_setfeature(ide_drive_t *drive, byte command) { @@ -256,7 +262,7 @@ pmac_ide_do_setfeature(ide_drive_t *drive, byte command) SELECT_MASK(HWIF(drive), drive, 0); udelay(1); if(wait_for_ready(drive)) { - printk("pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n"); + printk(KERN_ERR "pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n"); goto out; } OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); @@ -265,7 +271,7 @@ pmac_ide_do_setfeature(ide_drive_t *drive, byte command) udelay(1); result = wait_for_ready(drive); if (result) - printk("pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n"); + printk(KERN_ERR "pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n"); out: restore_flags(flags); @@ -311,7 +317,7 @@ pmac_ide_tuneproc(ide_drive_t *drive, byte pio) } #ifdef IDE_PMAC_DEBUG - printk("ide_pmac: Set PIO timing for mode %d, reg: 0x%08x\n", + printk(KERN_ERR "ide_pmac: Set PIO timing for mode %d, reg: 0x%08x\n", pio, *timings); #endif @@ -562,7 +568,7 @@ pmac_ide_probe(void) fixes in irq.c */ if (np->n_intrs == 0) { - printk("ide: no intrs for device %s, using 13\n", + printk(KERN_WARNING "ide: no intrs for device %s, using 13\n", np->full_name); irq = 13; } else { @@ -598,7 +604,7 @@ pmac_ide_probe(void) feature_set(np, FEATURE_IDE0_enable); } else { /* This is necessary to enable IDE when net-booting */ - printk("pmac_ide: enabling IDE bus ID %d\n", + printk(KERN_INFO "pmac_ide: enabling IDE bus ID %d\n", pmac_ide[i].aapl_bus_id); switch(pmac_ide[i].aapl_bus_id) { case 0: @@ -732,7 +738,7 @@ pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr) unsigned int tc = (size < 0xfe00)? size: 0xfe00; if (++count >= MAX_DCMDS) { - printk("%s: DMA table too small\n", + printk(KERN_WARNING "%s: DMA table too small\n", drive->name); return 0; /* revert to PIO for this request */ } @@ -804,10 +810,10 @@ pmac_ide_mdma_enable(ide_drive_t *drive, int idx) int ret; /* Set feature on drive */ - printk("%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf); + printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf); ret = pmac_ide_do_setfeature(drive, feature); if (ret) { - printk("%s: Failed !\n", drive->name); + printk(KERN_WARNING "%s: Failed !\n", drive->name); return 0; } @@ -860,7 +866,7 @@ pmac_ide_mdma_enable(ide_drive_t *drive, int idx) (accessTicks | (recTicks << 5) | (halfTick << 10)) << 11; } #ifdef IDE_PMAC_DEBUG - printk("ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n", + printk(KERN_INFO "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n", feature & 0xf, *timings); #endif drive->current_speed = feature; @@ -879,10 +885,10 @@ pmac_ide_udma_enable(ide_drive_t *drive, int idx) int ret; /* Set feature on drive */ - printk("%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf); + printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf); ret = pmac_ide_do_setfeature(drive, feature); if (ret) { - printk("%s: Failed !\n", drive->name); + printk(KERN_WARNING "%s: Failed !\n", drive->name); return 0; } @@ -953,7 +959,7 @@ pmac_ide_check_dma(ide_drive_t *drive) int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { - int ix, dstat; + int ix, dstat, i; volatile struct dbdma_regs *dma; /* Can we stuff a pointer to our intf structure in config_data @@ -966,7 +972,7 @@ int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) switch (func) { case ide_dma_off: - printk("%s: DMA disabled\n", drive->name); + printk(KERN_INFO "%s: DMA disabled\n", drive->name); case ide_dma_off_quietly: drive->using_dma = 0; break; @@ -994,7 +1000,27 @@ int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) /* verify good dma status */ return (dstat & (RUN|DEAD|ACTIVE)) != RUN; case ide_dma_test_irq: - return (in_le32(&dma->status) & (RUN|ACTIVE)) == RUN; + if ((in_le32(&dma->status) & (RUN|ACTIVE)) == RUN) + return 1; + /* That's a bit ugly and dangerous, but works in our case + * to workaround a problem with the channel status staying + * active if the drive returns an error + */ + if (IDE_CONTROL_REG) { + byte stat; + stat = GET_ALTSTAT(); + if (stat & ERR_STAT) + return 1; + } + /* In some edge cases, some datas may still be in the dbdma + * engine fifo, we wait a bit for dbdma to complete + */ + while ((in_le32(&dma->status) & (RUN|ACTIVE)) != RUN) { + if (++i > 100) + return 0; + udelay(1); + } + return 1; /* Let's implement tose just in case someone wants them */ case ide_dma_bad_drive: @@ -1005,10 +1031,10 @@ int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) case ide_dma_retune: case ide_dma_lostirq: case ide_dma_timeout: - printk("ide_pmac_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func), func); + printk(KERN_WARNING "ide_pmac_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func), func); return 1; default: - printk("ide_pmac_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func); + printk(KERN_WARNING "ide_pmac_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func); return 1; } return 0; @@ -1016,13 +1042,15 @@ int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ #ifdef CONFIG_PMAC_PBOOK -static void idepmac_sleep_disk(int i, unsigned long base) +static void idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base) { - struct device_node* np = pmac_ide[i].node; int j; - - /* FIXME: We only handle the master IDE */ - if (ide_hwifs[i].drives[0].media == ide_disk) { + + /* FIXME: We only handle the master IDE disk, we shoud + * try to fix CD-ROMs here + */ + switch (drive->media) { + case ide_disk: /* Spin down the drive */ outb(0xa0, base+0x60); outb(0x0, base+0x30); @@ -1038,86 +1066,112 @@ static void idepmac_sleep_disk(int i, unsigned long base) if (!(status & BUSY_STAT) && (status & DRQ_STAT)) break; } - } - feature_set(np, FEATURE_IDE0_reset); - feature_clear(np, FEATURE_IDE0_enable); - switch(pmac_ide[i].aapl_bus_id) { - case 0: - feature_set(np, FEATURE_IDE0_reset); - feature_clear(np, FEATURE_IDE0_enable); break; - case 1: - feature_set(np, FEATURE_IDE1_reset); - feature_clear(np, FEATURE_IDE1_enable); + case ide_cdrom: + // todo break; - case 2: - feature_set(np, FEATURE_IDE2_reset); + case ide_floppy: + // todo break; } - pmac_ide[i].timings[0] = 0; - pmac_ide[i].timings[1] = 0; } -static void idepmac_wake_disk(int i, unsigned long base) +static void idepmac_wake_device(ide_drive_t *drive, int used_dma) + { + /* We force the IDE subdriver to check for a media change + * This must be done first or we may lost the condition + * + * Problem: This can schedule. I moved the block device + * wakeup almost late by priority because of that. + */ + if (DRIVER(drive) && DRIVER(drive)->media_change) + DRIVER(drive)->media_change(drive); + + /* We kick the VFS too (see fix in ide.c revalidate) */ + check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS)); + +#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC + /* We re-enable DMA on the drive if it was active. */ + /* This doesn't work with the CD-ROM in the media-bay, probably + * because of a pending unit attention. The problem if that if I + * clear the error, the filesystem dies. + */ + if (used_dma && !ide_spin_wait_hwgroup(drive)) { + /* Lock HW group */ + HWGROUP(drive)->busy = 1; + pmac_ide_check_dma(drive); + HWGROUP(drive)->busy = 0; + spin_unlock_irq(&io_request_lock); + } +#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ +} + +static void idepmac_sleep_interface(int i, unsigned base, int mediabay) { struct device_node* np = pmac_ide[i].node; - int j; - /* Revive IDE disk and controller */ + /* We clear the timings */ + pmac_ide[i].timings[0] = 0; + pmac_ide[i].timings[1] = 0; + + /* The media bay will handle itself just fine */ + if (mediabay) + return; + + /* Disable and reset the bus */ + feature_set(np, FEATURE_IDE0_reset); + feature_clear(np, FEATURE_IDE0_enable); switch(pmac_ide[i].aapl_bus_id) { case 0: feature_set(np, FEATURE_IDE0_reset); - mdelay(10); - feature_set(np, FEATURE_IDE0_enable); - mdelay(10); - feature_clear(np, FEATURE_IDE0_reset); + feature_clear(np, FEATURE_IDE0_enable); break; case 1: feature_set(np, FEATURE_IDE1_reset); - mdelay(10); - feature_set(np, FEATURE_IDE1_enable); - mdelay(10); - feature_clear(np, FEATURE_IDE1_reset); + feature_clear(np, FEATURE_IDE1_enable); break; case 2: - /* This one exists only for KL, I don't know - about any enable bit */ feature_set(np, FEATURE_IDE2_reset); - mdelay(10); - feature_clear(np, FEATURE_IDE2_reset); break; } - mdelay(IDE_WAKEUP_DELAY_MS); - - /* Reset timings */ - pmac_ide_selectproc(&ide_hwifs[i].drives[0]); - mdelay(10); - - /* Wait up to 10 seconds (enough for recent drives) */ - for (j = 0; j < 100; j++) { - int status; - mdelay(100); - status = inb(base + 0x70); - if (!(status & BUSY_STAT)) - break; - } } -/* Here we handle media bay devices */ -static void -idepmac_wake_bay(int i, unsigned long base) +static void idepmac_wake_interface(int i, unsigned long base, int mediabay) { - int timeout; + struct device_node* np = pmac_ide[i].node; + if (!mediabay) { + /* Revive IDE disk and controller */ + switch(pmac_ide[i].aapl_bus_id) { + case 0: + feature_set(np, FEATURE_IDE0_reset); + feature_set(np, FEATURE_IOBUS_enable); + mdelay(10); + feature_set(np, FEATURE_IDE0_enable); + mdelay(10); + feature_clear(np, FEATURE_IDE0_reset); + break; + case 1: + feature_set(np, FEATURE_IDE1_reset); + feature_set(np, FEATURE_IOBUS_enable); + mdelay(10); + feature_set(np, FEATURE_IDE1_enable); + mdelay(10); + feature_clear(np, FEATURE_IDE1_reset); + break; + case 2: + /* This one exists only for KL, I don't know + about any enable bit */ + feature_set(np, FEATURE_IDE2_reset); + mdelay(10); + feature_clear(np, FEATURE_IDE2_reset); + break; + } + } + /* Reset timings */ pmac_ide_selectproc(&ide_hwifs[i].drives[0]); mdelay(10); - - timeout = 10000; - while ((inb(base + 0x70) & BUSY_STAT) && timeout) { - mdelay(1); - --timeout; - } } /* Note: We support only master drives for now. This will have to be @@ -1128,6 +1182,8 @@ static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when) { int i, ret; unsigned long base; + unsigned long flags; + int big_delay; switch (when) { case PBOOK_SLEEP_REQUEST: @@ -1136,34 +1192,104 @@ static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when) break; case PBOOK_SLEEP_NOW: for (i = 0; i < pmac_ide_count; ++i) { + ide_hwif_t *hwif; + ide_drive_t *drive; + int unlock = 0; + if ((base = pmac_ide[i].regbase) == 0) - continue; + continue; + + hwif = &ide_hwifs[i]; + drive = &hwif->drives[0]; + + if (drive->present) { + /* Wait for HW group to complete operations */ + if (ide_spin_wait_hwgroup(drive)) { + // What can we do here ? Wake drive we had already + // put to sleep and return an error ? + } else { + unlock = 1; + /* Lock HW group */ + HWGROUP(drive)->busy = 1; + + /* Stop the device */ + idepmac_sleep_device(drive, i, base); + + } + } /* Disable irq during sleep */ disable_irq(pmac_ide[i].irq); + if (unlock) + spin_unlock_irq(&io_request_lock); + + /* Check if this is a media bay with an IDE device or not + * a media bay. + */ ret = check_media_bay_by_base(base, MB_CD); - if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present) - /* not media bay - put the disk to sleep */ - idepmac_sleep_disk(i, base); + if ((ret == 0) || (ret == -ENODEV)) + idepmac_sleep_interface(i, base, (ret == 0)); } break; case PBOOK_WAKE: + big_delay = 0; + for (i = 0; i < pmac_ide_count; ++i) { + + if ((base = pmac_ide[i].regbase) == 0) + continue; + + /* Check if this is a media bay with an IDE device or not + * a media bay + */ + ret = check_media_bay_by_base(base, MB_CD); + if ((ret == 0) || (ret == -ENODEV)) { + idepmac_wake_interface(i, base, (ret == 0)); + big_delay = 1; + } + + } + /* Let hardware get up to speed */ + if (big_delay) + mdelay(IDE_WAKEUP_DELAY_MS); + for (i = 0; i < pmac_ide_count; ++i) { ide_hwif_t *hwif; + ide_drive_t *drive; + int j, used_dma; + if ((base = pmac_ide[i].regbase) == 0) continue; + hwif = &ide_hwifs[i]; - /* We don't handle media bay devices this way */ - ret = check_media_bay_by_base(base, MB_CD); - if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present) - idepmac_wake_disk(i, base); - else if (ret == 0) - idepmac_wake_bay(i, base); - enable_irq(pmac_ide[i].irq); + drive = &hwif->drives[0]; + + /* Wait for the drive to come up and set it's DMA */ + if (drive->present) { + /* Wait up to 20 seconds */ + for (j = 0; j < 200; j++) { + int status; + mdelay(100); + status = inb(base + 0x70); + if (!(status & BUSY_STAT)) + break; + } + } + + /* We don't have re-configured DMA yet */ + used_dma = drive->using_dma; + drive->using_dma = 0; -#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC - if (hwif->drives[0].present && hwif->drives[0].using_dma) - pmac_ide_check_dma(&hwif->drives[0]); -#endif + /* We resume processing on the HW group */ + spin_lock_irqsave(&io_request_lock, flags); + enable_irq(pmac_ide[i].irq); + if (drive->present) + HWGROUP(drive)->busy = 0; + spin_unlock_irqrestore(&io_request_lock, flags); + + /* Wake the device + * We could handle the slave here + */ + if (drive->present) + idepmac_wake_device(drive, used_dma); } break; } diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c index e33b5ed75db1..3f337eb5d599 100644 --- a/drivers/ieee1394/highlevel.c +++ b/drivers/ieee1394/highlevel.c @@ -154,21 +154,18 @@ void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, } -#define DEFINE_MULTIPLEXER(Function) \ -void highlevel_##Function(struct hpsb_host *host) \ -{ \ - struct list_head *entry,*next; \ - void (*funcptr)(struct hpsb_host*); \ - read_lock(&hl_drivers_lock); \ - entry = hl_drivers.next; \ - while (entry != &hl_drivers) { \ - next = entry->next; \ - funcptr = list_entry(entry, struct hpsb_highlevel, hl_list) \ - ->op->Function; \ - if (funcptr) funcptr(host); \ - entry = next; \ - } \ - read_unlock(&hl_drivers_lock); \ +#define DEFINE_MULTIPLEXER(Function) \ +void highlevel_##Function(struct hpsb_host *host) \ +{ \ + struct list_head *lh; \ + void (*funcptr)(struct hpsb_host*); \ + read_lock(&hl_drivers_lock); \ + list_for_each(lh, &hl_drivers) { \ + funcptr = list_entry(lh, struct hpsb_highlevel, hl_list) \ + ->op->Function; \ + if (funcptr) funcptr(host); \ + } \ + read_unlock(&hl_drivers_lock); \ } DEFINE_MULTIPLEXER(add_host) diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c index 0c1ed7426270..01019eddafc6 100644 --- a/drivers/ieee1394/hosts.c +++ b/drivers/ieee1394/hosts.c @@ -23,8 +23,8 @@ #include "highlevel.h" -static struct hpsb_host_template *templates = NULL; -spinlock_t templates_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(templates); +static spinlock_t templates_lock = SPIN_LOCK_UNLOCKED; /* * This function calls the add_host/remove_host hooks for every host currently @@ -32,13 +32,16 @@ spinlock_t templates_lock = SPIN_LOCK_UNLOCKED; */ void hl_all_hosts(struct hpsb_highlevel *hl, int init) { + struct list_head *tlh, *hlh; struct hpsb_host_template *tmpl; struct hpsb_host *host; spin_lock(&templates_lock); - for (tmpl = templates; tmpl != NULL; tmpl = tmpl->next) { - for (host = tmpl->hosts; host != NULL; host = host->next) { + list_for_each(tlh, &templates) { + tmpl = list_entry(tlh, struct hpsb_host_template, list); + list_for_each(hlh, &tmpl->hosts) { + host = list_entry(hlh, struct hpsb_host, list); if (host->initialized) { if (init) { if (hl->op->add_host) { @@ -58,21 +61,24 @@ void hl_all_hosts(struct hpsb_highlevel *hl, int init) int hpsb_inc_host_usage(struct hpsb_host *host) { + struct list_head *tlh, *hlh; struct hpsb_host_template *tmpl; - struct hpsb_host *h; int retval = 0; unsigned long flags; spin_lock_irqsave(&templates_lock, flags); - for (tmpl = templates; (tmpl != NULL) && !retval; tmpl = tmpl->next) { - for (h = tmpl->hosts; h != NULL; h = h->next) { - if (h == host) { - tmpl->devctl(h, MODIFY_USAGE, 1); + list_for_each(tlh, &templates) { + tmpl = list_entry(tlh, struct hpsb_host_template, list); + list_for_each(hlh, &tmpl->hosts) { + if (host == list_entry(hlh, struct hpsb_host, list)) { + tmpl->devctl(host, MODIFY_USAGE, 1); retval = 1; break; } } + if (retval) + break; } spin_unlock_irqrestore(&templates_lock, flags); @@ -113,32 +119,22 @@ struct hpsb_host *hpsb_get_host(struct hpsb_host_template *tmpl, h->speed_map = (u8 *)(h->csr.speed_map + 2); h->template = tmpl; - if (hd_size) { + if (hd_size) h->hostdata = &h->embedded_hostdata[0]; - } - - if (tmpl->hosts == NULL) { - tmpl->hosts = h; - } else { - struct hpsb_host *last = tmpl->hosts; - while (last->next != NULL) { - last = last->next; - } - last->next = h; - } + list_add_tail(&h->list, &tmpl->hosts); return h; } static void free_all_hosts(struct hpsb_host_template *tmpl) { - struct hpsb_host *next, *host = tmpl->hosts; + struct list_head *hlh, *next; + struct hpsb_host *host; - while (host) { - next = host->next; + list_for_each_safe(hlh, next, &tmpl->hosts) { + host = list_entry(hlh, struct hpsb_host, list); vfree(host); - host = next; } } @@ -146,11 +142,13 @@ static void free_all_hosts(struct hpsb_host_template *tmpl) static void init_hosts(struct hpsb_host_template *tmpl) { int count; + struct list_head *hlh; struct hpsb_host *host; count = tmpl->detect_hosts(tmpl); - for (host = tmpl->hosts; host != NULL; host = host->next) { + list_for_each(hlh, &tmpl->hosts) { + host = list_entry(hlh, struct hpsb_host, list); if (tmpl->initialize_host(host)) { host->initialized = 1; @@ -166,9 +164,11 @@ static void init_hosts(struct hpsb_host_template *tmpl) static void shutdown_hosts(struct hpsb_host_template *tmpl) { + struct list_head *hlh; struct hpsb_host *host; - for (host = tmpl->hosts; host != NULL; host = host->next) { + list_for_each(hlh, &tmpl->hosts) { + host = list_entry(hlh, struct hpsb_host, list); if (host->initialized) { host->initialized = 0; abort_requests(host); @@ -188,68 +188,17 @@ static void shutdown_hosts(struct hpsb_host_template *tmpl) } -static int add_template(struct hpsb_host_template *new) -{ - new->next = NULL; - new->hosts = NULL; - new->number_of_hosts = 0; - - spin_lock(&templates_lock); - if (templates == NULL) { - templates = new; - } else { - struct hpsb_host_template *last = templates; - while (last->next != NULL) { - last = last->next; - } - last->next = new; - } - spin_unlock(&templates_lock); - - return 0; -} - -static int remove_template(struct hpsb_host_template *tmpl) -{ - int retval = 0; - - if (tmpl->number_of_hosts) { - HPSB_ERR("attempted to remove busy host template " - "of %s at address 0x%p", tmpl->name, tmpl); - return 1; - } - - spin_lock(&templates_lock); - if (templates == tmpl) { - templates = tmpl->next; - } else { - struct hpsb_host_template *t; - - t = templates; - while (t->next != tmpl && t->next != NULL) { - t = t->next; - } - - if (t->next == NULL) { - HPSB_ERR("attempted to remove unregistered host template " - "of %s at address 0x%p", tmpl->name, tmpl); - retval = -1; - } else { - t->next = tmpl->next; - } - } - spin_unlock(&templates_lock); - - return retval; -} - - /* * The following two functions are exported symbols for module usage. */ int hpsb_register_lowlevel(struct hpsb_host_template *tmpl) { - add_template(tmpl); + INIT_LIST_HEAD(&tmpl->hosts); + tmpl->number_of_hosts = 0; + + spin_lock(&templates_lock); + list_add_tail(&tmpl->list, &templates); + spin_unlock(&templates_lock); /* PCI cards should be smart and use the PCI detection layer, and * not this one shot deal. detect_hosts() will be obsoleted soon. */ @@ -265,7 +214,12 @@ void hpsb_unregister_lowlevel(struct hpsb_host_template *tmpl) { shutdown_hosts(tmpl); - if (remove_template(tmpl)) { - HPSB_PANIC("remove_template failed on %s", tmpl->name); - } + if (tmpl->number_of_hosts) + HPSB_PANIC("attempted to remove busy host template " + "of %s at address 0x%p", tmpl->name, tmpl); + else { + spin_lock(&templates_lock); + list_del(&tmpl->list); + spin_unlock(&templates_lock); + } } diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h index 2f3c34771913..a58d415ab0b3 100644 --- a/drivers/ieee1394/hosts.h +++ b/drivers/ieee1394/hosts.h @@ -3,6 +3,7 @@ #include <linux/wait.h> #include <linux/tqueue.h> +#include <linux/list.h> #include <asm/semaphore.h> #include "ieee1394_types.h" @@ -13,7 +14,7 @@ struct hpsb_packet; struct hpsb_host { /* private fields (hosts, do not use them) */ - struct hpsb_host *next; + struct list_head list; atomic_t generation; @@ -109,9 +110,9 @@ enum reset_types { }; struct hpsb_host_template { - struct hpsb_host_template *next; + struct list_head list; - struct hpsb_host *hosts; + struct list_head hosts; int number_of_hosts; /* fields above will be ignored and overwritten after registering */ diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index fe58e3a33bc0..b19bd5d43909 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -17,6 +17,7 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <asm/bitops.h> #include <asm/byteorder.h> #include <asm/semaphore.h> @@ -30,6 +31,13 @@ #include "csr.h" #include "nodemgr.h" +/* + * Disable the nodemgr detection and config rom reading functionality. + */ +MODULE_PARM(disable_nodemgr, "i"); +MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality."); +static int disable_nodemgr = 0; + static kmem_cache_t *hpsb_packet_cache; @@ -95,7 +103,7 @@ struct hpsb_packet *alloc_hpsb_packet(size_t data_size) INIT_TQ_HEAD(packet->complete_tq); INIT_LIST_HEAD(&packet->list); sema_init(&packet->state_change, 0); - packet->state = unused; + packet->state = hpsb_unused; packet->generation = -1; packet->data_be = 1; @@ -352,14 +360,14 @@ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, } if (ackcode != ACK_PENDING || !packet->expect_response) { - packet->state = completed; + packet->state = hpsb_complete; up(&packet->state_change); up(&packet->state_change); run_task_queue(&packet->complete_tq); return; } - packet->state = pending; + packet->state = hpsb_pending; packet->sendtime = jiffies; spin_lock_irqsave(&host->pending_pkt_lock, flags); @@ -393,9 +401,9 @@ int hpsb_send_packet(struct hpsb_packet *packet) return 0; } - packet->state = queued; + packet->state = hpsb_queued; - if (packet->type == async && packet->node_id != ALL_NODES) { + if (packet->type == hpsb_async && packet->node_id != ALL_NODES) { packet->speed_code = host->speed_map[(host->node_id & NODE_MASK) * 64 + (packet->node_id & NODE_MASK)]; @@ -503,14 +511,14 @@ void handle_packet_response(struct hpsb_host *host, int tcode, quadlet_t *data, break; } - packet->state = completed; + packet->state = hpsb_complete; up(&packet->state_change); run_task_queue(&packet->complete_tq); } -struct hpsb_packet *create_reply_packet(struct hpsb_host *host, quadlet_t *data, - size_t dsize) +static struct hpsb_packet *create_reply_packet(struct hpsb_host *host, + quadlet_t *data, size_t dsize) { struct hpsb_packet *p; @@ -522,13 +530,15 @@ struct hpsb_packet *create_reply_packet(struct hpsb_host *host, quadlet_t *data, return NULL; } - p->type = async; - p->state = unused; + p->type = hpsb_async; + p->state = hpsb_unused; p->host = host; p->node_id = data[1] >> 16; p->tlabel = (data[0] >> 10) & 0x3f; p->no_waiter = 1; + p->generation = get_hpsb_generation(host); + if (dsize % 4) { p->data[dsize / 4] = 0; } @@ -540,8 +550,8 @@ struct hpsb_packet *create_reply_packet(struct hpsb_host *host, quadlet_t *data, packet = create_reply_packet(host, data, length); \ if (packet == NULL) break -void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data, - size_t size, int write_acked) +static void handle_incoming_packet(struct hpsb_host *host, int tcode, + quadlet_t *data, size_t size, int write_acked) { struct hpsb_packet *packet; int length, rcode, extcode; @@ -720,7 +730,7 @@ void abort_requests(struct hpsb_host *host) list_for_each(lh, &llist) { packet = list_entry(lh, struct hpsb_packet, list); - packet->state = completed; + packet->state = hpsb_complete; packet->ack_code = ACKX_ABORTED; up(&packet->state_change); run_task_queue(&packet->complete_tq); @@ -732,7 +742,7 @@ void abort_timedouts(struct hpsb_host *host) unsigned long flags; struct hpsb_packet *packet; unsigned long expire; - struct list_head *lh; + struct list_head *lh, *next; LIST_HEAD(expiredlist); spin_lock_irqsave(&host->csr.lock, flags); @@ -746,8 +756,9 @@ void abort_timedouts(struct hpsb_host *host) spin_lock_irqsave(&host->pending_pkt_lock, flags); - list_for_each(lh, &host->pending_packets) { + for (lh = host->pending_packets.next; lh != &host->pending_packets; lh = next) { packet = list_entry(lh, struct hpsb_packet, list); + next = lh->next; if (time_before(packet->sendtime + expire, jiffies)) { list_del(&packet->list); list_add(&packet->list, &expiredlist); @@ -761,7 +772,7 @@ void abort_timedouts(struct hpsb_host *host) list_for_each(lh, &expiredlist) { packet = list_entry(lh, struct hpsb_packet, list); - packet->state = completed; + packet->state = hpsb_complete; packet->ack_code = ACKX_TIMEOUT; up(&packet->state_change); run_task_queue(&packet->complete_tq); @@ -775,13 +786,19 @@ static int __init ieee1394_init(void) 0, 0, NULL, NULL); init_hpsb_highlevel(); init_csr(); - init_ieee1394_nodemgr(); + if (!disable_nodemgr) + init_ieee1394_nodemgr(); + else + HPSB_INFO("nodemgr functionality disabled"); + return 0; } static void __exit ieee1394_cleanup(void) { - cleanup_ieee1394_nodemgr(); + if (!disable_nodemgr) + cleanup_ieee1394_nodemgr(); + cleanup_csr(); kmem_cache_destroy(hpsb_packet_cache); } diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h index c1ebc47ad626..fa5d65fb785b 100644 --- a/drivers/ieee1394/ieee1394_core.h +++ b/drivers/ieee1394/ieee1394_core.h @@ -20,16 +20,16 @@ struct hpsb_packet { /* Async and Iso types should be clear, raw means send-as-is, do not * CRC! Byte swapping shall still be done in this case. */ - enum { async, iso, raw } __attribute__((packed)) type; + enum { hpsb_async, hpsb_iso, hpsb_raw } __attribute__((packed)) type; /* Okay, this is core internal and a no care for hosts. * queued = queued for sending * pending = sent, waiting for response - * completed = processing completed, successful or not + * complete = processing completed, successful or not * incoming = incoming packet */ enum { - unused, queued, pending, completed, incoming + hpsb_unused, hpsb_queued, hpsb_pending, hpsb_complete, hpsb_incoming } __attribute__((packed)) state; /* These are core internal. */ diff --git a/drivers/ieee1394/ieee1394_hotplug.h b/drivers/ieee1394/ieee1394_hotplug.h index 6de64a4cc504..f5933274accd 100644 --- a/drivers/ieee1394/ieee1394_hotplug.h +++ b/drivers/ieee1394/ieee1394_hotplug.h @@ -2,32 +2,75 @@ #define _IEEE1394_HOTPLUG_H #include "ieee1394_core.h" +#include "nodemgr.h" -#define IEEE1394_DEVICE_ID_MATCH_VENDOR_ID 0x0001 -#define IEEE1394_DEVICE_ID_MATCH_MODEL_ID 0x0002 -#define IEEE1394_DEVICE_ID_MATCH_SW_SPECIFIER_ID 0x0004 -#define IEEE1394_DEVICE_ID_MATCH_SW_SPECIFIER_VERSION 0x0008 +#define IEEE1394_MATCH_VENDOR_ID 0x0001 +#define IEEE1394_MATCH_MODEL_ID 0x0002 +#define IEEE1394_MATCH_SPECIFIER_ID 0x0004 +#define IEEE1394_MATCH_VERSION 0x0008 struct ieee1394_device_id { u32 match_flags; u32 vendor_id; u32 model_id; - u32 sw_specifier_id; - u32 sw_specifier_version; + u32 specifier_id; + u32 version; + void *driver_data; }; -#define IEEE1394_PROTOCOL(id, version) { \ - match_flags: IEEE1394_DEVICE_ID_MATCH_SW_SPECIFIER_ID | \ - IEEE1394_DEVICE_ID_MATCH_SW_SPECIFIER_VERSION, \ - sw_specifier_id: id, \ - sw_specifier_version: version \ -} - -#define IEEE1394_DEVICE(vendor_id, model_id) { \ - match_flags: IEEE1394_DEVICE_ID_MATCH_VENDOR_ID | \ - IEEE1394_DEVICE_ID_MATCH_MODEL_ID, \ - vendor_id: vendor_id, \ - model_id: vendor_id, \ -} +struct hpsb_protocol_driver { + /* The name of the driver, e.g. SBP2 or IP1394 */ + const char *name; + + /* + * The device id table describing the protocols and/or devices + * supported by this driver. This is used by the nodemgr to + * decide if a driver could support a given node, but the + * probe function below can implement further protocol + * dependent or vendor dependent checking. + */ + struct ieee1394_device_id *id_table; + + /* + * The probe function is called when a device is added to the + * bus and the nodemgr finds a matching entry in the drivers + * device id table or when registering this driver and a + * previously unhandled device can be handled. The driver may + * decline to handle the device based on further investigation + * of the device (or whatever reason) in which case a negative + * error code should be returned, otherwise 0 should be + * returned. The driver may use the driver_data field in the + * unit directory to store per device driver specific data. + */ + int (*probe)(struct unit_directory *ud); + + /* + * The disconnect function is called when a device is removed + * from the bus or if it wasn't possible to read the guid + * after the last bus reset. + */ + void (*disconnect)(struct unit_directory *ud); + + /* + * The update function is called when the node has just + * survived a bus reset, i.e. it is still present on the bus. + * However, it may be necessary to reestablish the connection + * or login into the node again, depending on the protocol. + */ + void (*update)(struct unit_directory *ud); + + /* Driver in list of all registered drivers */ + struct list_head list; + + /* The list of unit directories managed by this driver */ + struct list_head unit_directories; +}; + +int hpsb_register_protocol(struct hpsb_protocol_driver *driver); +void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver); + +int hpsb_claim_unit_directory(struct unit_directory *ud, + struct hpsb_protocol_driver *driver); +void hpsb_release_unit_directory(struct unit_directory *ud); #endif /* _IEEE1394_HOTPLUG_H */ diff --git a/drivers/ieee1394/ieee1394_syms.c b/drivers/ieee1394/ieee1394_syms.c index e5a07889a543..4b9324dd9cec 100644 --- a/drivers/ieee1394/ieee1394_syms.c +++ b/drivers/ieee1394/ieee1394_syms.c @@ -18,6 +18,7 @@ #include "hosts.h" #include "ieee1394_core.h" #include "ieee1394_transactions.h" +#include "ieee1394_hotplug.h" #include "highlevel.h" #include "nodemgr.h" @@ -75,8 +76,12 @@ EXPORT_SYMBOL(highlevel_add_host); EXPORT_SYMBOL(highlevel_remove_host); EXPORT_SYMBOL(highlevel_host_reset); EXPORT_SYMBOL(highlevel_add_one_host); + EXPORT_SYMBOL(hpsb_guid_get_entry); EXPORT_SYMBOL(hpsb_nodeid_get_entry); EXPORT_SYMBOL(hpsb_get_host_by_ne); EXPORT_SYMBOL(hpsb_guid_fill_packet); +EXPORT_SYMBOL(hpsb_register_protocol); +EXPORT_SYMBOL(hpsb_unregister_protocol); +EXPORT_SYMBOL(hpsb_release_unit_directory); MODULE_LICENSE("GPL"); diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c index 95b85139f0b8..7086bc7e2caa 100644 --- a/drivers/ieee1394/ieee1394_transactions.c +++ b/drivers/ieee1394/ieee1394_transactions.c @@ -131,7 +131,7 @@ void fill_iso_packet(struct hpsb_packet *packet, int length, int channel, packet->header_size = 4; packet->data_size = length; - packet->type = iso; + packet->type = hpsb_iso; packet->tcode = TCODE_ISO_DATA; } @@ -142,7 +142,7 @@ void fill_phy_packet(struct hpsb_packet *packet, quadlet_t data) packet->header_size = 8; packet->data_size = 0; packet->expect_response = 0; - packet->type = raw; /* No CRC added */ + packet->type = hpsb_raw; /* No CRC added */ packet->speed_code = SPEED_100; /* Force speed to be 100Mbps */ } @@ -488,7 +488,9 @@ struct hpsb_packet *hpsb_make_packet (struct hpsb_host *host, nodeid_t node, if (!packet) return NULL; - if (length != 4) + /* Sometimes this may be called without data, just to allocate the + * packet. */ + if (length != 4 && buffer) memcpy(packet->data, buffer, length); return packet; diff --git a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h index 1385070dd984..185cecacb444 100644 --- a/drivers/ieee1394/ieee1394_types.h +++ b/drivers/ieee1394/ieee1394_types.h @@ -26,6 +26,13 @@ #include <linux/spinlock.h> #endif +#ifndef list_for_each_safe +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +#endif + #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 37ac83b29244..7b1ee818652a 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -15,11 +15,13 @@ #include <asm/atomic.h> #include <linux/smp_lock.h> #include <linux/interrupt.h> +#include <linux/kmod.h> #include "ieee1394_types.h" #include "ieee1394.h" #include "hosts.h" #include "ieee1394_transactions.h" +#include "ieee1394_hotplug.h" #include "highlevel.h" #include "csr.h" #include "nodemgr.h" @@ -47,6 +49,16 @@ static LIST_HEAD(node_list); static rwlock_t node_lock = RW_LOCK_UNLOCKED; +static LIST_HEAD(driver_list); +static rwlock_t driver_lock = RW_LOCK_UNLOCKED; + +/* The rwlock unit_directory_lock is always held when manipulating the + * global unit_directory_list, but this also protects access to the + * lists of unit directories stored in the protocol drivers. + */ +static LIST_HEAD(unit_directory_list); +static rwlock_t unit_directory_lock = RW_LOCK_UNLOCKED; + static LIST_HEAD(host_info_list); static spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED; @@ -56,7 +68,12 @@ struct host_info { struct list_head list; }; -static struct node_entry *create_node_entry(void) +static void nodemgr_process_config_rom(struct node_entry *ne, + quadlet_t busoptions); + + +static struct node_entry *nodemgr_create_node(octlet_t guid, quadlet_t busoptions, + struct hpsb_host *host, nodeid_t nodeid) { struct node_entry *ne; unsigned long flags; @@ -66,15 +83,21 @@ static struct node_entry *create_node_entry(void) INIT_LIST_HEAD(&ne->list); INIT_LIST_HEAD(&ne->unit_directories); - ne->guid = (u64) -1; - ne->host = NULL; - ne->nodeid = 0; - atomic_set(&ne->generation, -1); + ne->host = host; + ne->nodeid = nodeid; + ne->guid = guid; + atomic_set(&ne->generation, get_hpsb_generation(ne->host)); write_lock_irqsave(&node_lock, flags); list_add_tail(&ne->list, &node_list); write_unlock_irqrestore(&node_lock, flags); + nodemgr_process_config_rom (ne, busoptions); + + HPSB_DEBUG("%s added: node " NODE_BUS_FMT ", GUID %016Lx", + (host->node_id == nodeid) ? "Local host" : "Device", + NODE_BUS_ARGS(nodeid), (unsigned long long)guid); + return ne; } @@ -104,16 +127,20 @@ static struct node_entry *find_entry_by_nodeid(nodeid_t nodeid) return NULL; } -int nodemgr_read_quadlet(struct node_entry *ne, +int nodemgr_read_quadlet(struct node_entry *ne, octlet_t address, quadlet_t *quad) { - if (hpsb_read(ne->host, ne->nodeid, address, quad, 4)) { - HPSB_DEBUG("read of address %Lx failed", address); - return -EAGAIN; + int i; + int ret = 0; + + for (i = 0; i < 3; i++) { + ret = hpsb_read(ne->host, ne->nodeid, address, quad, 4); + if (ret != -EAGAIN) + break; } *quad = be32_to_cpu(*quad); - return 0; + return ret; } #define CONFIG_ROM_VENDOR_ID 0x03 @@ -137,13 +164,14 @@ static void nodemgr_process_unit_directory(struct node_entry *ne, octlet_t a; quadlet_t quad; int length, i; - if (!(ud = kmalloc (sizeof *ud, GFP_KERNEL))) goto unit_directory_error; memset (ud, 0, sizeof *ud); + ud->ne = ne; ud->address = address; + ud->arb_count = 0; if (nodemgr_read_quadlet(ne, address, &quad)) goto unit_directory_error; @@ -151,7 +179,8 @@ static void nodemgr_process_unit_directory(struct node_entry *ne, a = address + 4; for (i = 0; i < length; i++, a += 4) { - int code, value; + int code; + quadlet_t value; if (nodemgr_read_quadlet(ne, a, &quad)) goto unit_directory_error; @@ -183,10 +212,20 @@ static void nodemgr_process_unit_directory(struct node_entry *ne, case CONFIG_ROM_DESCRIPTOR_DIRECTORY: /* TODO: read strings... icons? */ break; + + default: + if (ud->arb_count < 16) { + /* Place them in the arbitrary pairs */ + ud->arb_keys[ud->arb_count] = code; + ud->arb_values[ud->arb_count] = value; + ud->arb_count++; + } } } - list_add_tail (&ud->list, &ne->unit_directories); + list_add_tail(&ud->node_list, &ne->unit_directories); + list_add_tail(&ud->driver_list, &unit_directory_list); + return; unit_directory_error: @@ -194,27 +233,29 @@ unit_directory_error: kfree(ud); } -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG static void dump_directories (struct node_entry *ne) { +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG struct list_head *l; HPSB_DEBUG("vendor_id=0x%06x, capabilities=0x%06x", ne->vendor_id, ne->capabilities); list_for_each (l, &ne->unit_directories) { - struct unit_directory *ud = list_entry (l, struct unit_directory, list); + struct unit_directory *ud = list_entry (l, struct unit_directory, node_list); HPSB_DEBUG("unit directory:"); if (ud->flags & UNIT_DIRECTORY_VENDOR_ID) HPSB_DEBUG(" vendor_id=0x%06x ", ud->vendor_id); if (ud->flags & UNIT_DIRECTORY_MODEL_ID) HPSB_DEBUG(" model_id=0x%06x ", ud->model_id); if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) - HPSB_DEBUG(" specifier_id=0x%06x ", ud->specifier_id); + HPSB_DEBUG(" sw_specifier_id=0x%06x ", ud->specifier_id); if (ud->flags & UNIT_DIRECTORY_VERSION) - HPSB_DEBUG(" version=0x%06x ", ud->version); + HPSB_DEBUG(" sw_version=0x%06x ", ud->version); } -} +#else + return; #endif +} static void nodemgr_process_root_directory(struct node_entry *ne) { @@ -260,86 +301,383 @@ static void nodemgr_process_root_directory(struct node_entry *ne) break; } } -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + dump_directories(ne); +} + +#ifdef CONFIG_HOTPLUG + +static void nodemgr_call_policy(char *verb, struct unit_directory *ud) +{ + char *argv [3], **envp, *buf, *scratch; + int i = 0, value; + + if (!hotplug_path [0]) + return; + if (!current->fs->root) + return; + if (!(envp = (char **) kmalloc(20 * sizeof (char *), GFP_KERNEL))) { + HPSB_DEBUG ("ENOMEM"); + return; + } + if (!(buf = kmalloc(256, GFP_KERNEL))) { + kfree(envp); + HPSB_DEBUG("ENOMEM2"); + return; + } + + /* only one standardized param to hotplug command: type */ + argv[0] = hotplug_path; + argv[1] = "ieee1394"; + argv[2] = 0; + + /* minimal command environment */ + envp[i++] = "HOME=/"; + envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; + +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + /* hint that policy agent should enter no-stdout debug mode */ + envp[i++] = "DEBUG=kernel"; +#endif + /* extensible set of named bus-specific parameters, + * supporting multiple driver selection algorithms. + */ + scratch = buf; + + envp[i++] = scratch; + scratch += sprintf(scratch, "ACTION=%s", verb) + 1; + envp[i++] = scratch; + scratch += sprintf(scratch, "VENDOR_ID=%06x", ud->ne->vendor_id) + 1; + envp[i++] = scratch; + scratch += sprintf(scratch, "GUID=%016Lx", (long long unsigned)ud->ne->guid) + 1; + envp[i++] = scratch; + scratch += sprintf(scratch, "SPECIFIER_ID=%06x", ud->specifier_id) + 1; + envp[i++] = scratch; + scratch += sprintf(scratch, "VERSION=%06x", ud->version) + 1; + envp[i++] = 0; + + /* NOTE: user mode daemons can call the agents too */ +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + HPSB_DEBUG("NodeMgr: %s %s %016Lx", argv[0], verb, (long long unsigned)ud->ne->guid); #endif + value = call_usermodehelper(argv[0], argv, envp); + kfree(buf); + kfree(envp); + if (value != 0) + HPSB_DEBUG("NodeMgr: hotplug policy returned 0x%x", value); } -static void register_node(struct hpsb_host *host, nodeid_t nodeid, u64 guid, - quadlet_t busoptions) +#else + +static inline void +nodemgr_call_policy(char *verb, struct unit_directory *ud) { - struct node_entry *ne; - unsigned long flags, new = 0; +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + HPSB_DEBUG("NodeMgr: nodemgr_call_policy(): hotplug not enabled"); +#else + return; +#endif +} - read_lock_irqsave(&node_lock, flags); - ne = find_entry_by_guid(guid); - read_unlock_irqrestore(&node_lock, flags); +#endif /* CONFIG_HOTPLUG */ - /* New entry */ - if (!ne) { - if ((ne = create_node_entry()) == NULL) - return; +static void nodemgr_claim_unit_directory(struct unit_directory *ud, + struct hpsb_protocol_driver *driver) +{ + ud->driver = driver; + list_del(&ud->driver_list); + list_add_tail(&ud->driver_list, &driver->unit_directories); +} + +static void nodemgr_release_unit_directory(struct unit_directory *ud) +{ + ud->driver = NULL; + list_del(&ud->driver_list); + list_add_tail(&ud->driver_list, &unit_directory_list); +} + +void hpsb_release_unit_directory(struct unit_directory *ud) +{ + unsigned long flags; + + write_lock_irqsave(&unit_directory_lock, flags); + nodemgr_release_unit_directory(ud); + write_unlock_irqrestore(&unit_directory_lock, flags); +} + +static void nodemgr_free_unit_directories(struct node_entry *ne) +{ + struct list_head *lh; + struct unit_directory *ud; + + lh = ne->unit_directories.next; + while (lh != &ne->unit_directories) { + ud = list_entry(lh, struct unit_directory, node_list); + lh = lh->next; + if (ud->driver && ud->driver->disconnect) + ud->driver->disconnect(ud); + nodemgr_release_unit_directory(ud); + nodemgr_call_policy("remove", ud); + list_del(&ud->driver_list); + kfree(ud); + } +} + +static struct ieee1394_device_id * +nodemgr_match_driver(struct hpsb_protocol_driver *driver, + struct unit_directory *ud) +{ + struct ieee1394_device_id *id; + + for (id = driver->id_table; id->match_flags != 0; id++) { + if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) && + id->vendor_id != ud->vendor_id) + continue; + + if ((id->match_flags & IEEE1394_MATCH_MODEL_ID) && + id->model_id != ud->model_id) + continue; + + if ((id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) && + id->specifier_id != ud->specifier_id) + continue; + + if ((id->match_flags & IEEE1394_MATCH_VERSION) && + id->version != ud->version) + continue; + + return id; + } + + return NULL; +} + +static struct hpsb_protocol_driver * +nodemgr_find_driver(struct unit_directory *ud) +{ + struct list_head *l; + struct hpsb_protocol_driver *match, *driver; + struct ieee1394_device_id *device_id; + + match = NULL; + list_for_each(l, &driver_list) { + driver = list_entry(l, struct hpsb_protocol_driver, list); + device_id = nodemgr_match_driver(driver, ud); + + if (device_id != NULL) { + match = driver; + break; + } + } + + return match; +} + +static void nodemgr_bind_drivers (struct node_entry *ne) +{ + struct list_head *lh; + struct hpsb_protocol_driver *driver; + struct unit_directory *ud; + + list_for_each(lh, &ne->unit_directories) { + ud = list_entry(lh, struct unit_directory, node_list); + driver = nodemgr_find_driver(ud); + if (driver != NULL && driver->probe(ud) == 0) + nodemgr_claim_unit_directory(ud, driver); + nodemgr_call_policy("add", ud); + } +} - HPSB_DEBUG("%s added: node " NODE_BUS_FMT - ", GUID %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", - (host->node_id == nodeid) ? "Local host" : "Device", - NODE_BUS_ARGS(nodeid), ((u8 *)&guid)[0], - ((u8 *)&guid)[1], ((u8 *)&guid)[2], ((u8 *)&guid)[3], - ((u8 *)&guid)[4], ((u8 *)&guid)[5], ((u8 *)&guid)[6], - ((u8 *)&guid)[7]); +int hpsb_register_protocol(struct hpsb_protocol_driver *driver) +{ + struct unit_directory *ud; + struct list_head *lh; + unsigned long flags; - ne->guid = guid; - new = 1; + write_lock_irqsave(&driver_lock, flags); + list_add_tail(&driver->list, &driver_list); + write_unlock_irqrestore(&driver_lock, flags); + + write_lock_irqsave(&unit_directory_lock, flags); + INIT_LIST_HEAD(&driver->unit_directories); + lh = unit_directory_list.next; + while (lh != &unit_directory_list) { + ud = list_entry(lh, struct unit_directory, driver_list); + lh = lh->next; + if (nodemgr_match_driver(driver, ud) && driver->probe(ud) == 0) + nodemgr_claim_unit_directory(ud, driver); } + write_unlock_irqrestore(&unit_directory_lock, flags); + + /* + * Right now registration always succeeds, but maybe we should + * detect clashes in protocols handled by other drivers. + */ + + return 0; +} + +void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver) +{ + struct list_head *lh; + struct unit_directory *ud; + unsigned long flags; + + write_lock_irqsave(&driver_lock, flags); + list_del(&driver->list); + write_unlock_irqrestore(&driver_lock, flags); + + write_lock_irqsave(&unit_directory_lock, flags); + lh = driver->unit_directories.next; + while (lh != &driver->unit_directories) { + ud = list_entry(lh, struct unit_directory, driver_list); + lh = lh->next; + if (ud->driver && ud->driver->disconnect) + ud->driver->disconnect(ud); + nodemgr_release_unit_directory(ud); + } + write_unlock_irqrestore(&unit_directory_lock, flags); +} + +static void nodemgr_process_config_rom(struct node_entry *ne, + quadlet_t busoptions) +{ + unsigned long flags; + + ne->busopt.irmc = (busoptions >> 31) & 1; + ne->busopt.cmc = (busoptions >> 30) & 1; + ne->busopt.isc = (busoptions >> 29) & 1; + ne->busopt.bmc = (busoptions >> 28) & 1; + ne->busopt.pmc = (busoptions >> 27) & 1; + ne->busopt.cyc_clk_acc = (busoptions >> 16) & 0xff; + ne->busopt.max_rec = 1 << (((busoptions >> 12) & 0xf) + 1); + ne->busopt.generation = (busoptions >> 4) & 0xf; + ne->busopt.lnkspd = busoptions & 0x7; + +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + HPSB_DEBUG("NodeMgr: raw=0x%08x irmc=%d cmc=%d isc=%d bmc=%d pmc=%d " + "cyc_clk_acc=%d max_rec=%d gen=%d lspd=%d", + busoptions, ne->busopt.irmc, ne->busopt.cmc, + ne->busopt.isc, ne->busopt.bmc, ne->busopt.pmc, + ne->busopt.cyc_clk_acc, ne->busopt.max_rec, + ne->busopt.generation, ne->busopt.lnkspd); +#endif - if (!new && ne->nodeid != nodeid) + /* + * When the config rom changes we disconnect all drivers and + * free the cached unit directories and reread the whole + * thing. If this was a new device, the call to + * nodemgr_disconnect_drivers is a no-op and all is well. + */ + write_lock_irqsave(&unit_directory_lock, flags); + nodemgr_free_unit_directories(ne); + nodemgr_process_root_directory(ne); + nodemgr_bind_drivers(ne); + write_unlock_irqrestore(&unit_directory_lock, flags); +} + +/* + * This function updates nodes that were present on the bus before the + * reset and still are after the reset. The nodeid and the config rom + * may have changed, and the drivers managing this device must be + * informed that this device just went through a bus reset, to allow + * the to take whatever actions required. + */ +static void nodemgr_update_node(struct node_entry *ne, quadlet_t busoptions, + struct hpsb_host *host, nodeid_t nodeid) +{ + struct list_head *lh; + + if (ne->nodeid != nodeid) HPSB_DEBUG("Node " NODE_BUS_FMT " changed to " NODE_BUS_FMT, NODE_BUS_ARGS(ne->nodeid), NODE_BUS_ARGS(nodeid)); ne->host = host; - ne->nodeid = nodeid; + ne->nodeid = nodeid; - /* Now set the bus options. Only do all this crap if this is a new - * node, or if the generation number has changed. */ - if (new || ne->busopt.generation != ((busoptions >> 6) & 0x3)) { - ne->busopt.irmc = (busoptions >> 31) & 1; - ne->busopt.cmc = (busoptions >> 30) & 1; - ne->busopt.isc = (busoptions >> 29) & 1; - ne->busopt.bmc = (busoptions >> 28) & 1; - ne->busopt.pmc = (busoptions >> 27) & 1; - ne->busopt.cyc_clk_acc = (busoptions >> 16) & 0xff; - ne->busopt.max_rec = 1 << (((busoptions >> 12) & 0xf) + 1); - ne->busopt.generation = (busoptions >> 6) & 0x3; - ne->busopt.lnkspd = busoptions & 0x7; - - /* Now, process the rest of the tree */ - nodemgr_process_root_directory(ne); - } + if (ne->busopt.generation != ((busoptions >> 4) & 0xf)) + nodemgr_process_config_rom (ne, busoptions); /* Since that's done, we can declare this record current */ - atomic_set(&ne->generation, get_hpsb_generation(host)); + atomic_set(&ne->generation, get_hpsb_generation(ne->host)); + + list_for_each (lh, &ne->unit_directories) { + struct unit_directory *ud; + + ud = list_entry (lh, struct unit_directory, node_list); + if (ud->driver != NULL && ud->driver->update != NULL) + ud->driver->update(ud); + } +} + +static int read_businfo_block(struct hpsb_host *host, nodeid_t nodeid, + quadlet_t *buffer, int buffer_length) +{ + octlet_t base = CSR_REGISTER_BASE + CSR_CONFIG_ROM; + int retries = 3; + int header_count; + unsigned header_size; + quadlet_t quad; + +retry_configrom: + + if (!retries--) { + HPSB_ERR("Giving up on node " NODE_BUS_FMT + " for ConfigROM probe, too many errors", + NODE_BUS_ARGS(nodeid)); + return -1; + } + + header_count = 0; + header_size = 0; #ifdef CONFIG_IEEE1394_VERBOSEDEBUG - HPSB_DEBUG("raw=0x%08x irmc=%d cmc=%d isc=%d bmc=%d pmc=%d cyc_clk_acc=%d " - "max_rec=%d gen=%d lspd=%d", busoptions, - ne->busopt.irmc, ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc, - ne->busopt.pmc, ne->busopt.cyc_clk_acc, ne->busopt.max_rec, - ne->busopt.generation, ne->busopt.lnkspd); + HPSB_INFO("Initiating ConfigROM request for node " NODE_BUS_FMT, + NODE_BUS_ARGS(nodeid)); #endif - return; + /* Now, P1212 says that devices should support 64byte block + * reads, aligned on 64byte boundaries. That doesn't seem + * to work though, and we are forced to doing quadlet + * sized reads. */ + + if (hpsb_read(host, nodeid, base, &quad, 4)) { + HPSB_ERR("ConfigROM quadlet transaction error for node " NODE_BUS_FMT, + NODE_BUS_ARGS(nodeid)); + goto retry_configrom; + } + buffer[header_count++] = be32_to_cpu(quad); + + header_size = buffer[0] >> 24; + + if (header_size < 4) { + HPSB_INFO("Node " NODE_BUS_FMT " has non-standard ROM format (%d quads), " + "cannot parse", NODE_BUS_ARGS(nodeid), header_size); + return -1; + } + + while (header_count <= header_size && header_count < buffer_length) { + if (hpsb_read(host, nodeid, base + (header_count<<2), &quad, 4)) { + HPSB_ERR("ConfigROM quadlet transaction error for " NODE_BUS_FMT, + NODE_BUS_ARGS(nodeid)); + goto retry_configrom; + } + buffer[header_count++] = be32_to_cpu(quad); + } + + return 0; } static void nodemgr_remove_node(struct node_entry *ne) { - HPSB_DEBUG("Device removed: node " NODE_BUS_FMT ", GUID " - "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", - NODE_BUS_ARGS(ne->nodeid), - ((u8 *)&ne->guid)[0], ((u8 *)&ne->guid)[1], - ((u8 *)&ne->guid)[2], ((u8 *)&ne->guid)[3], - ((u8 *)&ne->guid)[4], ((u8 *)&ne->guid)[5], - ((u8 *)&ne->guid)[6], ((u8 *)&ne->guid)[7]); + unsigned long flags; + + HPSB_DEBUG("Device removed: node " NODE_BUS_FMT ", GUID %016Lx", + NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid); + write_lock_irqsave(&unit_directory_lock, flags); + nodemgr_free_unit_directories(ne); + write_unlock_irqrestore(&unit_directory_lock, flags); list_del(&ne->list); kfree(ne); @@ -352,82 +690,26 @@ static void nodemgr_node_probe(void *data) { struct hpsb_host *host = (struct hpsb_host *)data; struct selfid *sid = (struct selfid *)host->topology_map; - struct list_head *lh,*spare; + struct list_head *lh, *next; struct node_entry *ne; int nodecount = host->node_count; nodeid_t nodeid = LOCAL_BUS; - quadlet_t buffer[5], quad; - octlet_t base = CSR_REGISTER_BASE + CSR_CONFIG_ROM; + quadlet_t buffer[5]; + octlet_t guid; unsigned long flags; /* We need to detect when the ConfigROM's generation has changed, * so we only update the node's info when it needs to be. */ for (; nodecount; nodecount--, nodeid++, sid++) { - int retries = 3; - int header_count; - unsigned header_size; - octlet_t guid; - /* Skip extended, and non-active node's */ while (sid->extended) sid++; if (!sid->link_active) continue; - /* Just use our local ROM */ - if (nodeid == host->node_id) { - int i; - for (i = 0; i < 5; i++) - buffer[i] = be32_to_cpu(host->csr.rom[i]); - goto set_options; - } - -retry_configrom: - - if (!retries--) { - HPSB_ERR("Giving up on node " NODE_BUS_FMT - " for ConfigROM probe, too many errors", - NODE_BUS_ARGS(nodeid)); + if (read_businfo_block (host, nodeid, buffer, sizeof(buffer) >> 2)) continue; - } - header_count = 0; - header_size = 0; - -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG - HPSB_INFO("Initiating ConfigROM request for node " NODE_BUS_FMT, - NODE_BUS_ARGS(nodeid)); -#endif - - /* Now, P1212 says that devices should support 64byte block - * reads, aligned on 64byte boundaries. That doesn't seem - * to work though, and we are forced to doing quadlet - * sized reads. */ - - if (hpsb_read(host, nodeid, base, &quad, 4)) { - HPSB_ERR("ConfigROM quadlet transaction error for node " NODE_BUS_FMT, - NODE_BUS_ARGS(nodeid)); - goto retry_configrom; - } - buffer[header_count++] = be32_to_cpu(quad); - - header_size = buffer[0] >> 24; - - if (header_size < 4) { - HPSB_INFO("Node " NODE_BUS_FMT " has non-standard ROM format (%d quads), " - "cannot parse", NODE_BUS_ARGS(nodeid), header_size); - continue; - } - - while (header_count <= header_size && (header_count<<2) < sizeof(buffer)) { - if (hpsb_read(host, nodeid, base + (header_count<<2), &quad, 4)) { - HPSB_ERR("ConfigROM quadlet transaction error for " NODE_BUS_FMT, - NODE_BUS_ARGS(nodeid)); - goto retry_configrom; - } - buffer[header_count++] = be32_to_cpu(quad); - } -set_options: if (buffer[1] != IEEE1394_BUSID_MAGIC) { /* This isn't a 1394 device */ HPSB_ERR("Node " NODE_BUS_FMT " isn't an IEEE 1394 device", @@ -435,15 +717,21 @@ set_options: continue; } - guid = be64_to_cpu(((u64)buffer[3] << 32) | buffer[4]); - register_node(host, nodeid, guid, buffer[2]); + guid = ((u64)buffer[3] << 32) | buffer[4]; + ne = hpsb_guid_get_entry(guid); + + if (!ne) + nodemgr_create_node(guid, buffer[2], host, nodeid); + else + nodemgr_update_node(ne, buffer[2], host, nodeid); } /* Now check to see if we have any nodes that aren't referenced * any longer. */ write_lock_irqsave(&node_lock, flags); - list_for_each_safe(lh, spare, &node_list) { + for (lh = node_list.next; lh != &node_list; lh = next) { ne = list_entry(lh, struct node_entry, list); + next = lh->next; /* Only checking this host */ if (ne->host != host) @@ -453,7 +741,7 @@ set_options: * node was removed, or it failed the above probe. Either * way, we remove references to it, since they are * invalid. */ - if (atomic_read(&ne->generation) != get_hpsb_generation(host)) + if (!hpsb_node_entry_valid(ne)) nodemgr_remove_node(ne); } write_unlock_irqrestore(&node_lock, flags); @@ -511,7 +799,7 @@ static void nodemgr_add_host(struct hpsb_host *host) unsigned long flags; if (!hi) { - HPSB_ERR ("Out of memory in Node Manager"); + HPSB_ERR ("NodeMgr: out of memory in add host"); return; } @@ -544,7 +832,7 @@ static void nodemgr_host_reset(struct hpsb_host *host) } if (hi == NULL) { - HPSB_ERR ("Could not process reset of non-existent host in Node Manager"); + HPSB_ERR ("NodeMgr: could not process reset of non-existent host"); goto done_reset_host; } @@ -558,8 +846,7 @@ done_reset_host: static void nodemgr_remove_host(struct hpsb_host *host) { - struct list_head *lh; - struct host_info *hi = NULL; + struct list_head *lh, *next; struct node_entry *ne; unsigned long flags; @@ -568,8 +855,10 @@ static void nodemgr_remove_host(struct hpsb_host *host) /* First remove all node entries for this host */ write_lock_irqsave(&node_lock, flags); - list_for_each(lh, &node_list) { + + for (lh = node_list.next; lh != &node_list; lh = next) { ne = list_entry(lh, struct node_entry, list); + next = lh->next; /* Only checking this host */ if (ne->host != host) @@ -581,22 +870,17 @@ static void nodemgr_remove_host(struct hpsb_host *host) spin_lock_irqsave (&host_info_lock, flags); list_for_each(lh, &host_info_list) { - struct host_info *myhi = list_entry(lh, struct host_info, list); - if (myhi->host == host) { - hi = myhi; + struct host_info *hi = list_entry(lh, struct host_info, list); + if (hi->host == host) { + list_del(&hi->list); + kfree (hi); break; } } - if (hi == NULL) { - HPSB_ERR ("Could not remove non-existent host in Node Manager"); - goto done_remove_host; - } - - list_del(&hi->list); - kfree (hi); + if (lh == host_info_list.next) + HPSB_ERR ("NodeMgr: could not remove non-existent host"); -done_remove_host: spin_unlock_irqrestore (&host_info_lock, flags); return; @@ -614,7 +898,7 @@ void init_ieee1394_nodemgr(void) { hl = hpsb_register_highlevel("Node manager", &nodemgr_ops); if (!hl) { - HPSB_ERR("Out of memory during ieee1394 initialization"); + HPSB_ERR("NodeMgr: out of memory during ieee1394 initialization"); } } diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h index 7d91a1a7ccbe..46f574e64155 100644 --- a/drivers/ieee1394/nodemgr.h +++ b/drivers/ieee1394/nodemgr.h @@ -38,13 +38,23 @@ struct bus_options { u16 max_rec; /* Maximum packet size node can receive */ }; -#define UNIT_DIRECTORY_VENDOR_ID 0x01 -#define UNIT_DIRECTORY_MODEL_ID 0x02 -#define UNIT_DIRECTORY_SPECIFIER_ID 0x04 -#define UNIT_DIRECTORY_VERSION 0x08 +#define UNIT_DIRECTORY_VENDOR_ID 0x01 +#define UNIT_DIRECTORY_MODEL_ID 0x02 +#define UNIT_DIRECTORY_SPECIFIER_ID 0x04 +#define UNIT_DIRECTORY_VERSION 0x08 +/* + * A unit directory corresponds to a protocol supported by the + * node. If a node supports eg. IP/1394 and AV/C, its config rom has a + * unit directory for each of these protocols. + * + * Unit directories appear on two types of lists: for each node we + * maintain a list of the unit directories found in its config rom and + * for each driver we maintain a list of the unit directories + * (ie. devices) the driver manages. + */ struct unit_directory { - struct list_head list; + struct node_entry *ne; /* The node which this directory belongs to */ octlet_t address; /* Address of the unit directory on the node */ u8 flags; /* Indicates which entries were read */ quadlet_t vendor_id; @@ -53,6 +63,20 @@ struct unit_directory { char *model_name; quadlet_t specifier_id; quadlet_t version; + + /* Groupings for arbitrary key/value pairs */ + int arb_count; /* Number of arbitrary key/values */ + char arb_keys[16]; /* Up to 16 keys */ + quadlet_t arb_values[16]; /* Same for values */ + + struct hpsb_protocol_driver *driver; + void *driver_data; + + /* For linking the nodes managed by the driver, or unmanaged nodes */ + struct list_head driver_list; + + /* For linking directories belonging to a node */ + struct list_head node_list; }; struct node_entry { @@ -69,6 +93,11 @@ struct node_entry { struct list_head unit_directories; }; +static inline int hpsb_node_entry_valid(struct node_entry *ne) +{ + return atomic_read(&ne->generation) == get_hpsb_generation(ne->host); +} + /* * Returns a node entry (which has its reference count incremented) or NULL if * the GUID in question is not known. Getting a valid entry does not mean that diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 8c68f145bdcb..88c9e4bd91ce 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -105,6 +105,17 @@ #include <linux/vmalloc.h> #include <linux/init.h> +#ifdef CONFIG_ALL_PPC +#include <asm/feature.h> +#include <asm/prom.h> +#include <asm/pci-bridge.h> +#endif + +/* Revert to old bus reset algorithm that works on my Pismo until + * the new one is fixed + */ +#undef BUSRESET_WORKAROUND + #include "ieee1394.h" #include "ieee1394_types.h" #include "hosts.h" @@ -112,7 +123,6 @@ #include "highlevel.h" #include "ohci1394.h" - #ifdef CONFIG_IEEE1394_VERBOSEDEBUG #define OHCI1394_DEBUG #endif @@ -123,17 +133,17 @@ #ifdef OHCI1394_DEBUG #define DBGMSG(card, fmt, args...) \ -printk(KERN_INFO "ohci1394_%d: " fmt "\n" , card , ## args) +printk(KERN_INFO "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args) #else #define DBGMSG(card, fmt, args...) #endif #ifdef CONFIG_IEEE1394_OHCI_DMA_DEBUG #define OHCI_DMA_ALLOC(fmt, args...) \ - HPSB_ERR("ohci1394("__FUNCTION__")alloc(%d): "fmt, \ + HPSB_ERR("%s("__FUNCTION__")alloc(%d): "fmt, OHCI1394_DRIVER_NAME, \ ++global_outstanding_dmas, ## args) #define OHCI_DMA_FREE(fmt, args...) \ - HPSB_ERR("ohci1394("__FUNCTION__")free(%d): "fmt, \ + HPSB_ERR("%s("__FUNCTION__")free(%d): "fmt, OHCI1394_DRIVER_NAME, \ --global_outstanding_dmas, ## args) u32 global_outstanding_dmas = 0; #else @@ -143,18 +153,11 @@ u32 global_outstanding_dmas = 0; /* print general (card independent) information */ #define PRINT_G(level, fmt, args...) \ -printk(level "ohci1394: " fmt "\n" , ## args) +printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args) /* print card specific information */ #define PRINT(level, card, fmt, args...) \ -printk(level "ohci1394_%d: " fmt "\n" , card , ## args) - -#define FAIL(fmt, args...) \ -do { \ - PRINT_G(KERN_ERR, fmt , ## args); \ - remove_card(ohci); \ - return 1; \ -} while(0) +printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args) #define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10) @@ -179,21 +182,48 @@ MODULE_PARM(attempt_root,"i"); MODULE_PARM_DESC(attempt_root, "Attempt to make the host root."); static int attempt_root = 0; -#ifdef __LITTLE_ENDIAN -/* Don't waste cycles on same sex byte swaps */ -#define packet_swab(w,x,y,z) -#define block_swab32(x,y) -#else -static void packet_swab(quadlet_t *data, char tcode, int len, int payload_swap); -static __inline__ void block_swab32(quadlet_t *data, size_t size); -#endif - static unsigned int card_id_counter = 0; static void dma_trm_tasklet(unsigned long data); static void remove_card(struct ti_ohci *ohci); static void dma_trm_reset(struct dma_trm_ctx *d); +#ifndef __LITTLE_ENDIAN +/* Swap a series of quads inplace. */ +static __inline__ void block_swab32(quadlet_t *data, size_t size) { + while (size--) + data[size] = swab32(data[size]); +} + +static unsigned hdr_sizes[] = +{ + 3, /* TCODE_WRITEQ */ + 4, /* TCODE_WRITEB */ + 3, /* TCODE_WRITE_RESPONSE */ + 0, /* ??? */ + 3, /* TCODE_READQ */ + 4, /* TCODE_READB */ + 3, /* TCODE_READQ_RESPONSE */ + 4, /* TCODE_READB_RESPONSE */ + 1, /* TCODE_CYCLE_START (???) */ + 4, /* TCODE_LOCK_REQUEST */ + 2, /* TCODE_ISO_DATA */ + 4, /* TCODE_LOCK_RESPONSE */ +}; + +/* Swap headers */ +static inline void packet_swab(quadlet_t *data, int tcode, int len) +{ + if (tcode > TCODE_LOCK_RESPONSE || hdr_sizes[tcode] == 0) + return; + block_swab32(data, hdr_sizes[tcode]); +} +#else +/* Don't waste cycles on same sex byte swaps */ +#define packet_swab(w,x,y) +#define block_swab32(x,y) +#endif /* !LITTLE_ENDIAN */ + /*********************************** * IEEE-1394 functionality section * ***********************************/ @@ -230,7 +260,7 @@ static void set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data) { int i; unsigned long flags; - u32 r; + u32 r = 0; spin_lock_irqsave (&ohci->phy_reg_lock, flags); @@ -376,7 +406,7 @@ static int run_context(struct ti_ohci *ohci, int reg, char *msg) } /* Generate the dma receive prgs and start the context */ -static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d) +static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d, int generate_irq) { struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); int i; @@ -384,12 +414,17 @@ static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d) ohci1394_stop_context(ohci, d->ctrlClear, NULL); for (i=0; i<d->num_desc; i++) { + u32 c; - d->prg_cpu[i]->control = - cpu_to_le32((0x280C << 16) | d->buf_size); + c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | + DMA_CTL_BRANCH; + if (generate_irq) + c |= DMA_CTL_IRQ; + + d->prg_cpu[i]->control = cpu_to_le32(c | d->buf_size); /* End of descriptor list? */ - if ((i+1) < d->num_desc) { + if (i + 1 < d->num_desc) { d->prg_cpu[i]->branchAddress = cpu_to_le32((d->prg_bus[i+1] & 0xfffffff0) | 0x1); } else { @@ -565,15 +600,15 @@ static int ohci_initialize(struct hpsb_host *host) reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff); /* Initialize AR dma */ - initialize_dma_rcv_ctx(ohci->ar_req_context); - initialize_dma_rcv_ctx(ohci->ar_resp_context); + initialize_dma_rcv_ctx(ohci->ar_req_context, 0); + initialize_dma_rcv_ctx(ohci->ar_resp_context, 0); /* Initialize AT dma */ initialize_dma_trm_ctx(ohci->at_req_context); initialize_dma_trm_ctx(ohci->at_resp_context); /* Initialize IR dma */ - initialize_dma_rcv_ctx(ohci->ir_context); + initialize_dma_rcv_ctx(ohci->ir_context, 1); /* Initialize IT dma */ initialize_dma_trm_ctx(ohci->it_context); @@ -604,7 +639,6 @@ static int ohci_initialize(struct hpsb_host *host) /* Enable interrupts */ reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_masterIntEnable | - OHCI1394_phyRegRcvd | OHCI1394_busReset | OHCI1394_selfIDComplete | OHCI1394_RSPkt | @@ -674,9 +708,9 @@ static void insert_packet(struct ti_ohci *ohci, } else d->prg_cpu[idx]->begin.status = 0; - if ( (packet->type == async) || (packet->type == raw) ) { + if ( (packet->type == hpsb_async) || (packet->type == hpsb_raw) ) { - if (packet->type == raw) { + if (packet->type == hpsb_raw) { d->prg_cpu[idx]->data[0] = cpu_to_le32(OHCI1394_TCODE_PHY<<4); d->prg_cpu[idx]->data[1] = packet->header[0]; d->prg_cpu[idx]->data[2] = packet->header[1]; @@ -689,14 +723,18 @@ static void insert_packet(struct ti_ohci *ohci, d->prg_cpu[idx]->data[2] = packet->header[2]; d->prg_cpu[idx]->data[3] = packet->header[3]; packet_swab(d->prg_cpu[idx]->data, packet->tcode, - packet->header_size>>2, ohci->payload_swap); + packet->header_size>>2); } if (packet->data_size) { /* block transmit */ d->prg_cpu[idx]->begin.control = - cpu_to_le32(OUTPUT_MORE_IMMEDIATE | 0x10); + cpu_to_le32(DMA_CTL_OUTPUT_MORE | + DMA_CTL_IMMEDIATE | 0x10); d->prg_cpu[idx]->end.control = - cpu_to_le32(OUTPUT_LAST | packet->data_size); + cpu_to_le32(DMA_CTL_OUTPUT_LAST | + DMA_CTL_IRQ | + DMA_CTL_BRANCH | + packet->data_size); /* * Check that the packet data buffer * does not cross a page boundary. @@ -716,9 +754,6 @@ static void insert_packet(struct ti_ohci *ohci, PCI_DMA_TODEVICE)); OHCI_DMA_ALLOC("single, block transmit packet"); - if (ohci->payload_swap) - block_swab32(packet->data, packet->data_size >> 2); - d->prg_cpu[idx]->end.branchAddress = 0; d->prg_cpu[idx]->end.status = 0; if (d->branchAddrPtr) @@ -727,14 +762,20 @@ static void insert_packet(struct ti_ohci *ohci, d->branchAddrPtr = &(d->prg_cpu[idx]->end.branchAddress); } else { /* quadlet transmit */ - if (packet->type == raw) - d->prg_cpu[idx]->begin.control = cpu_to_le32( - OUTPUT_LAST_IMMEDIATE | - (packet->header_size+4)); + if (packet->type == hpsb_raw) + d->prg_cpu[idx]->begin.control = + cpu_to_le32(DMA_CTL_OUTPUT_LAST | + DMA_CTL_IMMEDIATE | + DMA_CTL_IRQ | + DMA_CTL_BRANCH | + (packet->header_size + 4)); else - d->prg_cpu[idx]->begin.control = cpu_to_le32( - OUTPUT_LAST_IMMEDIATE | - packet->header_size); + d->prg_cpu[idx]->begin.control = + cpu_to_le32(DMA_CTL_OUTPUT_LAST | + DMA_CTL_IMMEDIATE | + DMA_CTL_IRQ | + DMA_CTL_BRANCH | + packet->header_size); if (d->branchAddrPtr) *(d->branchAddrPtr) = @@ -747,20 +788,22 @@ static void insert_packet(struct ti_ohci *ohci, d->prg_cpu[idx]->data[0] = packet->speed_code<<16 | (packet->header[0] & 0xFFFF); d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000; - packet_swab(d->prg_cpu[idx]->data, packet->tcode, packet->header_size>>2, - ohci->payload_swap); + packet_swab(d->prg_cpu[idx]->data, packet->tcode, packet->header_size>>2); - d->prg_cpu[idx]->begin.control = cpu_to_le32(OUTPUT_MORE_IMMEDIATE | 0x8); - d->prg_cpu[idx]->end.control = cpu_to_le32( - OUTPUT_LAST | 0x08000000 | packet->data_size); + d->prg_cpu[idx]->begin.control = + cpu_to_le32(DMA_CTL_OUTPUT_MORE | + DMA_CTL_IMMEDIATE | 0x8); + d->prg_cpu[idx]->end.control = + cpu_to_le32(DMA_CTL_OUTPUT_LAST | + DMA_CTL_UPDATE | + DMA_CTL_IRQ | + DMA_CTL_BRANCH | + packet->data_size); d->prg_cpu[idx]->end.address = cpu_to_le32( pci_map_single(ohci->dev, packet->data, packet->data_size, PCI_DMA_TODEVICE)); OHCI_DMA_ALLOC("single, iso transmit packet"); - if (ohci->payload_swap) - block_swab32(packet->data, packet->data_size>>2); - d->prg_cpu[idx]->end.branchAddress = 0; d->prg_cpu[idx]->end.status = 0; DBGMSG(ohci->id, "Iso xmit context info: header[%08x %08x]\n" @@ -947,7 +990,7 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) if (arg<0 || arg>63) { PRINT(KERN_ERR, ohci->id, __FUNCTION__ - "IS0 listne channel %d is out of range", + "IS0 listen channel %d is out of range", arg); return -EFAULT; } @@ -1083,13 +1126,16 @@ static void ohci_irq_handler(int irq, void *dev_id, int phyid = -1, isroot = 0; unsigned long flags; - /* Read the interrupt event register. We don't clear the bus reset - * here. We wait till we get a selfid complete interrupt and clear - * it then, and _only_ then. */ + /* Read and clear the interrupt event register. Don't clear + * the busReset event, though, this is done when we get the + * selfIDComplete interrupt. */ spin_lock_irqsave(&ohci->event_lock, flags); event = reg_read(ohci, OHCI1394_IntEventClear); - reg_write(ohci, OHCI1394_IntEventClear, - event & ~(OHCI1394_selfIDComplete | OHCI1394_busReset)); +#ifdef BUSRESET_WORKAROUND + reg_write(ohci, OHCI1394_IntEventClear, event); +#else + reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset); +#endif spin_unlock_irqrestore(&ohci->event_lock, flags); if (!event) return; @@ -1103,24 +1149,26 @@ static void ohci_irq_handler(int irq, void *dev_id, return; } - /* Someone wants a bus reset. Better watch what you wish for... */ if (event & OHCI1394_busReset) { + /* The busReset event bit can't be cleared during the + * selfID phase, so we disable busReset interrupts, to + * avoid burying the cpu in interrupt requests. */ + spin_lock_irqsave(&ohci->event_lock, flags); +#ifdef BUSRESET_WORKAROUND + reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); +#else + reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset); +#endif + spin_unlock_irqrestore(&ohci->event_lock, flags); if (!host->in_bus_reset) { DBGMSG(ohci->id, "irq_handler: Bus reset requested%s", ((host->attempt_root || attempt_root) ? " and attempting to become root" : "")); - - /* Wait for the AT fifo to be flushed */ - dma_trm_reset(ohci->at_req_context); - dma_trm_reset(ohci->at_resp_context); /* Subsystem call */ hpsb_bus_reset(ohci->host); - - ohci->NumBusResets++; } - /* Mask out everything except selfid */ - event &= OHCI1394_selfIDComplete; + event &= ~OHCI1394_busReset; } /* XXX: We need a way to also queue the OHCI1394_reqTxComplete, @@ -1234,11 +1282,12 @@ static void ohci_irq_handler(int irq, void *dev_id, handle_selfid(ohci, host, phyid, isroot); - } else + } else { PRINT(KERN_ERR, ohci->id, "SelfID interrupt received, but " "NodeID is not valid: %08X", node_id); + } /* Accept Physical requests from all nodes. */ reg_write(ohci,OHCI1394_AsReqFilterHiSet, @@ -1258,21 +1307,15 @@ static void ohci_irq_handler(int irq, void *dev_id, PRINT(KERN_ERR, ohci->id, "SelfID received outside of bus reset sequence"); - /* Clear everything, it's a new day */ + /* Finally, we clear the busReset event and reenable + * the busReset interrupt. */ +#ifndef BUSRESET_WORKAROUND spin_lock_irqsave(&ohci->event_lock, flags); - reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff); + reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); + reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); spin_unlock_irqrestore(&ohci->event_lock, flags); - - event &= ~OHCI1394_selfIDComplete; - } - if (event & OHCI1394_phyRegRcvd) { - if (host->in_bus_reset) { - DBGMSG (ohci->id, "PhyControl: %08X", - reg_read(ohci, OHCI1394_PhyControl)); - } else - PRINT(KERN_ERR, ohci->id, - "Physical register received outside of bus reset sequence"); - event &= ~OHCI1394_phyRegRcvd; +#endif + event &= ~OHCI1394_selfIDComplete; } /* Make sure we handle everything, just in case we accidentally @@ -1365,14 +1408,14 @@ static void dma_rcv_tasklet (unsigned long data) dma_cache_wback_inv(buf_ptr, bytes_left); while (bytes_left > 0) { - tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->payload_swap) >> 4) & 0xf; + tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming) >> 4) & 0xf; /* packet_length() will return < 4 for an error */ - length = packet_length(d, idx, buf_ptr, offset, tcode, ohci->payload_swap); + length = packet_length(d, idx, buf_ptr, offset, tcode, ohci->no_swap_incoming); if (length < 4) { /* something is wrong */ sprintf(msg,"Unexpected tcode 0x%x(0x%08x) in AR ctx=%d, length=%d", - tcode, cond_le32_to_cpu(buf_ptr[0], ohci->payload_swap), + tcode, cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming), d->ctx, length); ohci1394_stop_context(ohci, d->ctrlClear, msg); spin_unlock_irqrestore(&d->lock, flags); @@ -1448,19 +1491,18 @@ static void dma_rcv_tasklet (unsigned long data) /* We get one phy packet to the async descriptor for each * bus reset. We always ignore it. */ if (tcode != OHCI1394_TCODE_PHY) { - if (!ohci->payload_swap) - packet_swab(d->spb, tcode, (length - 4) >> 2, 0); - + if (!ohci->no_swap_incoming) + packet_swab(d->spb, tcode, (length - 4) >> 2); DBGMSG(ohci->id, "Packet received from node" " %d ack=0x%02X spd=%d tcode=0x%X" " length=%d ctx=%d tlabel=%d", (d->spb[1]>>16)&0x3f, - (cond_le32_to_cpu(d->spb[length/4-1], ohci->payload_swap)>>16)&0x1f, - (cond_le32_to_cpu(d->spb[length/4-1], ohci->payload_swap)>>21)&0x3, + (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f, + (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>21)&0x3, tcode, length, d->ctx, - (cond_le32_to_cpu(d->spb[length/4-1], ohci->payload_swap)>>10)&0x3f); + (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>10)&0x3f); - ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->payload_swap)>>16)&0x1f) + ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f) == 0x11) ? 1 : 0; hpsb_packet_received(ohci->host, d->spb, @@ -1510,7 +1552,7 @@ static void dma_trm_tasklet (unsigned long data) while (d->fifo_first) { packet = d->fifo_first; datasize = d->fifo_first->data_size; - if (datasize && packet->type != raw) + if (datasize && packet->type != hpsb_raw) ack = le32_to_cpu( d->prg_cpu[d->sent_ind]->end.status) >> 16; else @@ -2032,6 +2074,14 @@ static struct hpsb_host_template ohci_template = { hw_csr_reg: ohci_hw_csr_reg, }; + +#define FAIL(fmt, args...) \ +do { \ + PRINT_G(KERN_ERR, fmt , ## args); \ + remove_card(ohci); \ + return 1; \ +} while(0) + static int __devinit ohci1394_add_one(struct pci_dev *dev, const struct pci_device_id *ent) { struct ti_ohci *ohci; /* shortcut to currently handled device */ @@ -2075,10 +2125,10 @@ static int __devinit ohci1394_add_one(struct pci_dev *dev, const struct pci_devi * noByteSwapData registers to see if they were not cleared to * zero. Should this work? Obviously it's not defined what these * registers will read when they aren't supported. Bleh! */ - if (dev->vendor == PCI_VENDOR_ID_APPLE) { - ohci->payload_swap = 1; - if (dev->device != PCI_DEVICE_ID_APPLE_UNI_N_FW) - ohci->selfid_swap = 1; + if (dev->vendor == PCI_VENDOR_ID_APPLE && + dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) { + ohci->no_swap_incoming = 1; + ohci->selfid_swap = 0; } else ohci->selfid_swap = 1; #endif @@ -2248,6 +2298,23 @@ static void remove_card(struct ti_ohci *ohci) release_mem_region (pci_resource_start(ohci->dev, 0), pci_resource_len(ohci->dev, 0)); +#ifdef CONFIG_ALL_PPC + /* On UniNorth, power down the cable and turn off the + * chip clock when the module is removed to save power + * on laptops. Turning it back ON is done by the arch + * code when pci_enable_device() is called + */ + { + struct device_node* of_node; + + of_node = pci_device_to_OF_node(ohci->dev); + if (of_node) { + feature_set_firewire_power(of_node, 0); + feature_set_firewire_cable_power(of_node, 0); + } + } +#endif /* CONFIG_ALL_PPC */ + pci_set_drvdata(ohci->dev, NULL); } @@ -2292,68 +2359,6 @@ void ohci1394_unregister_video(struct ti_ohci *ohci, } } -#ifndef __LITTLE_ENDIAN - -/* Swap a series of quads inplace. */ -static __inline__ void block_swab32(quadlet_t *data, size_t size) { - while (size--) - data[size] = swab32(data[size]); -} - -/* Swap headers and sometimes data too */ -static void packet_swab(quadlet_t *data, char tcode, int len, int payload_swap) -{ - if (payload_swap) { - block_swab32(data, len); - return; - } - - switch(tcode) - { - /* 4 quad header */ - case TCODE_READB_RESPONSE: - case TCODE_LOCK_RESPONSE: - case TCODE_LOCK_REQUEST: - case TCODE_WRITEB: - case TCODE_READB: - block_swab32(data, 4); - break; - - /* 3 quad header, 1 quad payload */ - case TCODE_WRITEQ: - case TCODE_READQ_RESPONSE: - block_swab32(data, 3); - break; - - /* 3 quad header */ - case TCODE_WRITE_RESPONSE: - case TCODE_READQ: - block_swab32(data, 3); - break; - - /* 2 quad header */ - case TCODE_ISO_DATA: - block_swab32(data, 2); - break; - - case OHCI1394_TCODE_PHY: - break; /* should never happen anyway */ - - case TCODE_CYCLE_START: - PRINT_G(KERN_ERR, "Unhandled tcode in packet_swab (0x%x)", tcode); - /* Atleast swap one quad */ - block_swab32(data, 1); - break; - default: - PRINT_G(KERN_ERR, "Invalid tcode in packet_swab (0x%x)", tcode); - break; - } - return; -} - -#endif /* !LITTLE_ENDIAN */ - - #if 0 int ohci1394_request_channel(struct ti_ohci *ohci, int channel) { diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h index 985ce439ec2e..3ab491270135 100644 --- a/drivers/ieee1394/ohci1394.h +++ b/drivers/ieee1394/ohci1394.h @@ -191,15 +191,14 @@ struct ti_ohci { spinlock_t event_lock; int self_id_errors; - int NumBusResets; /* video device */ struct video_template *video_tmpl; /* Swap the selfid buffer? */ unsigned int selfid_swap:1; - /* Swap the payload? */ - unsigned int payload_swap:1; + /* Some Apple chipset seem to swap incoming headers for us */ + unsigned int no_swap_incoming:1; }; static inline int cross_bound(unsigned long addr, unsigned int size) @@ -332,14 +331,16 @@ static inline u32 reg_read(const struct ti_ohci *ohci, int offset) #define OHCI1394_phyRegRcvd 0x04000000 #define OHCI1394_masterIntEnable 0x80000000 -#define OUTPUT_MORE 0x00000000 -#define OUTPUT_MORE_IMMEDIATE 0x02000000 -#define OUTPUT_LAST 0x103c0000 -#define OUTPUT_LAST_IMMEDIATE 0x123c0000 - -#define DMA_SPEED_100 0x0 -#define DMA_SPEED_200 0x1 -#define DMA_SPEED_400 0x2 +/* DMA Control flags */ +#define DMA_CTL_OUTPUT_MORE 0x00000000 +#define DMA_CTL_OUTPUT_LAST 0x10000000 +#define DMA_CTL_INPUT_MORE 0x20000000 +#define DMA_CTL_INPUT_LAST 0x30000000 +#define DMA_CTL_UPDATE 0x08000000 +#define DMA_CTL_IMMEDIATE 0x02000000 +#define DMA_CTL_IRQ 0x00300000 +#define DMA_CTL_BRANCH 0x000c0000 +#define DMA_CTL_WAIT 0x00030000 #define OHCI1394_TCODE_PHY 0xE diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c index ee7d5b99150c..815176c8fc1f 100644 --- a/drivers/ieee1394/pcilynx.c +++ b/drivers/ieee1394/pcilynx.c @@ -38,6 +38,7 @@ #include "ieee1394_types.h" #include "hosts.h" #include "ieee1394_core.h" +#include "highlevel.h" #include "pcilynx.h" @@ -393,7 +394,7 @@ static void send_next(struct ti_lynx *lynx, int what) struct lynx_send_data *d; struct hpsb_packet *packet; - d = (what == iso ? &lynx->iso_send : &lynx->async); + d = (what == hpsb_iso ? &lynx->iso_send : &lynx->async); packet = d->queue; d->header_dma = pci_map_single(lynx->dev, packet->header, @@ -419,13 +420,13 @@ static void send_next(struct ti_lynx *lynx, int what) pcl.buffer[1].pointer = d->data_dma; switch (packet->type) { - case async: + case hpsb_async: pcl.buffer[0].control |= PCL_CMD_XMT; break; - case iso: + case hpsb_iso: pcl.buffer[0].control |= PCL_CMD_XMT | PCL_ISOMODE; break; - case raw: + case hpsb_raw: pcl.buffer[0].control |= PCL_CMD_UNFXMT; break; } @@ -606,11 +607,11 @@ static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet) } switch (packet->type) { - case async: - case raw: + case hpsb_async: + case hpsb_raw: d = &lynx->async; break; - case iso: + case hpsb_iso: d = &lynx->iso_send; break; default: @@ -1227,7 +1228,7 @@ static void lynx_irq_handler(int irq, void *dev_id, } if (lynx->async.queue != NULL) { - send_next(lynx, async); + send_next(lynx, hpsb_async); } spin_unlock(&lynx->async.queue_lock); @@ -1259,7 +1260,7 @@ static void lynx_irq_handler(int irq, void *dev_id, } if (lynx->iso_send.queue != NULL) { - send_next(lynx, iso); + send_next(lynx, hpsb_iso); } spin_unlock(&lynx->iso_send.queue_lock); @@ -1368,7 +1369,7 @@ static int __devinit add_card(struct pci_dev *dev, FAIL("failed to allocate host structure"); lynx->state = have_host_struct; - + lynx->host->hostdata = lynx; lynx->id = num_of_cards-1; lynx->dev = dev; lynx->host->pdev = dev; @@ -1501,6 +1502,9 @@ static int __devinit add_card(struct pci_dev *dev, PRINT(KERN_INFO, lynx->id, "found old 1394 PHY"); } + /* Tell the highlevel this host is ready */ + highlevel_add_one_host (lynx->host); + return 0; #undef FAIL } @@ -1633,8 +1637,8 @@ MODULE_DEVICE_TABLE(pci, pci_table); static void __exit pcilynx_cleanup(void) { - pci_unregister_driver(&lynx_pcidriver); hpsb_unregister_lowlevel(&lynx_template); + pci_unregister_driver(&lynx_pcidriver); PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module"); } diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index 03a72ab10eb3..903ddbcb7755 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c @@ -290,8 +290,11 @@ static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data, } spin_unlock_irqrestore(&host_info_lock, flags); - list_for_each(lh, &reqs) { + lh = reqs.next; + while (lh != &reqs) { req = list_entry(lh, struct pending_request, list); + lh = lh->next; + queue_complete_req(req); } } @@ -356,8 +359,11 @@ static void fcp_request(struct hpsb_host *host, int nodeid, int direction, } spin_unlock_irqrestore(&host_info_lock, flags); - list_for_each(lh, &reqs) { + lh = reqs.next; + while (lh != &reqs) { req = list_entry(lh, struct pending_request, list); + lh = lh->next; + queue_complete_req(req); } } @@ -746,6 +752,8 @@ static int handle_remote_request(struct file_info *fi, list_add_tail(&req->list, &fi->req_pending); spin_unlock_irq(&fi->reqlists_lock); + packet->generation = req->req.generation; + if (!hpsb_send_packet(packet)) { req->req.error = RAW1394_ERROR_SEND_ERROR; req->req.length = 0; @@ -766,7 +774,7 @@ static int handle_iso_send(struct file_info *fi, struct pending_request *req, fill_iso_packet(packet, req->req.length, channel & 0x3f, (req->req.misc >> 16) & 0x3, req->req.misc & 0xf); - packet->type = iso; + packet->type = hpsb_iso; packet->speed_code = req->req.address & 0x3; packet->host = fi->host; @@ -787,6 +795,9 @@ static int handle_iso_send(struct file_info *fi, struct pending_request *req, list_add_tail(&req->list, &fi->req_pending); spin_unlock_irq(&fi->reqlists_lock); + /* Update the generation of the packet just before sending. */ + packet->generation = get_hpsb_generation(fi->host); + if (!hpsb_send_packet(packet)) { req->req.error = RAW1394_ERROR_SEND_ERROR; queue_complete_req(req); diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index a69131f98d82..594680253913 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -122,26 +122,14 @@ * are some stress issues under investigation with deserialized I/O. To enable * deserialized I/O for testing, do "insmod sbp2 serialize_io=0" * - * - Hot-Plugging: Need to add procfs support and integration with linux - * hot-plug support (http://linux-hotplug.sourceforge.net) for auto-mounting - * of drives. - * * - Error Handling: SCSI aborts and bus reset requests are handled somewhat * but the code needs additional debugging. * - * - IEEE-1394 Bus Management: There is currently little bus management - * in the core IEEE-1394 stack. Because of this, the SBP-2 driver handles - * detection of SBP-2 devices itself. This should be moved to the core - * stack. - * * - The SBP-2 driver is currently only supported as a module. It would not take * much work to allow it to be compiled into the kernel, but you'd have to * add some init code to the kernel to support this... and modules are much * more flexible anyway. ;-) * - * - Workaround for PPC pismo firewire chipset (enable SBP2_PPC_PISMO_WORKAROUND - * define below). - * * * History: * @@ -222,8 +210,18 @@ * <bcollins@debian.org * 07/22/01 - Use NodeMngr to get info about the local host and * attached devices. Ben Collins + * + * 09/15/01 - Remove detection code, instead subscribe to the nodemgr + * driver management interface. This also removes the + * initial bus scan stuff since the nodemgr calls + * sbp2_probe for each sbp2 device already on the bus, + * when we register our driver. This change + * automtically adds hotplug support to the driver. + * Kristian Hogsberg <hogsberg@users.sf.net> */ + + /* * Includes */ @@ -264,50 +262,26 @@ #include "sbp2.h" /* - * PPC firewire Pismo chipset workaround!!! - * - * This is a workaround for a bug in the firewire pismo chipset. For some odd reason the status - * fifo address hi/lo must be byteswapped and the response address byteswapped, but no other - * parts of the structure. Apple's drivers seem to specifically check for the pismo and do - * the same workaround for sbp2. (Daniel Berlin) - * - * Please enable the following define if you're running on the PPC Pismo chipset. - */ - -#ifdef CONFIG_IEEE1394_SBP2_PISMO -#define SBP2_NEED_LOGIN_DESCRIPTOR_WORKAROUND -#endif - -/* * Module load parameter definitions */ /* - * Normally the sbp2 driver tries to catch the initial scsi bus scan to pick up any - * attached sbp2 devices. Setting no_bus_scan to 1 tells the sbp2 driver not to catch - * this initial scsi bus scan on module load. You can always either add or remove devices - * later through the rescan-scsi-bus.sh script or scsi procfs. - */ -MODULE_PARM(no_bus_scan,"i"); -MODULE_PARM_DESC(no_bus_scan, "Skip the initial scsi bus scan during module load"); -static int no_bus_scan = 0; - -/* - * Set mode_sense_hack to 1 if you have some sort of unusual sbp2 device, like a 1394 memory - * stick reader, compact flash reader, or MO drive that does not support mode sense. Allows - * you to mount the media rw instead of ro. + * Set mode_sense_hack to 1 if you have some sort of unusual sbp2 device, + * like a 1394 memory stick reader, compact flash reader, or MO drive that + * does not support mode sense. Allows you to mount the media rw instead + * of ro. */ MODULE_PARM(mode_sense_hack,"i"); MODULE_PARM_DESC(mode_sense_hack, "Emulate mode sense for devices like 1394 memory stick readers"); static int mode_sense_hack = 0; /* - * Change max_speed on module load if you have a bad IEEE-1394 controller that has trouble running - * 2KB packets at 400mb. + * Change max_speed on module load if you have a bad IEEE-1394 controller + * that has trouble running 2KB packets at 400mb. * - * NOTE: On certain OHCI parts I have seen short packets on async transmit (probably - * due to PCI latency/throughput issues with the part). You can bump down the speed if - * you are running into problems. + * NOTE: On certain OHCI parts I have seen short packets on async transmit + * (probably due to PCI latency/throughput issues with the part). You can + * bump down the speed if you are running into problems. * * Valid values: * max_speed = 2 (default: max speed 400mb) @@ -319,30 +293,37 @@ MODULE_PARM_DESC(max_speed, "Force down max speed (2 = 400mb default, 1 = 200mb, static int max_speed = SPEED_400; /* - * Set serialize_io to 1 if you'd like only one scsi command sent down to us at a time (debugging). + * Set serialize_io to 1 if you'd like only one scsi command sent down to + * us at a time (debugging). */ MODULE_PARM(serialize_io,"i"); MODULE_PARM_DESC(serialize_io, "Serialize all I/O coming down from the scsi drivers (debugging)"); static int serialize_io = 1; /* serialize I/O until stress issues are resolved */ /* - * Set no_large_packets to 1 if you'd like to limit the size of requests sent down to us (normally - * the sbp2 driver will break up any requests to any individual devices with 128KB transfer size limits). - * Sets max s/g list elements to 0x1f in size and disables s/g clustering. + * Set no_large_packets to 1 if you'd like to limit the size of requests + * sent down to us (normally the sbp2 driver will break up any requests to + * any individual devices with 128KB transfer size limits). Sets max s/g + * list elements to 0x1f in size and disables s/g clustering. */ MODULE_PARM(no_large_packets,"i"); MODULE_PARM_DESC(no_large_packets, "Do not allow large transfers from scsi drivers (debugging)"); static int no_large_packets = 0; /* - * Export information about protocols/devices supported by this driver + * Export information about protocols/devices supported by this driver. */ static struct ieee1394_device_id sbp2_id_table[] = { - IEEE1394_PROTOCOL(SBP2_UNIT_SPEC_ID_ENTRY, SBP2_SW_VERSION_ENTRY), + { + match_flags: IEEE1394_MATCH_SPECIFIER_ID | + IEEE1394_MATCH_VERSION, + specifier_id: SBP2_UNIT_SPEC_ID_ENTRY & 0xffffff, + version: SBP2_SW_VERSION_ENTRY & 0xffffff + }, { } }; -MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table); +MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table); /* * Debug levels, configured via kernel config. @@ -372,6 +353,7 @@ static u32 global_outstanding_dmas = 0; #define SBP2_DMA_FREE(fmt, args...) #endif + #if CONFIG_IEEE1394_SBP2_DEBUG >= 2 #define SBP2_DEBUG(fmt, args...) HPSB_ERR(fmt, ## args) #define SBP2_INFO(fmt, args...) HPSB_ERR(fmt, ## args) @@ -392,12 +374,14 @@ static u32 global_outstanding_dmas = 0; #define SBP2_ERR(fmt, args...) HPSB_ERR(fmt, ## args) /* - * Spinlock debugging stuff. I'm playing it safe until the driver has been debugged on SMP. (JSG) + * Spinlock debugging stuff. I'm playing it safe until the driver has been + * debugged on SMP. (JSG) */ /* #define SBP2_USE_REAL_SPINLOCKS */ #ifdef SBP2_USE_REAL_SPINLOCKS #define sbp2_spin_lock(lock, flags) spin_lock_irqsave(lock, flags) #define sbp2_spin_unlock(lock, flags) spin_unlock_irqrestore(lock, flags); +static spinlock_t sbp2_host_info_lock = SPIN_LOCK_UNLOCKED; #else #define sbp2_spin_lock(lock, flags) do {save_flags(flags); cli();} while (0) #define sbp2_spin_unlock(lock, flags) do {restore_flags(flags);} while (0) @@ -411,28 +395,27 @@ Scsi_Host_Template *global_scsi_tpnt = NULL; static LIST_HEAD(sbp2_host_info_list); static int sbp2_host_count = 0; -static spinlock_t sbp2_host_info_lock = SPIN_LOCK_UNLOCKED; static struct hpsb_highlevel *sbp2_hl_handle = NULL; static struct hpsb_highlevel_ops sbp2_hl_ops = { - sbp2_add_host, - sbp2_remove_host, - sbp2_host_reset, - NULL, - NULL + add_host: sbp2_add_host, + remove_host: sbp2_remove_host, }; static struct hpsb_address_ops sbp2_ops = { - write: sbp2_handle_status_write, + write: sbp2_handle_status_write }; -#if 0 -static struct hpsb_address_ops sbp2_physdma_ops = { - read: sbp2_handle_physdma_read, - write: sbp2_handle_physdma_write, +static struct hpsb_protocol_driver sbp2_driver = { + name: "SBP2 Driver", + id_table: sbp2_id_table, + probe: sbp2_probe, + disconnect: sbp2_disconnect, + update: sbp2_update }; -#endif + + /************************************** * General utility functions @@ -472,108 +455,29 @@ static __inline__ void sbp2util_cpu_to_be32_buffer(void *buffer, int length) #endif /* - * This function does quadlet sized reads (used by detection code) - */ -static int sbp2util_read_quadlet(struct sbp2scsi_host_info *hi, nodeid_t node, u64 addr, - quadlet_t *buffer) -{ - int retval = 0; - int retry_count = 3; - - /* - * Retry a couple times if needed (for slow devices) - */ - do { - - retval = hpsb_read(hi->host, node, addr, buffer, 4); - - if (retval) { - SBP2_DEBUG("sbp2: sbp2util_read_quadlet data packet error"); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/50); /* 20ms delay */ - } - - retry_count--; - - } while (retval && retry_count); - - return(retval); -} - -/* - * This function returns the address of the unit directory. - */ -static int sbp2util_unit_directory(struct sbp2scsi_host_info *hi, nodeid_t node_id, u64 *unit_directory_addr) -{ - quadlet_t root_directory_length, current_quadlet; - u64 current_addr; - int length, i; - - /* - * First, read the first quadlet of the root directory to determine its size - */ - if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, CONFIG_ROM_ROOT_DIR_BASE, - &root_directory_length)) { - SBP2_DEBUG("sbp2: Error reading root directory length - bad status"); - return(-EIO); - } - - current_addr = CONFIG_ROM_ROOT_DIR_BASE; - length = be32_to_cpu(root_directory_length) >> 16; - - /* - * Step through the root directory and look for the "Unit_Directory entry", which - * contains the offset to the unit directory. - */ - for (i=0; i < length; i++) { - - current_addr += 4; - - if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, current_addr, ¤t_quadlet)) { - SBP2_DEBUG("sbp2: Error reading at address 0x%08x%08x - bad status", - (unsigned int) ((current_addr) >> 32), (unsigned int) ((current_addr) & 0xffffffff)); - return(-EIO); - } - - /* - * Check for unit directory offset tag - */ - if ((be32_to_cpu(current_quadlet) >> 24) == SBP2_UNIT_DIRECTORY_OFFSET_KEY) { - *unit_directory_addr = current_addr + 4 * ((be32_to_cpu(current_quadlet) & 0xffffff)); - SBP2_DEBUG("sbp2: unit_directory_addr = %lu", *unit_directory_addr); - } - } - - return(0); -} - -/* - * This function is called to initially create a packet pool for use in sbp2 I/O requests. - * This packet pool is used when sending out sbp2 command and agent reset requests, and - * allows us to remove all kmallocs/kfrees from the critical I/O paths. + * This function is called to initially create a packet pool for use in + * sbp2 I/O requests. This packet pool is used when sending out sbp2 + * command and agent reset requests, and allows us to remove all + * kmallocs/kfrees from the critical I/O paths. */ static int sbp2util_create_request_packet_pool(struct sbp2scsi_host_info *hi) { struct hpsb_packet *packet; int i; - unsigned long flags; - /* - * Create SBP2_MAX_REQUEST_PACKETS number of request packets. - */ - sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags); + /* Create SBP2_MAX_REQUEST_PACKETS number of request packets. */ for (i=0; i<SBP2_MAX_REQUEST_PACKETS; i++) { /* - * Max payload of 8 bytes since the sbp2 command request uses a payload of - * 8 bytes, and agent reset is a quadlet write request. Bump this up if we - * plan on using this pool for other stuff. + * Max payload of 8 bytes since the sbp2 command request + * uses a payload of 8 bytes, and agent reset is a quadlet + * write request. Bump this up if we plan on using this + * pool for other stuff. */ packet = alloc_hpsb_packet(8); if (!packet) { SBP2_ERR("sbp2: sbp2util_create_request_packet_pool - packet allocation failed!"); - sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags); return(-ENOMEM); } @@ -585,13 +489,13 @@ static int sbp2util_create_request_packet_pool(struct sbp2scsi_host_info *hi) list_add_tail(&hi->request_packet[i].list, &hi->sbp2_req_free); } - sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags); return(0); } /* - * This function is called to remove the packet pool. It is called when the sbp2 driver is unloaded. + * This function is called to remove the packet pool. It is called when + * the sbp2 driver is unloaded. */ static void sbp2util_remove_request_packet_pool(struct sbp2scsi_host_info *hi) { @@ -624,15 +528,17 @@ static void sbp2util_remove_request_packet_pool(struct sbp2scsi_host_info *hi) } /* - * This function is called to retrieve a block write packet from our packet pool. This function is - * used in place of calling alloc_hpsb_packet (which costs us three kmallocs). Instead we - * just pull out a free request packet and re-initialize values in it. I'm sure this can still - * stand some more optimization. - */ -static struct sbp2_request_packet *sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi, - nodeid_t node, u64 addr, - size_t data_size, - quadlet_t data) { + * This function is called to retrieve a block write packet from our + * packet pool. This function is used in place of calling + * alloc_hpsb_packet (which costs us three kmallocs). Instead we just pull + * out a free request packet and re-initialize values in it. I'm sure this + * can still stand some more optimization. + */ +static struct sbp2_request_packet * +sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi, + nodeid_t node, u64 addr, + size_t data_size, + quadlet_t data) { struct list_head *lh; struct sbp2_request_packet *request_packet = NULL; struct hpsb_packet *packet; @@ -651,13 +557,14 @@ static struct sbp2_request_packet *sbp2util_allocate_write_request_packet(struct packet = request_packet->packet; /* - * Initialize the packet (this is really initialization the core 1394 stack should do, - * but I'm doing it myself to avoid the overhead). + * Initialize the packet (this is really initialization + * the core 1394 stack should do, but I'm doing it myself + * to avoid the overhead). */ packet->data_size = data_size; INIT_LIST_HEAD(&packet->list); sema_init(&packet->state_change, 0); - packet->state = unused; + packet->state = hpsb_unused; packet->generation = get_hpsb_generation(hi->host); packet->data_be = 1; @@ -672,8 +579,8 @@ static struct sbp2_request_packet *sbp2util_allocate_write_request_packet(struct } /* - * Set up a task queue completion routine, which returns the packet to the free list - * and releases the tlabel + * Set up a task queue completion routine, which returns + * the packet to the free list and releases the tlabel. */ request_packet->tq.routine = (void (*)(void*))sbp2util_free_request_packet; request_packet->tq.data = request_packet; @@ -681,7 +588,7 @@ static struct sbp2_request_packet *sbp2util_allocate_write_request_packet(struct queue_task(&request_packet->tq, &packet->complete_tq); /* - * Now, put the packet on the in-use list + * Now, put the packet on the in-use list. */ list_add_tail(&request_packet->list, &hi->sbp2_req_inuse); @@ -694,8 +601,8 @@ static struct sbp2_request_packet *sbp2util_allocate_write_request_packet(struct } /* - * This function is called to return a packet to our packet pool. It is also called as a - * completion routine when a request packet is completed. + * This function is called to return a packet to our packet pool. It is + * also called as a completion routine when a request packet is completed. */ static void sbp2util_free_request_packet(struct sbp2_request_packet *request_packet) { @@ -703,7 +610,7 @@ static void sbp2util_free_request_packet(struct sbp2_request_packet *request_pac struct sbp2scsi_host_info *hi = request_packet->hi_context; /* - * Free the tlabel, and return the packet to the free pool + * Free the tlabel, and return the packet to the free pool. */ sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags); free_tlabel(hi->host, LOCAL_BUS | request_packet->packet->node_id, @@ -716,8 +623,8 @@ static void sbp2util_free_request_packet(struct sbp2_request_packet *request_pac } /* - * This function is called to create a pool of command orbs used for command processing. It is called - * when a new sbp2 device is detected. + * This function is called to create a pool of command orbs used for + * command processing. It is called when a new sbp2 device is detected. */ static int sbp2util_create_command_orb_pool(struct scsi_id_instance_data *scsi_id, struct sbp2scsi_host_info *hi) @@ -785,10 +692,11 @@ static void sbp2util_remove_command_orb_pool(struct scsi_id_instance_data *scsi_ } /* - * This functions finds the sbp2_command for a given outstanding - * command orb. Only looks at the inuse list. + * This functions finds the sbp2_command for a given outstanding command + * orb. Only looks at the inuse list. */ -static struct sbp2_command_info *sbp2util_find_command_for_orb(struct scsi_id_instance_data *scsi_id, dma_addr_t orb) +static struct sbp2_command_info *sbp2util_find_command_for_orb( + struct scsi_id_instance_data *scsi_id, dma_addr_t orb) { struct list_head *lh; struct sbp2_command_info *command; @@ -812,7 +720,8 @@ static struct sbp2_command_info *sbp2util_find_command_for_orb(struct scsi_id_in } /* - * This functions finds the sbp2_command for a given outstanding SCpnt. Only looks at the inuse list + * This functions finds the sbp2_command for a given outstanding SCpnt. + * Only looks at the inuse list. */ static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_instance_data *scsi_id, void *SCpnt) { @@ -837,10 +746,11 @@ static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_ /* * This function allocates a command orb used to send a scsi command. */ -static struct sbp2_command_info *sbp2util_allocate_command_orb(struct scsi_id_instance_data *scsi_id, - Scsi_Cmnd *Current_SCpnt, - void (*Current_done)(Scsi_Cmnd *), - struct sbp2scsi_host_info *hi) +static struct sbp2_command_info *sbp2util_allocate_command_orb( + struct scsi_id_instance_data *scsi_id, + Scsi_Cmnd *Current_SCpnt, + void (*Current_done)(Scsi_Cmnd *), + struct sbp2scsi_host_info *hi) { struct list_head *lh; struct sbp2_command_info *command = NULL; @@ -903,13 +813,15 @@ static void sbp2util_mark_command_completed(struct scsi_id_instance_data *scsi_i sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags); } + + /********************************************* * IEEE-1394 core driver stack related section *********************************************/ /* - * This function is called at SCSI init in order to register our driver with the - * IEEE-1394 stack + * This function is called at SCSI init in order to register our driver + * with the IEEE-1394 stack. */ int sbp2_init(void) { @@ -931,26 +843,21 @@ int sbp2_init(void) hpsb_register_addrspace(sbp2_hl_handle, &sbp2_ops, SBP2_STATUS_FIFO_ADDRESS, SBP2_STATUS_FIFO_ADDRESS + sizeof(struct sbp2_status_block)); - /* - * Register physical dma address space... used for - * adapters not supporting hardware phys dma. - * - * XXX: Disabled for now. - */ - /* hpsb_register_addrspace(sbp2_hl_handle, &sbp2_physdma_ops, - 0x0ULL, 0xfffffffcULL); */ + hpsb_register_protocol(&sbp2_driver); - return(0); + return 0; } /* - * This function is called from cleanup module, or during shut-down, in order to - * unregister our driver + * This function is called from cleanup module, or during shut-down, in + * order to unregister our driver. */ void sbp2_cleanup(void) { SBP2_DEBUG("sbp2: sbp2_cleanup"); + hpsb_unregister_protocol(&sbp2_driver); + if (sbp2_hl_handle) { hpsb_unregister_highlevel(sbp2_hl_handle); sbp2_hl_handle = NULL; @@ -958,73 +865,121 @@ void sbp2_cleanup(void) return; } -/* - * This function is called after registering our operations in sbp2_init. We go ahead and - * allocate some memory for our host info structure, and init some structures. - */ -static void sbp2_add_host(struct hpsb_host *host) +static int sbp2_probe(struct unit_directory *ud) { struct sbp2scsi_host_info *hi; - unsigned long flags; - SBP2_DEBUG("sbp2: sbp2_add_host"); + SBP2_DEBUG("sbp2: sbp2_probe"); + hi = sbp2_find_host_info(ud->ne->host); - /* - * Allocate some memory for our host info structure - */ - hi = (struct sbp2scsi_host_info *)kmalloc(sizeof(struct sbp2scsi_host_info), GFP_KERNEL); + return sbp2_start_device(hi, ud); +} - if (hi != NULL) { +static void sbp2_disconnect(struct unit_directory *ud) +{ + struct sbp2scsi_host_info *hi; + struct scsi_id_instance_data *scsi_id = ud->driver_data; - /* - * Initialize some host stuff - */ - memset(hi, 0, sizeof(struct sbp2scsi_host_info)); - INIT_LIST_HEAD(&hi->list); - INIT_LIST_HEAD(&hi->sbp2_req_inuse); - INIT_LIST_HEAD(&hi->sbp2_req_free); - hi->host = host; - hi->sbp2_command_lock = SPIN_LOCK_UNLOCKED; - hi->sbp2_request_packet_lock = SPIN_LOCK_UNLOCKED; + SBP2_DEBUG("sbp2: sbp2_disconnect"); + hi = sbp2_find_host_info(ud->ne->host); - /* - * Create our request packet pool (pool of packets for use in I/O) + if (hi != NULL) + sbp2_remove_device(hi, scsi_id); +} + +static void sbp2_update(struct unit_directory *ud) +{ + struct sbp2scsi_host_info *hi; + struct scsi_id_instance_data *scsi_id = ud->driver_data; + unsigned long flags; + + SBP2_DEBUG("sbp2: sbp2_update"); + hi = sbp2_find_host_info(ud->ne->host); + + if (sbp2_reconnect_device(hi, scsi_id)) { + + /* Ok, reconnect has failed. Perhaps we didn't + * reconnect fast enough. Try doing a regular login. */ - if (sbp2util_create_request_packet_pool(hi)) { - SBP2_ERR("sbp2: sbp2util_create_request_packet_pool failed!"); + if (sbp2_login_device(hi, scsi_id)) { + + /* Login failed too... so, just mark him as + * unvalidated, so that he gets cleaned up + * later. + */ + SBP2_ERR("sbp2: sbp2_reconnect_device failed!"); + sbp2_remove_device(hi, scsi_id); return; } + } - sbp2_spin_lock(&sbp2_host_info_lock, flags); - list_add_tail(&hi->list, &sbp2_host_info_list); - sbp2_host_count++; - sbp2_spin_unlock(&sbp2_host_info_lock, flags); + /* Set max retries to something large on the device. */ + sbp2_set_busy_timeout(hi, scsi_id); - /* - * Initialize us to bus reset in progress - */ - hi->bus_reset_in_progress = 1; + /* Do a SBP-2 fetch agent reset. */ + sbp2_agent_reset(hi, scsi_id, 0); + + /* Get the max speed and packet size that we can use. */ + sbp2_max_speed_and_size(hi, scsi_id); - /* - * Register our host with the SCSI stack. - */ - sbp2scsi_register_scsi_host(hi); + /* Complete any pending commands with busy (so they get + * retried) and remove them from our queue + */ + sbp2_spin_lock(&hi->sbp2_command_lock, flags); + sbp2scsi_complete_all_commands(hi, scsi_id, DID_BUS_BUSY); + sbp2_spin_unlock(&hi->sbp2_command_lock, flags); +} - /* - * Start our kernel thread to deal with sbp2 device detection - */ - init_waitqueue_head(&hi->sbp2_detection_wait); - hi->sbp2_detection_pid = 0; - hi->sbp2_detection_pid = kernel_thread(sbp2_detection_thread, hi, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); +/* + * This function is called after registering our operations in sbp2_init. + * We go ahead and allocate some memory for our host info structure, and + * init some structures. + */ +static void sbp2_add_host(struct hpsb_host *host) +{ + struct sbp2scsi_host_info *hi; + unsigned long flags; + SBP2_DEBUG("sbp2: sbp2_add_host"); + + /* Allocate some memory for our host info structure */ + hi = (struct sbp2scsi_host_info *)kmalloc(sizeof(struct sbp2scsi_host_info), + GFP_KERNEL); + + if (hi == NULL) { + SBP2_ERR("sbp2: out of memory in sbp2_add_host"); + return; } + /* Initialize some host stuff */ + memset(hi, 0, sizeof(struct sbp2scsi_host_info)); + INIT_LIST_HEAD(&hi->list); + INIT_LIST_HEAD(&hi->sbp2_req_inuse); + INIT_LIST_HEAD(&hi->sbp2_req_free); + hi->host = host; + hi->sbp2_command_lock = SPIN_LOCK_UNLOCKED; + hi->sbp2_request_packet_lock = SPIN_LOCK_UNLOCKED; + + /* Create our request packet pool (pool of packets for use in I/O) */ + if (sbp2util_create_request_packet_pool(hi)) { + SBP2_ERR("sbp2: sbp2util_create_request_packet_pool failed!"); + return; + } + + sbp2_spin_lock(&sbp2_host_info_lock, flags); + list_add_tail(&hi->list, &sbp2_host_info_list); + sbp2_host_count++; + sbp2_spin_unlock(&sbp2_host_info_lock, flags); + + /* Register our host with the SCSI stack. */ + sbp2scsi_register_scsi_host(hi); + return; } /* - * This fuction returns a host info structure from the host structure, - * in case we have multiple hosts + * This fuction returns a host info structure from the host structure, in + * case we have multiple hosts. */ static struct sbp2scsi_host_info *sbp2_find_host_info(struct hpsb_host *host) { @@ -1047,206 +1002,55 @@ static struct sbp2scsi_host_info *sbp2_find_host_info(struct hpsb_host *host) static void sbp2_remove_host(struct hpsb_host *host) { struct sbp2scsi_host_info *hi; - int i; unsigned long flags; + int i; SBP2_DEBUG("sbp2: sbp2_remove_host"); sbp2_spin_lock(&sbp2_host_info_lock, flags); - hi = sbp2_find_host_info(host); + hi = sbp2_find_host_info(host); if (hi != NULL) { - - /* - * Need to remove any attached SBP-2 devices. Also make sure to logout of all devices. + /* Here's an annoying hack: we get a disconnect + * callback for each device, so this loop shouldn't be + * necessary. However, the sbp2 driver receives the + * remove_host callback before the nodemgr, so when we + * get the disconnect callback, we've already freed + * the host. Thus, we free the devices here... */ - for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) { - if (hi->scsi_id[i]) { + for (i = 0; i < SBP2SCSI_MAX_SCSI_IDS; i++) { + if (hi->scsi_id[i] != NULL) { sbp2_logout_device(hi, hi->scsi_id[i]); - hi->scsi_id[i]->validated = 0; + sbp2_remove_device(hi, hi->scsi_id[i]); } } - - sbp2_remove_unvalidated_devices(hi); - - list_del(&hi->list); + sbp2util_remove_request_packet_pool(hi); sbp2_host_count--; + list_del(&hi->list); + kfree(hi); } - sbp2_spin_unlock(&sbp2_host_info_lock, flags); - - if (hi == NULL) { + else SBP2_ERR("sbp2: attempt to remove unknown host %p", host); - return; - } - - /* - * Remove the packet pool (release the packets) - */ - sbp2util_remove_request_packet_pool(hi); - - /* - * Kill our detection thread - */ - if (hi->sbp2_detection_pid >= 0) { - kill_proc(hi->sbp2_detection_pid, SIGINT, 1); - } - - /* - * Give the detection thread a little time to exit - */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ); /* 1 second delay */ - - kfree(hi); - hi = NULL; - - return; -} - -/* - * This is our sbp2 detection thread. It is signalled when bus resets occur - * so that we can find and initialize any sbp2 devices. - */ -static int sbp2_detection_thread(void *__hi) -{ - struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *)__hi; - SBP2_DEBUG("sbp2: sbp2_detection_thread"); - - lock_kernel(); - - /* - * This thread doesn't need any user-level access, - * so get rid of all our resources - */ -#if LINUX_VERSION_CODE > 0x20300 - daemonize(); -#endif - - /* - * Set-up a nice name - */ - strcpy(current->comm, SBP2_DEVICE_NAME); - - unlock_kernel(); - - while ((!signal_pending(current)) && hi) { - - /* - * Process our bus reset now - */ - if (hi) { - MOD_INC_USE_COUNT; - sbp2_bus_reset_handler(hi); - MOD_DEC_USE_COUNT; - } - - /* - * Sleep until next bus reset - */ - if (hi) { - interruptible_sleep_on(&hi->sbp2_detection_wait); - } - } - - return(0); + sbp2_spin_unlock(&sbp2_host_info_lock, flags); } /* - * This function is where we first pull the node unique ids, and then allocate memory and register - * a SBP-2 device + * This function is where we first pull the node unique ids, and then + * allocate memory and register a SBP-2 device. */ -static int sbp2_start_device(struct sbp2scsi_host_info *hi, int node_id) +static int sbp2_start_device(struct sbp2scsi_host_info *hi, struct unit_directory *ud) { - u64 node_unique_id; struct scsi_id_instance_data *scsi_id = NULL; struct node_entry *ne; int i; SBP2_DEBUG("sbp2: sbp2_start_device"); - - /* XXX: This will go away once we start using the nodemgr's - * feature subscription API. */ - ne = hpsb_nodeid_get_entry(node_id|(hi->host->node_id & BUS_MASK)); - if (!ne) { - HPSB_ERR("sbp2: Could not find device node"); - return -ENXIO; - } - - node_unique_id = ne->guid; - - /* - * First, we need to find out whether this is a "new" SBP-2 device plugged in, or one that already - * exists and is initialized. We do this by looping through our scsi id instance data structures - * looking for matching node unique ids. - */ - for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) { - - if (hi->scsi_id[i]) { - - if (hi->scsi_id[i]->node_unique_id == node_unique_id) { - - /* - * Update our node id - */ - hi->scsi_id[i]->node_id = node_id; - - /* - * Mark the device as validated, since it still exists on the bus - */ - hi->scsi_id[i]->validated = 1; - SBP2_DEBUG("sbp2: SBP-2 device re-validated, SCSI ID = %x", (unsigned int) i); - - /* - * Reconnect to the sbp-2 device - */ - if (sbp2_reconnect_device(hi, hi->scsi_id[i])) { - - /* - * Ok, reconnect has failed. Perhaps we didn't reconnect fast enough. Try - * doing a regular login. - */ - if (sbp2_login_device(hi, hi->scsi_id[i])) { - - /* - * Login failed too... so, just mark him as unvalidated, so that he gets cleaned up - * later - */ - SBP2_ERR("sbp2: sbp2_reconnect_device failed!"); - hi->scsi_id[i]->validated = 0; - } - } - - if (hi->scsi_id[i]->validated) { - - /* - * Set max retries to something large on the device - */ - sbp2_set_busy_timeout(hi, hi->scsi_id[i]); - - /* - * Do a SBP-2 fetch agent reset - */ - sbp2_agent_reset(hi, hi->scsi_id[i], 0); - - /* - * Get the max speed and packet size that we can use - */ - sbp2_max_speed_and_size(hi, hi->scsi_id[i]); - - } - - /* - * Nothing more to do, since we found the device - */ - return(0); - - } - } - } + ne = ud->ne; /* - * This really is a "new" device plugged in. Let's allocate memory for our scsi id instance data + * This really is a "new" device plugged in. Let's allocate memory + * for our scsi id instance data. */ scsi_id = (struct scsi_id_instance_data *)kmalloc(sizeof(struct scsi_id_instance_data), GFP_KERNEL); @@ -1318,11 +1122,11 @@ alloc_fail_first: /* * Initialize some of the fields in this structure */ - scsi_id->node_id = node_id; - scsi_id->node_unique_id = node_unique_id; - scsi_id->validated = 1; + scsi_id->ne = ne; + scsi_id->ud = ud; scsi_id->speed_code = SPEED_100; scsi_id->max_payload_size = MAX_PAYLOAD_S100; + ud->driver_data = scsi_id; init_waitqueue_head(&scsi_id->sbp2_login_wait); @@ -1335,14 +1139,11 @@ alloc_fail_first: scsi_id->sbp2_total_command_orbs = 0; /* - * Make sure that we've gotten ahold of the sbp2 management agent address. Also figure out the - * command set being used (SCSI or RBC). + * Make sure that we've gotten ahold of the sbp2 management agent + * address. Also figure out the command set being used (SCSI or + * RBC). */ - if (sbp2_parse_unit_directory(hi, scsi_id)) { - SBP2_ERR("sbp2: Error while parsing sbp2 unit directory"); - hi->scsi_id[i]->validated = 0; - return(-EIO); - } + sbp2_parse_unit_directory(scsi_id); scsi_id->sbp2_total_command_orbs = SBP2_MAX_COMMAND_ORBS; @@ -1354,447 +1155,136 @@ alloc_fail_first: } /* - * Allocate some extra command orb structures for devices with 128KB limit + * Allocate some extra command orb structures for devices with + * 128KB limit. */ if (scsi_id->sbp2_firmware_revision == SBP2_128KB_BROKEN_FIRMWARE) { scsi_id->sbp2_total_command_orbs *= 4; } /* - * Create our command orb pool - */ - if (sbp2util_create_command_orb_pool(scsi_id, hi)) { - SBP2_ERR("sbp2: sbp2util_create_command_orb_pool failed!"); - hi->scsi_id[i]->validated = 0; - return (-ENOMEM); - } - - /* * Find an empty spot to stick our scsi id instance data. */ - for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) { + for (i = 0; i < SBP2SCSI_MAX_SCSI_IDS; i++) { if (!hi->scsi_id[i]) { hi->scsi_id[i] = scsi_id; + scsi_id->id = i; SBP2_DEBUG("sbp2: New SBP-2 device inserted, SCSI ID = %x", (unsigned int) i); break; } } /* + * Create our command orb pool + */ + if (sbp2util_create_command_orb_pool(scsi_id, hi)) { + SBP2_ERR("sbp2: sbp2util_create_command_orb_pool failed!"); + sbp2_remove_device(hi, scsi_id); + return -ENOMEM; + } + + /* * Make sure we are not out of space */ - if (i >= SBP2SCSI_MAX_SCSI_IDS) { + if (i == SBP2SCSI_MAX_SCSI_IDS) { SBP2_ERR("sbp2: No slots left for SBP-2 device"); - hi->scsi_id[i]->validated = 0; - return(-EBUSY); + sbp2_remove_device(hi, scsi_id); + return -EBUSY; } /* * Login to the sbp-2 device */ - if (sbp2_login_device(hi, hi->scsi_id[i])) { + if (sbp2_login_device(hi, scsi_id)) { /* - * Login failed... so, just mark him as unvalidated, so that he gets cleaned up later + * Login failed... so, just mark him as unvalidated, so + * that he gets cleaned up later. */ SBP2_ERR("sbp2: sbp2_login_device failed"); - hi->scsi_id[i]->validated = 0; + sbp2_remove_device(hi, scsi_id); + return -EBUSY; } - if (hi->scsi_id[i]->validated) { - - /* - * Set max retries to something large on the device - */ - sbp2_set_busy_timeout(hi, hi->scsi_id[i]); - - /* - * Do a SBP-2 fetch agent reset - */ - sbp2_agent_reset(hi, hi->scsi_id[i], 0); - - /* - * Get the max speed and packet size that we can use - */ - sbp2_max_speed_and_size(hi, hi->scsi_id[i]); - - } - - return(0); -} - -/* - * This function tries to determine if a device is a valid SBP-2 device - */ -static int sbp2_check_device(struct sbp2scsi_host_info *hi, int node_id) -{ - quadlet_t unit_spec_id_data = 0, unit_sw_ver_data = 0; - quadlet_t unit_directory_length, current_quadlet; - u64 unit_directory_addr, current_addr; - unsigned int i, length; - - SBP2_DEBUG("sbp2: sbp2_check_device"); - /* - * Let's try and read the unit spec id and unit sw ver to determine if this is an SBP2 device... + * Set max retries to something large on the device */ - - if (sbp2util_unit_directory(hi, LOCAL_BUS | node_id, &unit_directory_addr)) { - SBP2_DEBUG("sbp2: Error reading unit directory address - bad status"); - return(-EIO); - } - - /* - * Read the size of the unit directory - */ - if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, unit_directory_addr, - &unit_directory_length)) { - SBP2_DEBUG("sbp2: Error reading root directory length - bad status"); - return(-EIO); - } - - current_addr = unit_directory_addr; - length = be32_to_cpu(unit_directory_length) >> 16; - + sbp2_set_busy_timeout(hi, scsi_id); + /* - * Now, step through the unit directory and look for the unit_spec_ID and the unit_sw_version + * Do a SBP-2 fetch agent reset */ - for (i=0; i < length; i++) { - - current_addr += 4; - - if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, current_addr, ¤t_quadlet)) { - SBP2_DEBUG("sbp2: Error reading at address 0x%08x%08x - bad status", - (unsigned int) ((current_addr) >> 32), (unsigned int) ((current_addr) & 0xffffffff)); - return(-EIO); - } - - /* - * Check for unit_spec_ID tag - */ - if ((be32_to_cpu(current_quadlet) >> 24) == SBP2_UNIT_SPEC_ID_KEY) { - unit_spec_id_data = current_quadlet; - SBP2_DEBUG("sbp2: Node %x, unit spec id = %x", (LOCAL_BUS | node_id), - (unsigned int) be32_to_cpu(unit_spec_id_data)); - } - - /* - * Check for unit_sw_version tag - */ - if ((be32_to_cpu(current_quadlet) >> 24) == SBP2_UNIT_SW_VERSION_KEY) { - unit_sw_ver_data = current_quadlet; - SBP2_DEBUG("sbp2: Node %x, unit sw version = %x", (LOCAL_BUS | node_id), - (unsigned int) be32_to_cpu(unit_sw_ver_data)); - } - } - + sbp2_agent_reset(hi, scsi_id, 0); + /* - * Validate unit spec id and unit sw ver to see if this is an SBP-2 device + * Get the max speed and packet size that we can use */ - if ((be32_to_cpu(unit_spec_id_data) != SBP2_UNIT_SPEC_ID_ENTRY) || - (be32_to_cpu(unit_sw_ver_data) != SBP2_SW_VERSION_ENTRY)) { + sbp2_max_speed_and_size(hi, scsi_id); - /* - * Not an sbp2 device - */ - return(-ENXIO); - } - - /* - * This device is a valid SBP-2 device - */ - SBP2_INFO("sbp2: Node 0x%04x, Found SBP-2 device", (LOCAL_BUS | node_id)); - return(0); + return 0; } /* * This function removes (cleans-up after) any unvalidated sbp2 devices */ -static void sbp2_remove_unvalidated_devices(struct sbp2scsi_host_info *hi) +static void sbp2_remove_device(struct sbp2scsi_host_info *hi, + struct scsi_id_instance_data *scsi_id) { - int i; - - /* - * Loop through and free any unvalidated scsi id instance data structures - */ - for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) { - if (hi->scsi_id[i]) { - if (!hi->scsi_id[i]->validated) { - - /* - * Complete any pending commands with selection timeout - */ - sbp2scsi_complete_all_commands(hi, hi->scsi_id[i], DID_NO_CONNECT); + /* Complete any pending commands with selection timeout */ + sbp2scsi_complete_all_commands(hi, scsi_id, DID_NO_CONNECT); - /* - * Clean up any other structures - */ - if (hi->scsi_id[i]->sbp2_total_command_orbs) { - sbp2util_remove_command_orb_pool(hi->scsi_id[i], hi); - } - if (hi->scsi_id[i]->login_response) { - pci_free_consistent(hi->host->pdev, - sizeof(struct sbp2_login_response), - hi->scsi_id[i]->login_response, - hi->scsi_id[i]->login_response_dma); - SBP2_DMA_FREE("single login FIFO"); - } - - if (hi->scsi_id[i]->login_orb) { - pci_free_consistent(hi->host->pdev, - sizeof(struct sbp2_login_orb), - hi->scsi_id[i]->login_orb, - hi->scsi_id[i]->login_orb_dma); - SBP2_DMA_FREE("single login ORB"); - } - - if (hi->scsi_id[i]->reconnect_orb) { - pci_free_consistent(hi->host->pdev, - sizeof(struct sbp2_reconnect_orb), - hi->scsi_id[i]->reconnect_orb, - hi->scsi_id[i]->reconnect_orb_dma); - SBP2_DMA_FREE("single reconnect orb"); - } - - if (hi->scsi_id[i]->logout_orb) { - pci_free_consistent(hi->host->pdev, - sizeof(struct sbp2_logout_orb), - hi->scsi_id[i]->logout_orb, - hi->scsi_id[i]->reconnect_orb_dma); - SBP2_DMA_FREE("single logout orb"); - } - - kfree(hi->scsi_id[i]); - hi->scsi_id[i] = NULL; - SBP2_DEBUG("sbp2: Unvalidated SBP-2 device removed, SCSI ID = %x", (unsigned int) i); - } - } + /* Clean up any other structures */ + if (scsi_id->sbp2_total_command_orbs) { + sbp2util_remove_command_orb_pool(scsi_id, hi); } - return; -} - -/* - * This function is our reset handler. It is run out of a thread, since we get - * notified of a bus reset from a bh (or interrupt). - */ -static void sbp2_bus_reset_handler(void *context) -{ - struct sbp2scsi_host_info *hi = context; - quadlet_t signature_data; - int i; - unsigned long flags; - struct scsi_id_instance_data *scsi_id; - - SBP2_DEBUG("sbp2: sbp2_bus_reset_handler"); - - /* - * TODO. Check and keep track of generation number of all requests, in case a - * bus reset occurs while trying to find and login to SBP-2 devices. - */ - - /* - * First thing to do. Invalidate all SBP-2 devices. This is needed so that - * we stop sending down I/O requests to the device, and also so that we can - * figure out which devices have disappeared after a bus reset. - */ - for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) { - if (hi->scsi_id[i]) { - hi->scsi_id[i]->validated = 0; - } - } - - /* - * Give the sbp2 devices a little time to recover after the bus reset - */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/2); /* 1/2 second delay */ - - /* - * Spit out what we know from the host - */ - SBP2_DEBUG("host: node_count = %x", (unsigned int) hi->host->node_count); - SBP2_DEBUG("host: selfid_count = %x", (unsigned int) hi->host->selfid_count); - SBP2_DEBUG("host: node_id = %x", (unsigned int) hi->host->node_id); - SBP2_DEBUG("host: irm_id = %x", (unsigned int) hi->host->irm_id); - SBP2_DEBUG("host: busmgr_id = %x", (unsigned int) hi->host->busmgr_id); - SBP2_DEBUG("host: is_root = %x", (unsigned int) hi->host->is_root); - SBP2_DEBUG("host: is_cycmst = %x", (unsigned int) hi->host->is_cycmst); - SBP2_DEBUG("host: is_irm = %x", (unsigned int) hi->host->is_irm); - SBP2_DEBUG("host: is_busmgr = %x", (unsigned int) hi->host->is_busmgr); - - /* - * Let's try and figure out which devices out there are SBP-2 devices! Loop through all - * nodes out there. - */ - for (i=0; i<hi->host->node_count; i++) { - - /* - * Don't read from ourselves! - */ - if (i != ((hi->host->node_id) & NODE_MASK)) { - - /* - * Try and send a request for a config rom signature. This is expected to fail for - * some nodes, as they might be repeater phys or not be initialized. - */ - if (!sbp2util_read_quadlet(hi, LOCAL_BUS | i, CONFIG_ROM_SIGNATURE_ADDRESS, &signature_data)) { - - if (be32_to_cpu(signature_data) == IEEE1394_CONFIG_ROM_SIGNATURE) { - - /* - * Hey, we've got a valid responding IEEE1394 node. Need to now see if it's an SBP-2 device - */ - if (!sbp2_check_device(hi, i)) { - - /* - * Found an SBP-2 device. Now, actually start the device. - */ - sbp2_start_device(hi, i); - } - } - } - } + if (scsi_id->login_response) { + pci_free_consistent(hi->host->pdev, + sizeof(struct sbp2_login_response), + scsi_id->login_response, + scsi_id->login_response_dma); + SBP2_DMA_FREE("single login FIFO"); } - /* - * This code needs protection - */ - sbp2_spin_lock(&hi->sbp2_command_lock, flags); - - /* - * Ok, we've discovered and re-validated all SBP-2 devices out there. Let's remove structures of all - * devices not re-validated (meaning they've been removed). - */ - sbp2_remove_unvalidated_devices(hi); - - /* - * Complete any pending commands with busy (so they get retried) and remove them from our queue - */ - for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) { - if (hi->scsi_id[i]) { - sbp2scsi_complete_all_commands(hi, hi->scsi_id[i], DID_BUS_BUSY); - } + if (scsi_id->login_orb) { + pci_free_consistent(hi->host->pdev, + sizeof(struct sbp2_login_orb), + scsi_id->login_orb, + scsi_id->login_orb_dma); + SBP2_DMA_FREE("single login ORB"); } - /* - * Now, note that the bus reset is complete (finally!) - */ - hi->bus_reset_in_progress = 0; - - /* - * Deal with the initial scsi bus scan if needed (since we only now know if there are - * any sbp2 devices attached) - */ - if (!no_bus_scan && !hi->initial_scsi_bus_scan_complete && hi->bus_scan_SCpnt) { - - hi->initial_scsi_bus_scan_complete = 1; - scsi_id = hi->scsi_id[hi->bus_scan_SCpnt->target]; - - /* - * If the sbp2 device exists, then let's now execute the command. - * If not, then just complete it as a selection time-out. - */ - if (scsi_id) { - if (sbp2_send_command(hi, scsi_id, hi->bus_scan_SCpnt, hi->bus_scan_done)) { - SBP2_ERR("sbp2: Error sending SCSI command"); - sbp2scsi_complete_command(hi, scsi_id, SBP2_SCSI_STATUS_SELECTION_TIMEOUT, - hi->bus_scan_SCpnt, hi->bus_scan_done); - } - } else { - void (*done)(Scsi_Cmnd *) = hi->bus_scan_done; - hi->bus_scan_SCpnt->result = DID_NO_CONNECT << 16; - done (hi->bus_scan_SCpnt); - } + if (scsi_id->reconnect_orb) { + pci_free_consistent(hi->host->pdev, + sizeof(struct sbp2_reconnect_orb), + scsi_id->reconnect_orb, + scsi_id->reconnect_orb_dma); + SBP2_DMA_FREE("single reconnect orb"); } - sbp2_spin_unlock(&hi->sbp2_command_lock, flags); - - return; -} - - -/* - * This is called from the host's bh when a bus reset is complete. We wake up our detection thread - * to deal with the reset - */ -static void sbp2_host_reset(struct hpsb_host *host) -{ - unsigned long flags; - struct sbp2scsi_host_info *hi; - int i; - - SBP2_INFO("sbp2: IEEE-1394 bus reset"); - sbp2_spin_lock(&sbp2_host_info_lock, flags); - hi = sbp2_find_host_info(host); - - if (hi != NULL) { - - /* - * Wake up our detection thread, only if it's not already handling a reset - */ - if (!hi->bus_reset_in_progress) { - - /* - * First thing to do. Invalidate all SBP-2 devices. This is needed so that - * we stop sending down I/O requests to the device, and also so that we can - * figure out which devices have disappeared after a bus reset. - */ - for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) { - if (hi->scsi_id[i]) { - hi->scsi_id[i]->validated = 0; - } - } - - hi->bus_reset_in_progress = 1; - - wake_up(&hi->sbp2_detection_wait); - } + if (scsi_id->logout_orb) { + pci_free_consistent(hi->host->pdev, + sizeof(struct sbp2_logout_orb), + scsi_id->logout_orb, + scsi_id->reconnect_orb_dma); + SBP2_DMA_FREE("single logout orb"); } - sbp2_spin_unlock(&sbp2_host_info_lock, flags); - return; -} - -/* XXX: How best to handle these with DMA interface? */ - -#if 0 -/* - * This function deals with physical dma write requests (for adapters that do not support - * physical dma in hardware). - */ -static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, quadlet_t *data, - u64 addr, unsigned int length) -{ - /* - * Manually put the data in the right place. - */ - memcpy(bus_to_virt((u32)addr), data, length); - return(RCODE_COMPLETE); + SBP2_DEBUG("sbp2: Unvalidated SBP-2 device removed, SCSI ID = %d", + scsi_id->id); + hi->scsi_id[scsi_id->id] = NULL; + kfree(scsi_id); } -/* - * This function deals with physical dma read requests (for adapters that do not support - * physical dma in hardware). - */ -static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data, - u64 addr, unsigned int length) -{ - - /* - * Grab data from memory and send a read response. - */ - memcpy(data, bus_to_virt((u32)addr), length); - return(RCODE_COMPLETE); -} -#endif + /************************************** * SBP-2 protocol related section **************************************/ /* - * This function is called in order to login to a particular SBP-2 device, after a bus reset + * This function is called in order to login to a particular SBP-2 device, + * after a bus reset. */ static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) { @@ -1808,34 +1298,28 @@ static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_insta return(-EIO); } - /* - * Set-up login ORB - */ - scsi_id->login_orb->password_hi = 0; /* Assume no password */ + /* Set-up login ORB, assume no password */ + scsi_id->login_orb->password_hi = 0; scsi_id->login_orb->password_lo = 0; SBP2_DEBUG("sbp2: sbp2_login_device: password_hi/lo initialized"); -#ifdef SBP2_NEED_LOGIN_DESCRIPTOR_WORKAROUND - scsi_id->login_orb->login_response_lo = cpu_to_le32(scsi_id->login_response_dma); - scsi_id->login_orb->login_response_hi = cpu_to_le32(ORB_SET_NODE_ID(hi->host->node_id)); -#else + scsi_id->login_orb->login_response_lo = scsi_id->login_response_dma; scsi_id->login_orb->login_response_hi = ORB_SET_NODE_ID(hi->host->node_id); -#endif SBP2_DEBUG("sbp2: sbp2_login_device: login_response_hi/lo initialized"); + scsi_id->login_orb->lun_misc = ORB_SET_FUNCTION(LOGIN_REQUEST); scsi_id->login_orb->lun_misc |= ORB_SET_RECONNECT(0); /* One second reconnect time */ scsi_id->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(1); /* Exclusive access to device */ scsi_id->login_orb->lun_misc |= ORB_SET_NOTIFY(1); /* Notify us of login complete */ SBP2_DEBUG("sbp2: sbp2_login_device: lun_misc initialized"); - scsi_id->login_orb->passwd_resp_lengths = ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response)); + + scsi_id->login_orb->passwd_resp_lengths = + ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response)); SBP2_DEBUG("sbp2: sbp2_login_device: passwd_resp_lengths initialized"); -#ifdef SBP2_NEED_LOGIN_DESCRIPTOR_WORKAROUND - scsi_id->login_orb->status_FIFO_lo = cpu_to_le32((u32)SBP2_STATUS_FIFO_ADDRESS_LO); - scsi_id->login_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | cpu_to_le16(SBP2_STATUS_FIFO_ADDRESS_HI)); -#else + scsi_id->login_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO; - scsi_id->login_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI); -#endif + scsi_id->login_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | + SBP2_STATUS_FIFO_ADDRESS_HI); SBP2_DEBUG("sbp2: sbp2_login_device: status FIFO initialized"); /* @@ -1861,25 +1345,26 @@ static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_insta sbp2util_cpu_to_be32_buffer(data, 8); SBP2_DEBUG("sbp2: sbp2_login_device: prepared to write"); - - hpsb_write(hi->host, LOCAL_BUS | scsi_id->node_id, scsi_id->sbp2_management_agent_addr, data, 8); + hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_management_agent_addr, data, 8); + SBP2_DEBUG("sbp2: sbp2_login_device: written"); /* - * Wait for login status... but, only if the device has not already logged-in (some devices are fast) + * Wait for login status... but, only if the device has not + * already logged-in (some devices are fast) */ - SBP2_DEBUG("sbp2: sbp2_login_device: written"); save_flags(flags); cli(); - if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) { - interruptible_sleep_on_timeout(&scsi_id->sbp2_login_wait, 10*HZ); /* 10 second timeout */ - } + /* 10 second timeout */ + if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) + sleep_on_timeout(&scsi_id->sbp2_login_wait, 10*HZ); restore_flags(flags); SBP2_DEBUG("sbp2: sbp2_login_device: initial check"); /* - * Match status to the login orb. If they do not match, it's probably because the login timed-out + * Match status to the login orb. If they do not match, it's + * probably because the login timed-out. */ if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) { SBP2_ERR("sbp2: Error logging into SBP-2 device - login timed-out"); @@ -1900,17 +1385,21 @@ static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_insta } /* - * Byte swap the login response, for use when reconnecting or logging out. + * Byte swap the login response, for use when reconnecting or + * logging out. */ sbp2util_cpu_to_be32_buffer(scsi_id->login_response, sizeof(struct sbp2_login_response)); /* - * Grab our command block agent address from the login response + * Grab our command block agent address from the login response. */ - SBP2_DEBUG("sbp2: command_block_agent_hi = %x", (unsigned int)scsi_id->login_response->command_block_agent_hi); - SBP2_DEBUG("sbp2: command_block_agent_lo = %x", (unsigned int)scsi_id->login_response->command_block_agent_lo); + SBP2_DEBUG("sbp2: command_block_agent_hi = %x", + (unsigned int)scsi_id->login_response->command_block_agent_hi); + SBP2_DEBUG("sbp2: command_block_agent_lo = %x", + (unsigned int)scsi_id->login_response->command_block_agent_lo); - scsi_id->sbp2_command_block_agent_addr = ((u64)scsi_id->login_response->command_block_agent_hi) << 32; + scsi_id->sbp2_command_block_agent_addr = + ((u64)scsi_id->login_response->command_block_agent_hi) << 32; scsi_id->sbp2_command_block_agent_addr |= ((u64)scsi_id->login_response->command_block_agent_lo); scsi_id->sbp2_command_block_agent_addr &= 0x0000ffffffffffffULL; @@ -1921,8 +1410,8 @@ static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_insta } /* - * This function is called in order to logout from a particular SBP-2 device, usually called during driver - * unload + * This function is called in order to logout from a particular SBP-2 + * device, usually called during driver unload. */ static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) { @@ -1937,17 +1426,17 @@ static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_inst scsi_id->logout_orb->reserved2 = 0x0; scsi_id->logout_orb->reserved3 = 0x0; scsi_id->logout_orb->reserved4 = 0x0; + scsi_id->logout_orb->login_ID_misc = ORB_SET_FUNCTION(LOGOUT_REQUEST); scsi_id->logout_orb->login_ID_misc |= ORB_SET_LOGIN_ID(scsi_id->login_response->length_login_ID); - scsi_id->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1); /* Notify us when complete */ + + /* Notify us when complete */ + scsi_id->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1); + scsi_id->logout_orb->reserved5 = 0x0; -#ifdef SBP2_NEED_LOGIN_DESCRIPTOR_WORKAROUND - scsi_id->logout_orb->status_FIFO_lo = cpu_to_le32((u32)SBP2_STATUS_FIFO_ADDRESS_LO); - scsi_id->logout_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | cpu_to_le16(SBP2_STATUS_FIFO_ADDRESS_HI)); -#else scsi_id->logout_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO; - scsi_id->logout_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI); -#endif + scsi_id->logout_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | + SBP2_STATUS_FIFO_ADDRESS_HI); /* * Byte swap ORB if necessary @@ -1961,12 +1450,10 @@ static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_inst data[1] = scsi_id->logout_orb_dma; sbp2util_cpu_to_be32_buffer(data, 8); - hpsb_write(hi->host, LOCAL_BUS | scsi_id->node_id, scsi_id->sbp2_management_agent_addr, data, 8); + hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_management_agent_addr, data, 8); - /* - * Wait for device to logout... - */ - interruptible_sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ); /* 1 second timeout */ + /* Wait for device to logout...1 second. */ + sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ); SBP2_INFO("sbp2: Logged out of SBP-2 device"); @@ -1975,7 +1462,8 @@ static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_inst } /* - * This function is called in order to reconnect to a particular SBP-2 device, after a bus reset + * This function is called in order to reconnect to a particular SBP-2 + * device, after a bus reset. */ static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) { @@ -1991,18 +1479,19 @@ static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_i scsi_id->reconnect_orb->reserved2 = 0x0; scsi_id->reconnect_orb->reserved3 = 0x0; scsi_id->reconnect_orb->reserved4 = 0x0; + scsi_id->reconnect_orb->login_ID_misc = ORB_SET_FUNCTION(RECONNECT_REQUEST); - scsi_id->reconnect_orb->login_ID_misc |= ORB_SET_LOGIN_ID(scsi_id->login_response->length_login_ID); - scsi_id->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1); /* Notify us when complete */ + scsi_id->reconnect_orb->login_ID_misc |= + ORB_SET_LOGIN_ID(scsi_id->login_response->length_login_ID); + + /* Notify us when complete */ + scsi_id->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1); + scsi_id->reconnect_orb->reserved5 = 0x0; -#ifdef SBP2_NEED_LOGIN_DESCRIPTOR_WORKAROUND - scsi_id->reconnect_orb->status_FIFO_lo = cpu_to_le32((u32)SBP2_STATUS_FIFO_ADDRESS_LO); - scsi_id->reconnect_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | cpu_to_le16(SBP2_STATUS_FIFO_ADDRESS_HI)); -#else scsi_id->reconnect_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO; - scsi_id->reconnect_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI); -#endif - + scsi_id->reconnect_orb->status_FIFO_hi = + (ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI); + /* * Byte swap ORB if necessary */ @@ -2020,20 +1509,22 @@ static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_i data[1] = scsi_id->reconnect_orb_dma; sbp2util_cpu_to_be32_buffer(data, 8); - hpsb_write(hi->host, LOCAL_BUS | scsi_id->node_id, scsi_id->sbp2_management_agent_addr, data, 8); + hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_management_agent_addr, data, 8); /* - * Wait for reconnect status... but, only if the device has not already reconnected (some devices are fast) + * Wait for reconnect status... but, only if the device has not + * already reconnected (some devices are fast). */ save_flags(flags); cli(); - if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) { - interruptible_sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ); /* one second timeout */ - } + /* One second timout */ + if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) + sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ); restore_flags(flags); /* - * Match status to the reconnect orb. If they do not match, it's probably because the reconnect timed-out + * Match status to the reconnect orb. If they do not match, it's + * probably because the reconnect timed-out. */ if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) { SBP2_ERR("sbp2: Error reconnecting to SBP-2 device - reconnect timed-out"); @@ -2058,7 +1549,8 @@ static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_i } /* - * This function is called in order to set the busy timeout (number of retries to attempt) on the sbp2 device. + * This function is called in order to set the busy timeout (number of + * retries to attempt) on the sbp2 device. */ static int sbp2_set_busy_timeout(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) { @@ -2071,7 +1563,7 @@ static int sbp2_set_busy_timeout(struct sbp2scsi_host_info *hi, struct scsi_id_i */ data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE); - if (hpsb_write(hi->host, LOCAL_BUS | scsi_id->node_id, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) { + if (hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) { SBP2_ERR("sbp2: sbp2_set_busy_timeout error"); } @@ -2079,158 +1571,100 @@ static int sbp2_set_busy_timeout(struct sbp2scsi_host_info *hi, struct scsi_id_i } /* - * This function is called to parse sbp2 device's config rom unit directory. Used to determine - * things like sbp2 management agent offset, and command set used (SCSI or RBC). + * This function is called to parse sbp2 device's config rom unit + * directory. Used to determine things like sbp2 management agent offset, + * and command set used (SCSI or RBC). */ -static int sbp2_parse_unit_directory(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) +static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id) { - quadlet_t unit_directory_length, unit_directory_data; - u64 unit_directory_addr; - u32 i; + struct unit_directory *ud; + int i; SBP2_DEBUG("sbp2: sbp2_parse_unit_directory"); - if (sbp2util_unit_directory(hi, LOCAL_BUS | scsi_id->node_id, &unit_directory_addr)) { - SBP2_DEBUG("sbp2: Error reading unit directory address - bad status"); - return(-EIO); - } - - /* - * Read the size of the unit directory - */ - if (sbp2util_read_quadlet(hi, LOCAL_BUS | scsi_id->node_id, unit_directory_addr, - &unit_directory_length)) { - SBP2_DEBUG("sbp2: Error reading unit directory length - bad status"); - return(-EIO); - } - - unit_directory_length = ((be32_to_cpu(unit_directory_length)) >> 16); - - /* - * Now, sweep through the unit directory looking for the management agent offset - * Give up if we hit any error or somehow miss it... - */ - for (i=0; i<unit_directory_length; i++) { - - if (sbp2util_read_quadlet(hi, LOCAL_BUS | scsi_id->node_id, unit_directory_addr + (i<<2) + 4, - &unit_directory_data)) { - SBP2_DEBUG("sbp2: Error reading unit directory - bad status"); - return(-EIO); - } - - /* - * Handle different fields in the unit directory, based on keys - */ - unit_directory_data = be32_to_cpu(unit_directory_data); - switch (unit_directory_data >> 24) { - - case SBP2_CSR_OFFSET_KEY: - - /* - * Save off the management agent address - */ - scsi_id->sbp2_management_agent_addr = CONFIG_ROM_INITIAL_MEMORY_SPACE + - ((unit_directory_data & 0x00ffffff) << 2); - - SBP2_DEBUG("sbp2: sbp2_management_agent_addr = %x", (unsigned int) scsi_id->sbp2_management_agent_addr); - break; - - case SBP2_COMMAND_SET_SPEC_ID_KEY: - - /* - * Command spec organization - */ - scsi_id->sbp2_command_set_spec_id = unit_directory_data & 0xffffff; - SBP2_DEBUG("sbp2: sbp2_command_set_spec_id = %x", (unsigned int) scsi_id->sbp2_command_set_spec_id); - break; - - case SBP2_COMMAND_SET_KEY: + ud = scsi_id->ud; - /* - * Command set used by sbp2 device - */ - scsi_id->sbp2_command_set = unit_directory_data & 0xffffff; - SBP2_DEBUG("sbp2: sbp2_command_set = %x", (unsigned int) scsi_id->sbp2_command_set); - break; + /* Handle different fields in the unit directory, based on keys */ + for (i = 0; i < ud->arb_count; i++) { + switch (ud->arb_keys[i]) { + case SBP2_CSR_OFFSET_KEY: + /* Save off the management agent address */ + scsi_id->sbp2_management_agent_addr = + CONFIG_ROM_INITIAL_MEMORY_SPACE + + (ud->arb_values[i] << 2); - case SBP2_UNIT_CHARACTERISTICS_KEY: - - /* - * Unit characterisitcs (orb related stuff that I'm not yet paying attention to) - */ - scsi_id->sbp2_unit_characteristics = unit_directory_data & 0xffffff; - SBP2_DEBUG("sbp2: sbp2_unit_characteristics = %x", (unsigned int) scsi_id->sbp2_unit_characteristics); - break; - - case SBP2_DEVICE_TYPE_AND_LUN_KEY: - - /* - * Device type and lun (used for detemining type of sbp2 device) - */ - scsi_id->sbp2_device_type_and_lun = unit_directory_data & 0xffffff; - SBP2_DEBUG("sbp2: sbp2_device_type_and_lun = %x", (unsigned int) scsi_id->sbp2_device_type_and_lun); - break; - - case SBP2_UNIT_SPEC_ID_KEY: + SBP2_DEBUG("sbp2: sbp2_management_agent_addr = %x", + (unsigned int) scsi_id->sbp2_management_agent_addr); + break; - /* - * Unit spec id (used for protocol detection) - */ - scsi_id->sbp2_unit_spec_id = unit_directory_data & 0xffffff; - SBP2_DEBUG("sbp2: sbp2_unit_spec_id = %x", (unsigned int) scsi_id->sbp2_unit_spec_id); - break; + case SBP2_COMMAND_SET_SPEC_ID_KEY: + /* Command spec organization */ + scsi_id->sbp2_command_set_spec_id = ud->arb_values[i]; + SBP2_DEBUG("sbp2: sbp2_command_set_spec_id = %x", + (unsigned int) scsi_id->sbp2_command_set_spec_id); + break; - case SBP2_UNIT_SW_VERSION_KEY: + case SBP2_COMMAND_SET_KEY: + /* Command set used by sbp2 device */ + scsi_id->sbp2_command_set = ud->arb_values[i]; + SBP2_DEBUG("sbp2: sbp2_command_set = %x", + (unsigned int) scsi_id->sbp2_command_set); + break; - /* - * Unit sw version (used for protocol detection) - */ - scsi_id->sbp2_unit_sw_version = unit_directory_data & 0xffffff; - SBP2_DEBUG("sbp2: sbp2_unit_sw_version = %x", (unsigned int) scsi_id->sbp2_unit_sw_version); - break; + case SBP2_UNIT_CHARACTERISTICS_KEY: + /* + * Unit characterisitcs (orb related stuff + * that I'm not yet paying attention to) + */ + scsi_id->sbp2_unit_characteristics = ud->arb_values[i]; + SBP2_DEBUG("sbp2: sbp2_unit_characteristics = %x", + (unsigned int) scsi_id->sbp2_unit_characteristics); + break; - case SBP2_FIRMWARE_REVISION_KEY: + case SBP2_DEVICE_TYPE_AND_LUN_KEY: + /* + * Device type and lun (used for + * detemining type of sbp2 device) + */ + scsi_id->sbp2_device_type_and_lun = ud->arb_values[i]; + SBP2_DEBUG("sbp2: sbp2_device_type_and_lun = %x", + (unsigned int) scsi_id->sbp2_device_type_and_lun); + break; - /* - * Firmware revision (used to find broken devices). If the vendor id is 0xa0b8 - * (Symbios vendor id), then we have a bridge with 128KB max transfer size limitation. - */ - scsi_id->sbp2_firmware_revision = unit_directory_data & 0xffff00; - if (scsi_id->sbp2_firmware_revision == SBP2_128KB_BROKEN_FIRMWARE) { - SBP2_WARN("sbp2: warning: Bridge chipset supports 128KB max transfer size"); - } - break; + case SBP2_FIRMWARE_REVISION_KEY: + /* + * Firmware revision (used to find broken + * devices). If the vendor id is 0xa0b8 + * (Symbios vendor id), then we have a + * bridge with 128KB max transfer size + * limitation. + */ + scsi_id->sbp2_firmware_revision = ud->arb_values[i]; + if (scsi_id->sbp2_firmware_revision == + SBP2_128KB_BROKEN_FIRMWARE) { + SBP2_WARN("sbp2: warning: Bridge chipset supports 128KB max transfer size"); + } + break; - default: - break; + default: + break; } - } - - return(0); } /* - * This function is called in order to determine the max speed and packet size we can use in our ORBs. + * This function is called in order to determine the max speed and packet + * size we can use in our ORBs. */ static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) { u8 speed_code; - struct node_entry *ne; + unsigned int max_rec; SBP2_DEBUG("sbp2: sbp2_max_speed_and_size"); - /* Get this nodes information */ - ne = hpsb_nodeid_get_entry(hi->host->node_id); - - if (!ne) { - HPSB_ERR("sbp2: Unknown device, using S100, payload 512 bytes"); - scsi_id->speed_code = SPEED_100; - scsi_id->max_payload_size = MAX_PAYLOAD_S100; - return(0); - } - - speed_code = ne->busopt.lnkspd; + speed_code = scsi_id->ne->busopt.lnkspd; + max_rec = scsi_id->ne->busopt.max_rec; /* Bump down our speed if there is a module parameter forcing us slower */ if (speed_code > max_speed) { @@ -2240,11 +1674,11 @@ static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id /* Support the devices max_rec and max speed. We choose a setting * that fits both values, since they may differ. */ - if (speed_code >= SPEED_400 && ne->busopt.max_rec >= MAX_REC_S400) { + if (speed_code >= SPEED_400 && max_rec >= MAX_REC_S400) { HPSB_INFO("sbp2: SBP-2 device max speed S400 and payload 2KB"); scsi_id->speed_code = SPEED_400; scsi_id->max_payload_size = MAX_PAYLOAD_S400; - } else if (speed_code >= SPEED_200 && ne->busopt.max_rec >= MAX_REC_S200) { + } else if (speed_code >= SPEED_200 && max_rec >= MAX_REC_S200) { HPSB_INFO("sbp2: SBP-2 device max speed S200 and payload 1KB"); scsi_id->speed_code = SPEED_200; scsi_id->max_payload_size = MAX_PAYLOAD_S200; @@ -2269,9 +1703,11 @@ static int sbp2_agent_reset(struct sbp2scsi_host_info *hi, struct scsi_id_instan /* * Ok, let's write to the target's management agent register */ - agent_reset_request_packet = sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->node_id, - scsi_id->sbp2_command_block_agent_addr + SBP2_AGENT_RESET_OFFSET, - 0, ntohl(SBP2_AGENT_RESET_DATA)); + agent_reset_request_packet = + sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->ne->nodeid, + scsi_id->sbp2_command_block_agent_addr + + SBP2_AGENT_RESET_OFFSET, + 0, ntohl(SBP2_AGENT_RESET_DATA)); if (!agent_reset_request_packet) { SBP2_ERR("sbp2: sbp2util_allocate_write_request_packet failed"); @@ -2299,8 +1735,8 @@ static int sbp2_agent_reset(struct sbp2scsi_host_info *hi, struct scsi_id_instan } /* - * This function is called to create the actual command orb and s/g list out of the - * scsi command itself. + * This function is called to create the actual command orb and s/g list + * out of the scsi command itself. */ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, @@ -2321,9 +1757,10 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, /* * Set-up our command ORB.. * - * NOTE: We're doing unrestricted page tables (s/g), as this is best performance - * (at least with the devices I have). This means that data_size becomes the number - * of s/g elements, and page_size should be zero (for unrestricted). + * NOTE: We're doing unrestricted page tables (s/g), as this is + * best performance (at least with the devices I have). This means + * that data_size becomes the number of s/g elements, and + * page_size should be zero (for unrestricted). */ command_orb->next_ORB_hi = 0xffffffff; command_orb->next_ORB_lo = 0xffffffff; @@ -2332,8 +1769,8 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, command_orb->misc |= ORB_SET_NOTIFY(1); /* Notify us when complete */ /* - * Set-up our pagetable stuff... unfortunately, this has become messier than I'd like. Need to - * clean this up a bit. ;-) + * Set-up our pagetable stuff... unfortunately, this has become + * messier than I'd like. Need to clean this up a bit. ;-) */ if (sbp2scsi_direction_table[*scsi_cmd] == ORB_DIRECTION_NO_DATA_TRANSFER) { @@ -2405,13 +1842,15 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, } } - command_orb->misc |= ORB_SET_DATA_SIZE(sg_count); /* number of page table (s/g) elements */ + /* Number of page table (s/g) elements */ + command_orb->misc |= ORB_SET_DATA_SIZE(sg_count); /* * Byte swap page tables if necessary */ sbp2util_cpu_to_be32_buffer(scatter_gather_element, - (sizeof(struct sbp2_unrestricted_page_table)) * sg_count); + (sizeof(struct sbp2_unrestricted_page_table)) * + sg_count); } @@ -2427,8 +1866,8 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, SBP2_DMA_ALLOC("single bulk"); /* - * Handle case where we get a command w/o s/g enabled (but check - * for transfers larger than 64K) + * Handle case where we get a command w/o s/g enabled (but + * check for transfers larger than 64K) */ if (scsi_request_bufflen <= SBP2_MAX_SG_ELEMENT_LENGTH) { @@ -2438,7 +1877,8 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]); /* - * Sanity, in case our direction table is not up-to-date + * Sanity, in case our direction table is not + * up-to-date */ if (!scsi_request_bufflen) { command_orb->data_descriptor_hi = 0xffffffff; @@ -2448,15 +1888,19 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, } else { /* - * Need to turn this into page tables, since the buffer is too large. + * Need to turn this into page tables, since the + * buffer is too large. */ command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id); command_orb->data_descriptor_lo = command->sge_dma; - command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1); /* use page tables (s/g) */ + + /* Use page tables (s/g) */ + command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1); command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]); /* - * fill out our sbp-2 page tables (and split up the large buffer) + * fill out our sbp-2 page tables (and split up + * the large buffer) */ sg_count = 0; sg_len = scsi_request_bufflen; @@ -2476,7 +1920,8 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, sg_count++; } - command_orb->misc |= ORB_SET_DATA_SIZE(sg_count); /* number of page table (s/g) elements */ + /* Number of page table (s/g) elements */ + command_orb->misc |= ORB_SET_DATA_SIZE(sg_count); /* * Byte swap page tables if necessary @@ -2524,11 +1969,12 @@ static int sbp2_link_orb_command(struct sbp2scsi_host_info *hi, struct scsi_id_i /* * Ok, let's write to the target's management agent register */ - if (!hi->bus_reset_in_progress) { + if (hpsb_node_entry_valid(scsi_id->ne)) { - command_request_packet = sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->node_id, - scsi_id->sbp2_command_block_agent_addr + SBP2_ORB_POINTER_OFFSET, - 8, 0); + command_request_packet = + sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->ne->nodeid, + scsi_id->sbp2_command_block_agent_addr + + SBP2_ORB_POINTER_OFFSET, 8, 0); if (!command_request_packet) { SBP2_ERR("sbp2: sbp2util_allocate_write_request_packet failed"); @@ -2561,16 +2007,19 @@ static int sbp2_link_orb_command(struct sbp2scsi_host_info *hi, struct scsi_id_i * modifying these next orb pointers, as they are accessed * both by the sbp2 device and us. */ - scsi_id->last_orb->next_ORB_lo = cpu_to_be32(command->command_orb_dma); - scsi_id->last_orb->next_ORB_hi = 0x0; /* Tells hardware that this pointer is valid */ - + scsi_id->last_orb->next_ORB_lo = + cpu_to_be32(command->command_orb_dma); + /* Tells hardware that this pointer is valid */ + scsi_id->last_orb->next_ORB_hi = 0x0; + /* - * Only ring the doorbell if we need to (first parts of linked orbs don't need this) + * Only ring the doorbell if we need to (first parts of + * linked orbs don't need this). */ - if (!command->linked && !hi->bus_reset_in_progress) { + if (!command->linked && hpsb_node_entry_valid(scsi_id->ne)) { command_request_packet = sbp2util_allocate_write_request_packet(hi, - LOCAL_BUS | scsi_id->node_id, + LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_command_block_agent_addr + SBP2_DOORBELL_OFFSET, 0, cpu_to_be32(command->command_orb_dma)); @@ -2610,8 +2059,8 @@ static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_insta SBP2_DEBUG("sbp2: SCSI s/g elements = %x", (unsigned int)SCpnt->use_sg); /* - * Check for broken devices that can't handle greater than 128K transfers, and deal with them in a - * hacked ugly way. + * Check for broken devices that can't handle greater than 128K + * transfers, and deal with them in a hacked ugly way. */ if ((scsi_id->sbp2_firmware_revision == SBP2_128KB_BROKEN_FIRMWARE) && (SCpnt->request_bufflen > SBP2_BROKEN_FIRMWARE_MAX_TRANSFER) && @@ -2620,7 +2069,8 @@ static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_insta (*cmd == 0x28 || *cmd == 0x2a || *cmd == 0x0a || *cmd == 0x08)) { /* - * Darn, a broken device. We'll need to split up the transfer ourselves + * Darn, a broken device. We'll need to split up the + * transfer ourselves. */ sbp2_send_split_command(hi, scsi_id, SCpnt, done); return(0); @@ -2637,13 +2087,12 @@ static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_insta /* * Now actually fill in the comamnd orb and sbp2 s/g list */ - sbp2_create_command_orb(hi, scsi_id, command, cmd, SCpnt->use_sg, - SCpnt->request_bufflen, SCpnt->request_buffer, - scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); - + sbp2_create_command_orb(hi, scsi_id, command, cmd, SCpnt->use_sg, + SCpnt->request_bufflen, SCpnt->request_buffer, + scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); /* - * Update our cdb if necessary (to handle sbp2 RBC command set differences). - * This is where the command set hacks go! =) + * Update our cdb if necessary (to handle sbp2 RBC command set + * differences). This is where the command set hacks go! =) */ if ((device_type == TYPE_DISK) || (device_type == TYPE_SDAD) || @@ -2665,7 +2114,8 @@ static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_insta } /* - * This function is called for broken sbp2 device, where we have to break up large transfers. + * This function is called for broken sbp2 device, where we have to break + * up large transfers. */ static int sbp2_send_split_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) @@ -2779,8 +2229,8 @@ static int sbp2_send_split_command(struct sbp2scsi_host_info *hi, struct scsi_id } /* - * This function deals with command set differences between Linux scsi command set and sbp2 RBC - * command set. + * This function deals with command set differences between Linux scsi + * command set and sbp2 RBC command set. */ static void sbp2_check_sbp2_command(unchar *cmd) { @@ -3001,9 +2451,9 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest */ for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) { if (hi->scsi_id[i]) { - if (hi->scsi_id[i]->node_id == (nodeid & NODE_MASK)) { + if ((hi->scsi_id[i]->ne->nodeid & NODE_MASK) == (nodeid & NODE_MASK)) { scsi_id = hi->scsi_id[i]; - SBP2_DEBUG("sbp2: SBP-2 status write from node %x", scsi_id->node_id); + SBP2_DEBUG("sbp2: SBP-2 status write from node %x", scsi_id->ne->nodeid); break; } } @@ -3089,6 +2539,7 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest return(RCODE_COMPLETE); } + /************************************** * SCSI interface related section @@ -3121,18 +2572,8 @@ static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) scsi_id = hi->scsi_id[SCpnt->target]; /* - * Save off the command if this is the initial bus scan... so that we can - * complete it after we find all our sbp2 devices on the 1394 bus - */ - if (!no_bus_scan && !hi->initial_scsi_bus_scan_complete) { - hi->bus_scan_SCpnt = SCpnt; - hi->bus_scan_done = done; - return(0); - } - - /* - * If scsi_id is null, it means there is no device in this slot, so we should return - * selection timeout. + * If scsi_id is null, it means there is no device in this slot, + * so we should return selection timeout. */ if (!scsi_id) { SCpnt->result = DID_NO_CONNECT << 16; @@ -3141,7 +2582,8 @@ static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) } /* - * Until we handle multiple luns, just return selection time-out to any IO directed at non-zero LUNs + * Until we handle multiple luns, just return selection time-out + * to any IO directed at non-zero LUNs */ if (SCpnt->lun) { SCpnt->result = DID_NO_CONNECT << 16; @@ -3150,7 +2592,8 @@ static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) } /* - * Check for request sense command, and handle it here (autorequest sense) + * Check for request sense command, and handle it here + * (autorequest sense) */ if (SCpnt->cmnd[0] == REQUEST_SENSE) { SBP2_DEBUG("sbp2: REQUEST_SENSE"); @@ -3161,9 +2604,10 @@ static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) } /* - * Check to see if there is a command in progress and just return busy (to be queued later) + * Check to see if there is a command in progress and just return + * busy (to be queued later) */ - if (hi->bus_reset_in_progress) { + if (!hpsb_node_entry_valid(scsi_id->ne)) { SBP2_ERR("sbp2: Bus reset in progress - rejecting command"); SCpnt->result = DID_BUS_BUSY << 16; done (SCpnt); @@ -3184,9 +2628,11 @@ static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) } /* - * This function is called in order to complete all outstanding SBP-2 commands (in case of resets, etc.). + * This function is called in order to complete all outstanding SBP-2 + * commands (in case of resets, etc.). */ -static void sbp2scsi_complete_all_commands(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, +static void sbp2scsi_complete_all_commands(struct sbp2scsi_host_info *hi, + struct scsi_id_instance_data *scsi_id, u32 status) { struct list_head *lh; @@ -3210,7 +2656,7 @@ static void sbp2scsi_complete_all_commands(struct sbp2scsi_host_info *hi, struct } /* - * This function is called in order to complete a regular SBP-2 command. + * This function is called in order to complete a regular SBP-2 command. */ static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 scsi_status, Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) @@ -3226,10 +2672,11 @@ static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi } /* - * If a bus reset is in progress and there was an error, don't complete the command, - * just let it get retried at the end of the bus reset. + * If a bus reset is in progress and there was an error, don't + * complete the command, just let it get retried at the end of the + * bus reset. */ - if ((hi->bus_reset_in_progress) && (scsi_status != SBP2_SCSI_STATUS_GOOD)) { + if (!hpsb_node_entry_valid(scsi_id->ne) && (scsi_status != SBP2_SCSI_STATUS_GOOD)) { SBP2_ERR("sbp2: Bus reset in progress - retry command later"); return; } @@ -3283,9 +2730,10 @@ static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi } /* - * One more quick hack (not enabled by default). Some sbp2 devices do not support - * mode sense. Turn-on this hack to allow the device to pass the sd driver's - * write-protect test (so that you can mount the device rw). + * One more quick hack (not enabled by default). Some sbp2 devices + * do not support mode sense. Turn-on this hack to allow the + * device to pass the sd driver's write-protect test (so that you + * can mount the device rw). */ if (mode_sense_hack && SCpnt->result != DID_OK && SCpnt->cmnd[0] == MODE_SENSE) { SBP2_INFO("sbp2: Returning success to mode sense command"); @@ -3295,17 +2743,18 @@ static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi } /* - * If a bus reset is in progress and there was an error, complete the command - * as busy so that it will get retried. + * If a bus reset is in progress and there was an error, complete + * the command as busy so that it will get retried. */ - if ((hi->bus_reset_in_progress) && (scsi_status != SBP2_SCSI_STATUS_GOOD)) { + if (!hpsb_node_entry_valid(scsi_id->ne) && (scsi_status != SBP2_SCSI_STATUS_GOOD)) { SBP2_ERR("sbp2: Completing command with busy (bus reset)"); SCpnt->result = DID_BUS_BUSY << 16; } /* - * If a unit attention occurs, return busy status so it gets retried... it could have happened because - * of a 1394 bus reset or hot-plug... + * If a unit attention occurs, return busy status so it gets + * retried... it could have happened because of a 1394 bus reset + * or hot-plug... */ if ((scsi_status == SBP2_SCSI_STATUS_CHECK_CONDITION) && (SCpnt->sense_buffer[2] == UNIT_ATTENTION)) { SBP2_INFO("sbp2: UNIT ATTENTION - return busy"); @@ -3321,8 +2770,8 @@ static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi } /* - * Called by scsi stack when something has really gone wrong. - * Usually called when a command has timed-out for some reason. + * Called by scsi stack when something has really gone wrong. Usually + * called when a command has timed-out for some reason. */ static int sbp2scsi_abort (Scsi_Cmnd *SCpnt) { @@ -3336,8 +2785,9 @@ static int sbp2scsi_abort (Scsi_Cmnd *SCpnt) if (scsi_id) { /* - * Right now, just return any matching command structures to the free pool (there may - * be more than one because of broken up/linked commands). + * Right now, just return any matching command structures + * to the free pool (there may be more than one because of + * broken up/linked commands). */ sbp2_spin_lock(&hi->sbp2_command_lock, flags); do { @@ -3445,10 +2895,6 @@ static int sbp2scsi_detect (Scsi_Host_Template *tpnt) global_scsi_tpnt->use_clustering = DISABLE_CLUSTERING; } - if (no_bus_scan) { - SBP2_ERR("sbp2: Initial scsi bus scan deferred (no_bus_scan = 1)"); - } - if (mode_sense_hack) { SBP2_ERR("sbp2: Mode sense emulation enabled (mode_sense_hack = 1)"); } @@ -3457,21 +2903,19 @@ static int sbp2scsi_detect (Scsi_Host_Template *tpnt) if (!sbp2_host_count) { SBP2_ERR("sbp2: Please load the lower level IEEE-1394 driver (e.g. ohci1394) before sbp2..."); - if (sbp2_hl_handle) { - hpsb_unregister_highlevel(sbp2_hl_handle); - sbp2_hl_handle = NULL; - } + sbp2_cleanup(); } /* - * Since we are returning this count, it means that sbp2 must be loaded "after" the - * host adapter module... + * Since we are returning this count, it means that sbp2 must be + * loaded "after" the host adapter module... */ return(sbp2_host_count); } /* - * This function is called from sbp2_add_host, and is where we register our scsi host + * This function is called from sbp2_add_host, and is where we register + * our scsi host */ static void sbp2scsi_register_scsi_host(struct sbp2scsi_host_info *hi) { @@ -3488,7 +2932,8 @@ static void sbp2scsi_register_scsi_host(struct sbp2scsi_host_info *hi) shpnt = scsi_register (global_scsi_tpnt, sizeof(void *)); /* - * If successful, save off a context (to be used when SCSI commands are received) + * If successful, save off a context (to be used when SCSI + * commands are received) */ if (shpnt) { shpnt->hostdata[0] = (unsigned long)hi; diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h index 9df0ecc354b3..c1fc8dd29fe3 100644 --- a/drivers/ieee1394/sbp2.h +++ b/drivers/ieee1394/sbp2.h @@ -36,13 +36,6 @@ #define ORB_DIRECTION_READ_FROM_MEDIA 0x1 #define ORB_DIRECTION_NO_DATA_TRANSFER 0x2 -#define SPEED_S100 0x0 -#define SPEED_S200 0x1 -#define SPEED_S400 0x2 -#define SPEED_S800 0x3 -#define SPEED_S1600 0x4 -#define SPEED_S3200 0x5 - /* 2^(MAX_PAYLOAD+1) = Maximum data transfer length */ #define MAX_PAYLOAD_S100 0x7 #define MAX_PAYLOAD_S200 0x8 @@ -232,8 +225,8 @@ struct sbp2_status_block { * Unit spec id and sw version entry for SBP-2 devices */ -#define SBP2_UNIT_SPEC_ID_ENTRY 0x1200609e -#define SBP2_SW_VERSION_ENTRY 0x13010483 +#define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e +#define SBP2_SW_VERSION_ENTRY 0x00010483 /* * Miscellaneous general config rom related defines @@ -243,11 +236,8 @@ struct sbp2_status_block { #define CONFIG_ROM_BASE_ADDRESS 0xfffff0000400ULL #define CONFIG_ROM_ROOT_DIR_BASE 0xfffff0000414ULL -#define CONFIG_ROM_SIGNATURE_ADDRESS 0xfffff0000404ULL #define CONFIG_ROM_UNIT_DIRECTORY_OFFSET 0xfffff0000424ULL -#define IEEE1394_CONFIG_ROM_SIGNATURE 0x31333934 - #define SBP2_128KB_BROKEN_FIRMWARE 0xa0b800 #define SBP2_BROKEN_FIRMWARE_MAX_TRANSFER 0x20000 @@ -350,6 +340,8 @@ struct sbp2_command_info { * Information needed on a per scsi id basis (one for each sbp2 device) */ struct scsi_id_instance_data { + /* SCSI ID */ + int id; /* * Various sbp2 specific structures @@ -368,18 +360,15 @@ struct scsi_id_instance_data { /* * Stuff we need to know about the sbp2 device itself */ - u64 node_unique_id; u64 sbp2_management_agent_addr; u64 sbp2_command_block_agent_addr; - u32 node_id; u32 speed_code; u32 max_payload_size; /* * Values pulled from the device's unit directory */ - u32 sbp2_unit_spec_id; - u32 sbp2_unit_sw_version; + struct unit_directory *ud; u32 sbp2_command_set_spec_id; u32 sbp2_command_set; u32 sbp2_unit_characteristics; @@ -391,12 +380,6 @@ struct scsi_id_instance_data { */ wait_queue_head_t sbp2_login_wait; - /* - * Flag noting whether the sbp2 device is currently validated (for use during - * bus resets). - */ - u32 validated; - /* * Pool of command orbs, so we can have more than overlapped command per id */ @@ -405,6 +388,8 @@ struct scsi_id_instance_data { struct list_head sbp2_command_orb_completed; u32 sbp2_total_command_orbs; + /* Node entry, as retrieved from NodeMgr entries */ + struct node_entry *ne; }; /* @@ -425,22 +410,6 @@ struct sbp2scsi_host_info { spinlock_t sbp2_request_packet_lock; /* - * Flag indicating if a bus reset (or device detection) is in progress - */ - u32 bus_reset_in_progress; - - /* - * We currently use a kernel thread for dealing with bus resets and sbp2 - * device detection. We use this to wake up the thread when needed. - */ - wait_queue_head_t sbp2_detection_wait; - - /* - * PID of sbp2 detection kernel thread - */ - int sbp2_detection_pid; - - /* * Lists keeping track of inuse/free sbp2_request_packets. These structures are * used for sending out sbp2 command and agent reset packets. We initially create * a pool of request packets so that we don't have to do any kmallocs while in critical @@ -450,13 +419,6 @@ struct sbp2scsi_host_info { struct list_head sbp2_req_free; /* - * Stuff to keep track of the initial scsi bus scan (so that we don't miss it) - */ - u32 initial_scsi_bus_scan_complete; - Scsi_Cmnd *bus_scan_SCpnt; - void (*bus_scan_done)(Scsi_Cmnd *); - - /* * Here is the pool of request packets. All the hpsb packets (for 1394 bus transactions) * are allocated at init and simply re-initialized when needed. */ @@ -476,9 +438,6 @@ struct sbp2scsi_host_info { /* * Various utility prototypes */ -static int sbp2util_read_quadlet(struct sbp2scsi_host_info *hi, nodeid_t node, u64 addr, - quadlet_t *buffer); -static int sbp2util_unit_directory(struct sbp2scsi_host_info *hi, nodeid_t node, u64 *addr); static int sbp2util_create_request_packet_pool(struct sbp2scsi_host_info *hi); static void sbp2util_remove_request_packet_pool(struct sbp2scsi_host_info *hi); static struct sbp2_request_packet *sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi, @@ -500,23 +459,19 @@ static void sbp2util_mark_command_completed(struct scsi_id_instance_data *scsi_i /* * IEEE-1394 core driver related prototypes */ -static void sbp2_remove_unvalidated_devices(struct sbp2scsi_host_info *hi); -static int sbp2_start_device(struct sbp2scsi_host_info *hi, int node_id); -static int sbp2_check_device(struct sbp2scsi_host_info *hi, int node_id); -static void sbp2_bus_reset_handler(void *context); static void sbp2_add_host(struct hpsb_host *host); static struct sbp2scsi_host_info *sbp2_find_host_info(struct hpsb_host *host); static void sbp2_remove_host(struct hpsb_host *host); -static void sbp2_host_reset(struct hpsb_host *host); -static int sbp2_detection_thread(void *__sbp2); int sbp2_init(void); void sbp2_cleanup(void); -#if 0 -static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, quadlet_t *data, - u64 addr, unsigned int length); -static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data, - u64 addr, unsigned int length); -#endif +static int sbp2_probe(struct unit_directory *ud); +static void sbp2_disconnect(struct unit_directory *ud); +static void sbp2_update(struct unit_directory *ud); +static int sbp2_start_device(struct sbp2scsi_host_info *hi, + struct unit_directory *ud); +static void sbp2_remove_device(struct sbp2scsi_host_info *hi, + struct scsi_id_instance_data *scsi_id); + /* * SBP-2 protocol related prototypes */ @@ -543,7 +498,7 @@ static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense static void sbp2_check_sbp2_command(unchar *cmd); static void sbp2_check_sbp2_response(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, Scsi_Cmnd *SCpnt); -static int sbp2_parse_unit_directory(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); +static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id); static int sbp2_set_busy_timeout(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c index 810d6ffb7659..d3df29b05d4c 100644 --- a/drivers/ieee1394/video1394.c +++ b/drivers/ieee1394/video1394.c @@ -103,7 +103,7 @@ struct dma_iso_ctx { int ctxMatch; wait_queue_head_t waitq; spinlock_t lock; - unsigned int syt_offset; + unsigned int syt_offset; int flags; }; @@ -488,24 +488,27 @@ static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags) int i; /* the first descriptor will read only 4 bytes */ - ir_prg[0].control = (0x280C << 16) | 4; + ir_prg[0].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | + DMA_CTL_BRANCH | 4; /* set the sync flag */ if (flags & VIDEO1394_SYNC_FRAMES) - ir_prg[0].control |= 0x00030000; + ir_prg[0].control |= DMA_CTL_WAIT; ir_prg[0].address = kvirt_to_bus(buf); ir_prg[0].branchAddress = (virt_to_bus(&(ir_prg[1].control)) & 0xfffffff0) | 0x1; /* the second descriptor will read PAGE_SIZE-4 bytes */ - ir_prg[1].control = (0x280C << 16) | (PAGE_SIZE-4); + ir_prg[1].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | + DMA_CTL_BRANCH | (PAGE_SIZE-4); ir_prg[1].address = kvirt_to_bus(buf+4); ir_prg[1].branchAddress = (virt_to_bus(&(ir_prg[2].control)) & 0xfffffff0) | 0x1; for (i=2;i<d->nb_cmd-1;i++) { - ir_prg[i].control = (0x280C << 16) | PAGE_SIZE; + ir_prg[i].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | + DMA_CTL_BRANCH | PAGE_SIZE; ir_prg[i].address = kvirt_to_bus(buf+(i-1)*PAGE_SIZE); ir_prg[i].branchAddress = @@ -514,7 +517,8 @@ static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags) } /* the last descriptor will generate an interrupt */ - ir_prg[i].control = (0x283C << 16) | d->left_size; + ir_prg[i].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | + DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size; ir_prg[i].address = kvirt_to_bus(buf+(i-1)*PAGE_SIZE); } @@ -691,13 +695,14 @@ static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag) d->last_used_cmd[n] = d->nb_cmd - 1; for (i=0;i<d->nb_cmd;i++) { - it_prg[i].begin.control = OUTPUT_MORE_IMMEDIATE | 8 ; + it_prg[i].begin.control = DMA_CTL_OUTPUT_MORE | + DMA_CTL_IMMEDIATE | 8 ; it_prg[i].begin.address = 0; it_prg[i].begin.status = 0; it_prg[i].data[0] = - (DMA_SPEED_100 << 16) + (SPEED_100 << 16) | (/* tag */ 1 << 14) | (d->channel << 8) | (TCODE_ISO_DATA << 4); @@ -706,7 +711,7 @@ static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag) it_prg[i].data[2] = 0; it_prg[i].data[3] = 0; - it_prg[i].end.control = 0x100c0000; + it_prg[i].end.control = DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH; it_prg[i].end.address = kvirt_to_bus(buf+i*d->packet_size); @@ -721,7 +726,8 @@ static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag) } else { /* the last prg generates an interrupt */ - it_prg[i].end.control |= 0x08300000 | d->left_size; + it_prg[i].end.control |= DMA_CTL_UPDATE | + DMA_CTL_IRQ | d->left_size; /* the last prg doesn't branch */ it_prg[i].begin.branchAddress = 0; it_prg[i].end.branchAddress = 0; @@ -761,7 +767,7 @@ static void initialize_dma_it_prg_var_packet_queue( size = packet_sizes[i]; } it_prg[i].data[1] = size << 16; - it_prg[i].end.control = 0x100c0000; + it_prg[i].end.control = DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH; if (i < d->nb_cmd-1 && packet_sizes[i+1] != 0) { it_prg[i].end.control |= size; @@ -773,7 +779,8 @@ static void initialize_dma_it_prg_var_packet_queue( & 0xfffffff0) | 0x3; } else { /* the last prg generates an interrupt */ - it_prg[i].end.control |= 0x08300000 | size; + it_prg[i].end.control |= DMA_CTL_UPDATE | + DMA_CTL_IRQ | size; /* the last prg doesn't branch */ it_prg[i].begin.branchAddress = 0; it_prg[i].end.branchAddress = 0; @@ -1560,7 +1567,6 @@ static int video1394_init(struct ti_ohci *ohci) static void remove_card(struct video_card *video) { int i; - unsigned long flags; ohci1394_unregister_video(video->ohci, &video_tmpl); @@ -1581,9 +1587,7 @@ static void remove_card(struct video_card *video) } kfree(video->it_context); } - spin_lock_irqsave(&video1394_cards_lock, flags); list_del(&video->list); - spin_unlock_irqrestore(&video1394_cards_lock, flags); kfree(video); } @@ -1607,7 +1611,7 @@ static void video1394_remove_host (struct hpsb_host *host) p = list_entry(lh, struct video_card, list); if (p ->ohci == ohci) { remove_card(p); - return; + break; } } } diff --git a/drivers/md/md.c b/drivers/md/md.c index 19c30390d089..01bc86ed9aae 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -140,7 +140,7 @@ static MD_LIST_HEAD(all_mddevs); */ dev_mapping_t mddev_map[MAX_MD_DEVS]; -void add_mddev_mapping (mddev_t * mddev, kdev_t dev, void *data) +void add_mddev_mapping(mddev_t * mddev, kdev_t dev, void *data) { unsigned int minor = MINOR(dev); @@ -148,7 +148,7 @@ void add_mddev_mapping (mddev_t * mddev, kdev_t dev, void *data) MD_BUG(); return; } - if (mddev_map[minor].mddev != NULL) { + if (mddev_map[minor].mddev) { MD_BUG(); return; } @@ -156,7 +156,7 @@ void add_mddev_mapping (mddev_t * mddev, kdev_t dev, void *data) mddev_map[minor].data = data; } -void del_mddev_mapping (mddev_t * mddev, kdev_t dev) +void del_mddev_mapping(mddev_t * mddev, kdev_t dev) { unsigned int minor = MINOR(dev); @@ -172,7 +172,7 @@ void del_mddev_mapping (mddev_t * mddev, kdev_t dev) mddev_map[minor].data = NULL; } -static int md_make_request (request_queue_t *q, int rw, struct buffer_head * bh) +static int md_make_request(request_queue_t *q, int rw, struct buffer_head * bh) { mddev_t *mddev = kdev_to_mddev(bh->b_rdev); @@ -184,7 +184,7 @@ static int md_make_request (request_queue_t *q, int rw, struct buffer_head * bh) } } -static mddev_t * alloc_mddev (kdev_t dev) +static mddev_t * alloc_mddev(kdev_t dev) { mddev_t *mddev; @@ -195,7 +195,7 @@ static mddev_t * alloc_mddev (kdev_t dev) mddev = (mddev_t *) kmalloc(sizeof(*mddev), GFP_KERNEL); if (!mddev) return NULL; - + memset(mddev, 0, sizeof(*mddev)); mddev->__minor = MINOR(dev); @@ -245,7 +245,7 @@ mdk_rdev_t * find_rdev(mddev_t * mddev, kdev_t dev) static MD_LIST_HEAD(device_names); -char * partition_name (kdev_t dev) +char * partition_name(kdev_t dev) { struct gendisk *hd; static char nomem [] = "<nomem>"; @@ -282,7 +282,7 @@ char * partition_name (kdev_t dev) return dname->name; } -static unsigned int calc_dev_sboffset (kdev_t dev, mddev_t *mddev, +static unsigned int calc_dev_sboffset(kdev_t dev, mddev_t *mddev, int persistent) { unsigned int size = 0; @@ -294,7 +294,7 @@ static unsigned int calc_dev_sboffset (kdev_t dev, mddev_t *mddev, return size; } -static unsigned int calc_dev_size (kdev_t dev, mddev_t *mddev, int persistent) +static unsigned int calc_dev_size(kdev_t dev, mddev_t *mddev, int persistent) { unsigned int size; @@ -308,7 +308,7 @@ static unsigned int calc_dev_size (kdev_t dev, mddev_t *mddev, int persistent) return size; } -static unsigned int zoned_raid_size (mddev_t *mddev) +static unsigned int zoned_raid_size(mddev_t *mddev) { unsigned int mask; mdk_rdev_t * rdev; @@ -338,7 +338,7 @@ static unsigned int zoned_raid_size (mddev_t *mddev) * provide data have to be able to deal with loss of individual * disks, so they do their checking themselves. */ -int md_check_ordering (mddev_t *mddev) +int md_check_ordering(mddev_t *mddev) { int i, c; mdk_rdev_t *rdev; @@ -349,8 +349,8 @@ int md_check_ordering (mddev_t *mddev) */ ITERATE_RDEV(mddev,rdev,tmp) { if (rdev->faulty) { - printk("md: md%d's device %s faulty, aborting.\n", - mdidx(mddev), partition_name(rdev->dev)); + printk(KERN_ERR "md: md%d's device %s faulty, aborting.\n", + mdidx(mddev), partition_name(rdev->dev)); goto abort; } } @@ -364,7 +364,7 @@ int md_check_ordering (mddev_t *mddev) goto abort; } if (mddev->nb_dev != mddev->sb->raid_disks) { - printk("md: md%d, array needs %d disks, has %d, aborting.\n", + printk(KERN_ERR "md: md%d, array needs %d disks, has %d, aborting.\n", mdidx(mddev), mddev->sb->raid_disks, mddev->nb_dev); goto abort; } @@ -378,13 +378,13 @@ int md_check_ordering (mddev_t *mddev) c++; } if (!c) { - printk("md: md%d, missing disk #%d, aborting.\n", - mdidx(mddev), i); + printk(KERN_ERR "md: md%d, missing disk #%d, aborting.\n", + mdidx(mddev), i); goto abort; } if (c > 1) { - printk("md: md%d, too many disks #%d, aborting.\n", - mdidx(mddev), i); + printk(KERN_ERR "md: md%d, too many disks #%d, aborting.\n", + mdidx(mddev), i); goto abort; } } @@ -393,7 +393,7 @@ abort: return 1; } -static void remove_descriptor (mdp_disk_t *disk, mdp_super_t *sb) +static void remove_descriptor(mdp_disk_t *disk, mdp_super_t *sb) { if (disk_active(disk)) { sb->working_disks--; @@ -426,7 +426,7 @@ static void remove_descriptor (mdp_disk_t *disk, mdp_super_t *sb) #define BAD_CSUM KERN_WARNING \ "md: invalid superblock checksum on %s\n" -static int alloc_array_sb (mddev_t * mddev) +static int alloc_array_sb(mddev_t * mddev) { if (mddev->sb) { MD_BUG(); @@ -440,14 +440,14 @@ static int alloc_array_sb (mddev_t * mddev) return 0; } -static int alloc_disk_sb (mdk_rdev_t * rdev) +static int alloc_disk_sb(mdk_rdev_t * rdev) { if (rdev->sb) MD_BUG(); rdev->sb = (mdp_super_t *) __get_free_page(GFP_KERNEL); if (!rdev->sb) { - printk (OUT_OF_MEM); + printk(OUT_OF_MEM); return -EINVAL; } md_clear_page(rdev->sb); @@ -455,7 +455,7 @@ static int alloc_disk_sb (mdk_rdev_t * rdev) return 0; } -static void free_disk_sb (mdk_rdev_t * rdev) +static void free_disk_sb(mdk_rdev_t * rdev) { if (rdev->sb) { free_page((unsigned long) rdev->sb); @@ -468,7 +468,7 @@ static void free_disk_sb (mdk_rdev_t * rdev) } } -static int read_disk_sb (mdk_rdev_t * rdev) +static int read_disk_sb(mdk_rdev_t * rdev) { int ret = -EINVAL; struct buffer_head *bh = NULL; @@ -479,15 +479,14 @@ static int read_disk_sb (mdk_rdev_t * rdev) if (!rdev->sb) { MD_BUG(); goto abort; - } - + } + /* * Calculate the position of the superblock, * it's at the end of the disk */ sb_offset = calc_dev_sboffset(rdev->dev, rdev->mddev, 1); rdev->sb_offset = sb_offset; - printk("(read) %s's sb offset: %ld", partition_name(dev), sb_offset); fsync_dev(dev); set_blocksize (dev, MD_SB_BYTES); bh = bread (dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); @@ -496,10 +495,10 @@ static int read_disk_sb (mdk_rdev_t * rdev) sb = (mdp_super_t *) bh->b_data; memcpy (rdev->sb, sb, MD_SB_BYTES); } else { - printk (NO_SB,partition_name(rdev->dev)); + printk(NO_SB,partition_name(rdev->dev)); goto abort; } - printk(" [events: %08lx]\n", (unsigned long)rdev->sb->events_lo); + printk(KERN_INFO " [events: %08lx]\n", (unsigned long)rdev->sb->events_lo); ret = 0; abort: if (bh) @@ -507,7 +506,7 @@ abort: return ret; } -static unsigned int calc_sb_csum (mdp_super_t * sb) +static unsigned int calc_sb_csum(mdp_super_t * sb) { unsigned int disk_csum, csum; @@ -522,7 +521,7 @@ static unsigned int calc_sb_csum (mdp_super_t * sb) * Check one RAID superblock for generic plausibility */ -static int check_disk_sb (mdk_rdev_t * rdev) +static int check_disk_sb(mdk_rdev_t * rdev) { mdp_super_t *sb; int ret = -EINVAL; @@ -534,13 +533,12 @@ static int check_disk_sb (mdk_rdev_t * rdev) } if (sb->md_magic != MD_SB_MAGIC) { - printk (BAD_MAGIC, partition_name(rdev->dev)); + printk(BAD_MAGIC, partition_name(rdev->dev)); goto abort; } if (sb->md_minor >= MAX_MD_DEVS) { - printk (BAD_MINOR, partition_name(rdev->dev), - sb->md_minor); + printk(BAD_MINOR, partition_name(rdev->dev), sb->md_minor); goto abort; } @@ -590,7 +588,7 @@ static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2) static MD_LIST_HEAD(all_raid_disks); static MD_LIST_HEAD(pending_raid_disks); -static void bind_rdev_to_array (mdk_rdev_t * rdev, mddev_t * mddev) +static void bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) { mdk_rdev_t *same_pdev; @@ -603,16 +601,16 @@ static void bind_rdev_to_array (mdk_rdev_t * rdev, mddev_t * mddev) printk( KERN_WARNING "md%d: WARNING: %s appears to be on the same physical disk as %s. True\n" " protection against single-disk failure might be compromised.\n", - mdidx(mddev), partition_name(rdev->dev), + mdidx(mddev), partition_name(rdev->dev), partition_name(same_pdev->dev)); - + md_list_add(&rdev->same_set, &mddev->disks); rdev->mddev = mddev; mddev->nb_dev++; - printk("md: bind<%s,%d>\n", partition_name(rdev->dev), mddev->nb_dev); + printk(KERN_INFO "md: bind<%s,%d>\n", partition_name(rdev->dev), mddev->nb_dev); } -static void unbind_rdev_from_array (mdk_rdev_t * rdev) +static void unbind_rdev_from_array(mdk_rdev_t * rdev) { if (!rdev->mddev) { MD_BUG(); @@ -621,7 +619,7 @@ static void unbind_rdev_from_array (mdk_rdev_t * rdev) md_list_del(&rdev->same_set); MD_INIT_LIST_HEAD(&rdev->same_set); rdev->mddev->nb_dev--; - printk("md: unbind<%s,%d>\n", partition_name(rdev->dev), + printk(KERN_INFO "md: unbind<%s,%d>\n", partition_name(rdev->dev), rdev->mddev->nb_dev); rdev->mddev = NULL; } @@ -633,13 +631,13 @@ static void unbind_rdev_from_array (mdk_rdev_t * rdev) * inode is not enough, the SCSI module usage code needs * an explicit open() on the device] */ -static int lock_rdev (mdk_rdev_t *rdev) +static int lock_rdev(mdk_rdev_t *rdev) { int err = 0; struct block_device *bdev; bdev = bdget(rdev->dev); - if (bdev == NULL) + if (!bdev) return -ENOMEM; err = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW); if (!err) @@ -647,7 +645,7 @@ static int lock_rdev (mdk_rdev_t *rdev) return err; } -static void unlock_rdev (mdk_rdev_t *rdev) +static void unlock_rdev(mdk_rdev_t *rdev) { struct block_device *bdev = rdev->bdev; rdev->bdev = NULL; @@ -656,11 +654,11 @@ static void unlock_rdev (mdk_rdev_t *rdev) blkdev_put(bdev, BDEV_RAW); } -void md_autodetect_dev (kdev_t dev); +void md_autodetect_dev(kdev_t dev); -static void export_rdev (mdk_rdev_t * rdev) +static void export_rdev(mdk_rdev_t * rdev) { - printk("md: export_rdev(%s)\n",partition_name(rdev->dev)); + printk(KERN_INFO "md: export_rdev(%s)\n",partition_name(rdev->dev)); if (rdev->mddev) MD_BUG(); unlock_rdev(rdev); @@ -668,7 +666,8 @@ static void export_rdev (mdk_rdev_t * rdev) md_list_del(&rdev->all); MD_INIT_LIST_HEAD(&rdev->all); if (rdev->pending.next != &rdev->pending) { - printk("md: (%s was pending)\n",partition_name(rdev->dev)); + printk(KERN_INFO "md: (%s was pending)\n", + partition_name(rdev->dev)); md_list_del(&rdev->pending); MD_INIT_LIST_HEAD(&rdev->pending); } @@ -680,13 +679,13 @@ static void export_rdev (mdk_rdev_t * rdev) kfree(rdev); } -static void kick_rdev_from_array (mdk_rdev_t * rdev) +static void kick_rdev_from_array(mdk_rdev_t * rdev) { unbind_rdev_from_array(rdev); export_rdev(rdev); } -static void export_array (mddev_t *mddev) +static void export_array(mddev_t *mddev) { struct md_list_head *tmp; mdk_rdev_t *rdev; @@ -708,7 +707,7 @@ static void export_array (mddev_t *mddev) MD_BUG(); } -static void free_mddev (mddev_t *mddev) +static void free_mddev(mddev_t *mddev) { if (!mddev) { MD_BUG(); @@ -751,45 +750,47 @@ static void print_sb(mdp_super_t *sb) { int i; - printk("md: SB: (V:%d.%d.%d) ID:<%08x.%08x.%08x.%08x> CT:%08x\n", + printk(KERN_INFO "md: SB: (V:%d.%d.%d) ID:<%08x.%08x.%08x.%08x> CT:%08x\n", sb->major_version, sb->minor_version, sb->patch_version, sb->set_uuid0, sb->set_uuid1, sb->set_uuid2, sb->set_uuid3, sb->ctime); - printk("md: L%d S%08d ND:%d RD:%d md%d LO:%d CS:%d\n", sb->level, + printk(KERN_INFO "md: L%d S%08d ND:%d RD:%d md%d LO:%d CS:%d\n", sb->level, sb->size, sb->nr_disks, sb->raid_disks, sb->md_minor, sb->layout, sb->chunk_size); - printk("md: UT:%08x ST:%d AD:%d WD:%d FD:%d SD:%d CSUM:%08x E:%08lx\n", + printk(KERN_INFO "md: UT:%08x ST:%d AD:%d WD:%d FD:%d SD:%d CSUM:%08x E:%08lx\n", sb->utime, sb->state, sb->active_disks, sb->working_disks, sb->failed_disks, sb->spare_disks, sb->sb_csum, (unsigned long)sb->events_lo); + printk(KERN_INFO); for (i = 0; i < MD_SB_DISKS; i++) { mdp_disk_t *desc; desc = sb->disks + i; - if (desc->number || desc->major || desc->minor || desc->raid_disk || (desc->state && (desc->state != 4))) { + if (desc->number || desc->major || desc->minor || + desc->raid_disk || (desc->state && (desc->state != 4))) { printk(" D %2d: ", i); print_desc(desc); } } - printk("md: THIS: "); + printk(KERN_INFO "md: THIS: "); print_desc(&sb->this_disk); } static void print_rdev(mdk_rdev_t *rdev) { - printk("md: rdev %s: O:%s, SZ:%08ld F:%d DN:%d ", + printk(KERN_INFO "md: rdev %s: O:%s, SZ:%08ld F:%d DN:%d ", partition_name(rdev->dev), partition_name(rdev->old_dev), rdev->size, rdev->faulty, rdev->desc_nr); if (rdev->sb) { - printk("md: rdev superblock:\n"); + printk(KERN_INFO "md: rdev superblock:\n"); print_sb(rdev->sb); } else - printk("md: no rdev superblock!\n"); + printk(KERN_INFO "md: no rdev superblock!\n"); } -void md_print_devices (void) +void md_print_devices(void) { struct md_list_head *tmp, *tmp2; mdk_rdev_t *rdev; @@ -818,7 +819,7 @@ void md_print_devices (void) printk("\n"); } -static int sb_equal ( mdp_super_t *sb1, mdp_super_t *sb2) +static int sb_equal(mdp_super_t *sb1, mdp_super_t *sb2) { int ret; mdp_super_t *tmp1, *tmp2; @@ -867,7 +868,7 @@ static int uuid_equal(mdk_rdev_t *rdev1, mdk_rdev_t *rdev2) return 0; } -static mdk_rdev_t * find_rdev_all (kdev_t dev) +static mdk_rdev_t * find_rdev_all(kdev_t dev) { struct md_list_head *tmp; mdk_rdev_t *rdev; @@ -908,8 +909,8 @@ static int write_disk_sb(mdk_rdev_t * rdev) dev = rdev->dev; sb_offset = calc_dev_sboffset(dev, rdev->mddev, 1); if (rdev->sb_offset != sb_offset) { - printk("%s's sb offset has changed from %ld to %ld, skipping\n", - partition_name(dev), rdev->sb_offset, sb_offset); + printk(KERN_INFO "%s's sb offset has changed from %ld to %ld, skipping\n", + partition_name(dev), rdev->sb_offset, sb_offset); goto skip; } /* @@ -919,12 +920,12 @@ static int write_disk_sb(mdk_rdev_t * rdev) */ size = calc_dev_size(dev, rdev->mddev, 1); if (size != rdev->size) { - printk("%s's size has changed from %ld to %ld since import, skipping\n", - partition_name(dev), rdev->size, size); + printk(KERN_INFO "%s's size has changed from %ld to %ld since import, skipping\n", + partition_name(dev), rdev->size, size); goto skip; } - printk("(write) %s's sb offset: %ld\n", partition_name(dev), sb_offset); + printk(KERN_INFO "(write) %s's sb offset: %ld\n", partition_name(dev), sb_offset); fsync_dev(dev); set_blocksize(dev, MD_SB_BYTES); bh = getblk(dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); @@ -945,7 +946,7 @@ static int write_disk_sb(mdk_rdev_t * rdev) skip: return 0; } -#undef GETBLK_FAILED +#undef GETBLK_FAILED static void set_this_disk(mddev_t *mddev, mdk_rdev_t *rdev) { @@ -1025,7 +1026,7 @@ repeat: err = 0; ITERATE_RDEV(mddev,rdev,tmp) { - printk("md: "); + printk(KERN_INFO "md: "); if (rdev->faulty) printk("(skipping faulty "); if (rdev->alias_device) @@ -1041,10 +1042,10 @@ repeat: } if (err) { if (--count) { - printk("md: errors occurred during superblock update, repeating\n"); + printk(KERN_ERR "md: errors occurred during superblock update, repeating\n"); goto repeat; } - printk("md: excessive errors occurred during superblock update, exiting\n"); + printk(KERN_ERR "md: excessive errors occurred during superblock update, exiting\n"); } return 0; } @@ -1059,7 +1060,7 @@ repeat: * * a faulty rdev _never_ has rdev->sb set. */ -static int md_import_device (kdev_t newdev, int on_disk) +static int md_import_device(kdev_t newdev, int on_disk) { int err; mdk_rdev_t *rdev; @@ -1070,13 +1071,13 @@ static int md_import_device (kdev_t newdev, int on_disk) rdev = (mdk_rdev_t *) kmalloc(sizeof(*rdev), GFP_KERNEL); if (!rdev) { - printk("md: could not alloc mem for %s!\n", partition_name(newdev)); + printk(KERN_ERR "md: could not alloc mem for %s!\n", partition_name(newdev)); return -ENOMEM; } memset(rdev, 0, sizeof(*rdev)); if (is_mounted(newdev)) { - printk("md: can not import %s, has active inodes!\n", + printk(KERN_WARNING "md: can not import %s, has active inodes!\n", partition_name(newdev)); err = -EBUSY; goto abort_free; @@ -1087,7 +1088,7 @@ static int md_import_device (kdev_t newdev, int on_disk) rdev->dev = newdev; if (lock_rdev(rdev)) { - printk("md: could not lock %s, zero-size? Marking faulty.\n", + printk(KERN_ERR "md: could not lock %s, zero-size? Marking faulty.\n", partition_name(newdev)); err = -EINVAL; goto abort_free; @@ -1099,7 +1100,7 @@ static int md_import_device (kdev_t newdev, int on_disk) if (blk_size[MAJOR(newdev)]) size = blk_size[MAJOR(newdev)][MINOR(newdev)]; if (!size) { - printk("md: %s has zero size, marking faulty!\n", + printk(KERN_WARNING "md: %s has zero size, marking faulty!\n", partition_name(newdev)); err = -EINVAL; goto abort_free; @@ -1107,13 +1108,13 @@ static int md_import_device (kdev_t newdev, int on_disk) if (on_disk) { if ((err = read_disk_sb(rdev))) { - printk("md: could not read %s's sb, not importing!\n", - partition_name(newdev)); + printk(KERN_WARNING "md: could not read %s's sb, not importing!\n", + partition_name(newdev)); goto abort_free; } if ((err = check_disk_sb(rdev))) { - printk("md: %s has invalid sb, not importing!\n", - partition_name(newdev)); + printk(KERN_WARNING "md: %s has invalid sb, not importing!\n", + partition_name(newdev)); goto abort_free; } @@ -1162,7 +1163,7 @@ abort_free: #define UNKNOWN_LEVEL KERN_ERR \ "md: md%d: unsupported raid level %d\n" -static int analyze_sbs (mddev_t * mddev) +static int analyze_sbs(mddev_t * mddev) { int out_of_date = 0, i, first; struct md_list_head *tmp, *tmp2; @@ -1197,7 +1198,7 @@ static int analyze_sbs (mddev_t * mddev) continue; } if (!sb_equal(sb, rdev->sb)) { - printk (INCONSISTENT, partition_name(rdev->dev)); + printk(INCONSISTENT, partition_name(rdev->dev)); kick_rdev_from_array(rdev); continue; } @@ -1227,7 +1228,8 @@ static int analyze_sbs (mddev_t * mddev) rdev->sb->events_hi--; } - printk("md: %s's event counter: %08lx\n", partition_name(rdev->dev), + printk(KERN_INFO "md: %s's event counter: %08lx\n", + partition_name(rdev->dev), (unsigned long)rdev->sb->events_lo); if (!freshest) { freshest = rdev; @@ -1246,7 +1248,7 @@ static int analyze_sbs (mddev_t * mddev) } if (out_of_date) { printk(OUT_OF_DATE); - printk("md: freshest: %s\n", partition_name(freshest->dev)); + printk(KERN_INFO "md: freshest: %s\n", partition_name(freshest->dev)); } memcpy (sb, freshest->sb, sizeof(*sb)); @@ -1265,7 +1267,7 @@ static int analyze_sbs (mddev_t * mddev) ev2 = md_event(sb); ++ev1; if (ev1 < ev2) { - printk("md: kicking non-fresh %s from array!\n", + printk(KERN_WARNING "md: kicking non-fresh %s from array!\n", partition_name(rdev->dev)); kick_rdev_from_array(rdev); continue; @@ -1291,7 +1293,8 @@ static int analyze_sbs (mddev_t * mddev) ((ev1 == ev2) || (ev1 == ev3))) { mdp_disk_t *desc; - printk("md: device name has changed from %s to %s since last import!\n", partition_name(rdev->old_dev), partition_name(rdev->dev)); + printk(KERN_WARNING "md: device name has changed from %s to %s since last import!\n", + partition_name(rdev->old_dev), partition_name(rdev->dev)); if (rdev->desc_nr == -1) { MD_BUG(); goto abort; @@ -1338,7 +1341,7 @@ static int analyze_sbs (mddev_t * mddev) ITERATE_RDEV(mddev,rdev,tmp) { if (rdev->desc_nr != desc->number) continue; - printk("md%d: kicking faulty %s!\n", + printk(KERN_WARNING "md%d: kicking faulty %s!\n", mdidx(mddev),partition_name(rdev->dev)); kick_rdev_from_array(rdev); found = 1; @@ -1347,7 +1350,7 @@ static int analyze_sbs (mddev_t * mddev) if (!found) { if (dev == MKDEV(0,0)) continue; - printk("md%d: removing former faulty %s!\n", + printk(KERN_WARNING "md%d: removing former faulty %s!\n", mdidx(mddev), partition_name(dev)); } remove_descriptor(desc, sb); @@ -1389,7 +1392,8 @@ static int analyze_sbs (mddev_t * mddev) if (found) continue; - printk("md%d: former device %s is unavailable, removing from array!\n", mdidx(mddev), partition_name(dev)); + printk(KERN_WARNING "md%d: former device %s is unavailable, removing from array!\n", + mdidx(mddev), partition_name(dev)); remove_descriptor(desc, sb); } @@ -1436,7 +1440,7 @@ static int analyze_sbs (mddev_t * mddev) first = 0; } } - + /* * Kick all rdevs that are not in the * descriptor array: @@ -1445,7 +1449,7 @@ static int analyze_sbs (mddev_t * mddev) if (rdev->desc_nr == -1) kick_rdev_from_array(rdev); } - + /* * Do a final reality check. */ @@ -1484,14 +1488,14 @@ static int analyze_sbs (mddev_t * mddev) if (sb->major_version != MD_MAJOR_VERSION || sb->minor_version > MD_MINOR_VERSION) { - printk (OLD_VERSION, mdidx(mddev), sb->major_version, + printk(OLD_VERSION, mdidx(mddev), sb->major_version, sb->minor_version, sb->patch_version); goto abort; } if ((sb->state != (1 << MD_SB_CLEAN)) && ((sb->level == 1) || (sb->level == 4) || (sb->level == 5))) - printk (NOT_CLEAN_IGNORE, mdidx(mddev)); + printk(NOT_CLEAN_IGNORE, mdidx(mddev)); return 0; abort: @@ -1503,7 +1507,7 @@ abort: #undef OLD_VERSION #undef OLD_LEVEL -static int device_size_calculation (mddev_t * mddev) +static int device_size_calculation(mddev_t * mddev) { int data_disks = 0, persistent; unsigned int readahead; @@ -1526,7 +1530,7 @@ static int device_size_calculation (mddev_t * mddev) } rdev->size = calc_dev_size(rdev->dev, mddev, persistent); if (rdev->size < sb->chunk_size / 1024) { - printk (KERN_WARNING + printk(KERN_WARNING "md: Dev %s smaller than chunk_size: %ldk < %dk\n", partition_name(rdev->dev), rdev->size, sb->chunk_size / 1024); @@ -1560,7 +1564,7 @@ static int device_size_calculation (mddev_t * mddev) data_disks = sb->raid_disks-1; break; default: - printk (UNKNOWN_LEVEL, mdidx(mddev), sb->level); + printk(UNKNOWN_LEVEL, mdidx(mddev), sb->level); goto abort; } if (!md_size[mdidx(mddev)]) @@ -1599,7 +1603,7 @@ abort: #define BAD_CHUNKSIZE KERN_ERR \ "no chunksize specified, see 'man raidtab'\n" -static int do_md_run (mddev_t * mddev) +static int do_md_run(mddev_t * mddev) { int pnum, err; int chunk_size; @@ -1663,7 +1667,8 @@ static int do_md_run (mddev_t * mddev) } } else if (chunk_size) - printk(KERN_INFO "md: RAID level %d does not need chunksize! Continuing anyway.\n", mddev->sb->level); + printk(KERN_INFO "md: RAID level %d does not need chunksize! Continuing anyway.\n", + mddev->sb->level); if (pnum >= MAX_PERSONALITY) { MD_BUG(); @@ -1700,7 +1705,7 @@ static int do_md_run (mddev_t * mddev) continue; invalidate_device(rdev->dev, 1); if (get_hardsect_size(rdev->dev) - > md_hardsect_sizes[mdidx(mddev)]) + > md_hardsect_sizes[mdidx(mddev)]) md_hardsect_sizes[mdidx(mddev)] = get_hardsect_size(rdev->dev); } @@ -1711,7 +1716,7 @@ static int do_md_run (mddev_t * mddev) err = mddev->pers->run(mddev); if (err) { - printk("md: pers->run() failed ...\n"); + printk(KERN_ERR "md: pers->run() failed ...\n"); mddev->pers = NULL; return -EINVAL; } @@ -1736,7 +1741,7 @@ static int do_md_run (mddev_t * mddev) #define OUT(x) do { err = (x); goto out; } while (0) -static int restart_array (mddev_t *mddev) +static int restart_array(mddev_t *mddev) { int err = 0; @@ -1753,7 +1758,7 @@ static int restart_array (mddev_t *mddev) mddev->ro = 0; set_device_ro(mddev_to_kdev(mddev), 0); - printk (KERN_INFO + printk(KERN_INFO "md: md%d switched to read-write mode.\n", mdidx(mddev)); /* * Kick recovery or resync if necessary @@ -1762,7 +1767,7 @@ static int restart_array (mddev_t *mddev) if (mddev->pers->restart_resync) mddev->pers->restart_resync(mddev); } else { - printk (KERN_ERR "md: md%d has no personality assigned.\n", + printk(KERN_ERR "md: md%d has no personality assigned.\n", mdidx(mddev)); err = -EINVAL; } @@ -1776,15 +1781,15 @@ out: #define STILL_IN_USE \ "md: md%d still in use.\n" -static int do_md_stop (mddev_t * mddev, int ro) +static int do_md_stop(mddev_t * mddev, int ro) { int err = 0, resync_interrupted = 0; kdev_t dev = mddev_to_kdev(mddev); - if (atomic_read(&mddev->active)>1) { - printk(STILL_IN_USE, mdidx(mddev)); - OUT(-EBUSY); - } + if (atomic_read(&mddev->active)>1) { + printk(STILL_IN_USE, mdidx(mddev)); + OUT(-EBUSY); + } if (mddev->pers) { /* @@ -1831,7 +1836,7 @@ static int do_md_stop (mddev_t * mddev, int ro) * interrupted. */ if (!mddev->recovery_running && !resync_interrupted) { - printk("md: marking sb clean...\n"); + printk(KERN_INFO "md: marking sb clean...\n"); mddev->sb->state |= 1 << MD_SB_CLEAN; } md_update_sb(mddev); @@ -1844,12 +1849,11 @@ static int do_md_stop (mddev_t * mddev, int ro) * Free resources if final stop */ if (!ro) { - printk (KERN_INFO "md: md%d stopped.\n", mdidx(mddev)); + printk(KERN_INFO "md: md%d stopped.\n", mdidx(mddev)); free_mddev(mddev); } else - printk (KERN_INFO - "md: md%d switched to read-only mode.\n", mdidx(mddev)); + printk(KERN_INFO "md: md%d switched to read-only mode.\n", mdidx(mddev)); out: return err; } @@ -1859,7 +1863,7 @@ out: /* * We have to safely support old arrays too. */ -int detect_old_array (mdp_super_t *sb) +int detect_old_array(mdp_super_t *sb) { if (sb->major_version > 0) return 0; @@ -1870,7 +1874,7 @@ int detect_old_array (mdp_super_t *sb) } -static void autorun_array (mddev_t *mddev) +static void autorun_array(mddev_t *mddev) { mdk_rdev_t *rdev; struct md_list_head *tmp; @@ -1881,7 +1885,7 @@ static void autorun_array (mddev_t *mddev) return; } - printk("md: running: "); + printk(KERN_INFO "md: running: "); ITERATE_RDEV(mddev,rdev,tmp) { printk("<%s>", partition_name(rdev->dev)); @@ -1890,7 +1894,7 @@ static void autorun_array (mddev_t *mddev) err = do_md_run (mddev); if (err) { - printk("md :do_md_run() returned %d\n", err); + printk(KERN_WARNING "md :do_md_run() returned %d\n", err); /* * prevent the writeback of an unrunnable array */ @@ -1911,7 +1915,7 @@ static void autorun_array (mddev_t *mddev) * * If "unit" is allocated, then bump its reference count */ -static void autorun_devices (kdev_t countdev) +static void autorun_devices(kdev_t countdev) { struct md_list_head candidates; struct md_list_head *tmp; @@ -1920,20 +1924,22 @@ static void autorun_devices (kdev_t countdev) kdev_t md_kdev; - printk("md: autorun ...\n"); + printk(KERN_INFO "md: autorun ...\n"); while (pending_raid_disks.next != &pending_raid_disks) { rdev0 = md_list_entry(pending_raid_disks.next, mdk_rdev_t, pending); - printk("md: considering %s ...\n", partition_name(rdev0->dev)); + printk(KERN_INFO "md: considering %s ...\n", partition_name(rdev0->dev)); MD_INIT_LIST_HEAD(&candidates); ITERATE_RDEV_PENDING(rdev,tmp) { if (uuid_equal(rdev0, rdev)) { if (!sb_equal(rdev0->sb, rdev->sb)) { - printk("md: %s has same UUID as %s, but superblocks differ ...\n", partition_name(rdev->dev), partition_name(rdev0->dev)); + printk(KERN_WARNING + "md: %s has same UUID as %s, but superblocks differ ...\n", + partition_name(rdev->dev), partition_name(rdev0->dev)); continue; } - printk("md: adding %s ...\n", partition_name(rdev->dev)); + printk(KERN_INFO "md: adding %s ...\n", partition_name(rdev->dev)); md_list_del(&rdev->pending); md_list_add(&rdev->pending, &candidates); } @@ -1946,20 +1952,20 @@ static void autorun_devices (kdev_t countdev) md_kdev = MKDEV(MD_MAJOR, rdev0->sb->md_minor); mddev = kdev_to_mddev(md_kdev); if (mddev) { - printk("md: md%d already running, cannot run %s\n", - mdidx(mddev), partition_name(rdev0->dev)); + printk(KERN_WARNING "md: md%d already running, cannot run %s\n", + mdidx(mddev), partition_name(rdev0->dev)); ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) export_rdev(rdev); continue; } mddev = alloc_mddev(md_kdev); - if (mddev == NULL) { - printk("md: cannot allocate memory for md drive.\n"); - break; - } - if (md_kdev == countdev) - atomic_inc(&mddev->active); - printk("md: created md%d\n", mdidx(mddev)); + if (!mddev) { + printk(KERN_ERR "md: cannot allocate memory for md drive.\n"); + break; + } + if (md_kdev == countdev) + atomic_inc(&mddev->active); + printk(KERN_INFO "md: created md%d\n", mdidx(mddev)); ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) { bind_rdev_to_array(rdev, mddev); md_list_del(&rdev->pending); @@ -1967,7 +1973,7 @@ static void autorun_devices (kdev_t countdev) } autorun_array(mddev); } - printk("md: ... autorun DONE.\n"); + printk(KERN_INFO "md: ... autorun DONE.\n"); } /* @@ -2002,14 +2008,14 @@ static void autorun_devices (kdev_t countdev) #define AUTORUNNING KERN_INFO \ "md: auto-running md%d.\n" -static int autostart_array (kdev_t startdev, kdev_t countdev) +static int autostart_array(kdev_t startdev, kdev_t countdev) { int err = -EINVAL, i; mdp_super_t *sb = NULL; mdk_rdev_t *start_rdev = NULL, *rdev; if (md_import_device(startdev, 1)) { - printk("md: could not import %s!\n", partition_name(startdev)); + printk(KERN_WARNING "md: could not import %s!\n", partition_name(startdev)); goto abort; } @@ -2019,7 +2025,7 @@ static int autostart_array (kdev_t startdev, kdev_t countdev) goto abort; } if (start_rdev->faulty) { - printk("md: can not autostart based on faulty %s!\n", + printk(KERN_WARNING "md: can not autostart based on faulty %s!\n", partition_name(startdev)); goto abort; } @@ -2029,7 +2035,9 @@ static int autostart_array (kdev_t startdev, kdev_t countdev) err = detect_old_array(sb); if (err) { - printk("md: array version is too old to be autostarted, use raidtools 0.90 mkraid --upgrade\nto upgrade the array without data loss!\n"); + printk(KERN_WARNING "md: array version is too old to be autostarted ," + "use raidtools 0.90 mkraid --upgrade to upgrade the array " + "without data loss!\n"); goto abort; } @@ -2045,7 +2053,8 @@ static int autostart_array (kdev_t startdev, kdev_t countdev) if (dev == startdev) continue; if (md_import_device(dev, 1)) { - printk("md: could not import %s, trying to run array nevertheless.\n", partition_name(dev)); + printk(KERN_WARNING "md: could not import %s, trying to run array nevertheless.\n", + partition_name(dev)); continue; } rdev = find_rdev_all(dev); @@ -2078,7 +2087,7 @@ abort: #undef AUTORUNNING -static int get_version (void * arg) +static int get_version(void * arg) { mdu_version_t ver; @@ -2093,7 +2102,7 @@ static int get_version (void * arg) } #define SET_FROM_SB(x) info.x = mddev->sb->x -static int get_array_info (mddev_t * mddev, void * arg) +static int get_array_info(mddev_t * mddev, void * arg) { mdu_array_info_t info; @@ -2131,7 +2140,7 @@ static int get_array_info (mddev_t * mddev, void * arg) #undef SET_FROM_SB #define SET_FROM_SB(x) info.x = mddev->sb->disks[nr].x -static int get_disk_info (mddev_t * mddev, void * arg) +static int get_disk_info(mddev_t * mddev, void * arg) { mdu_disk_info_t info; unsigned int nr; @@ -2160,7 +2169,7 @@ static int get_disk_info (mddev_t * mddev, void * arg) #define SET_SB(x) mddev->sb->disks[nr].x = info->x -static int add_new_disk (mddev_t * mddev, mdu_disk_info_t *info) +static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) { int err, size, persistent; mdk_rdev_t *rdev; @@ -2169,15 +2178,15 @@ static int add_new_disk (mddev_t * mddev, mdu_disk_info_t *info) dev = MKDEV(info->major,info->minor); if (find_rdev_all(dev)) { - printk("md: device %s already used in a RAID array!\n", - partition_name(dev)); + printk(KERN_WARNING "md: device %s already used in a RAID array!\n", + partition_name(dev)); return -EBUSY; } if (!mddev->sb) { /* expecting a device which has a superblock */ err = md_import_device(dev, 1); if (err) { - printk("md: md_import_device returned %d\n", err); + printk(KERN_WARNING "md: md_import_device returned %d\n", err); return -EINVAL; } rdev = find_rdev_all(dev); @@ -2189,12 +2198,14 @@ static int add_new_disk (mddev_t * mddev, mdu_disk_info_t *info) mdk_rdev_t *rdev0 = md_list_entry(mddev->disks.next, mdk_rdev_t, same_set); if (!uuid_equal(rdev0, rdev)) { - printk("md: %s has different UUID to %s\n", partition_name(rdev->dev), partition_name(rdev0->dev)); + printk(KERN_WARNING "md: %s has different UUID to %s\n", + partition_name(rdev->dev), partition_name(rdev0->dev)); export_rdev(rdev); return -EINVAL; } if (!sb_equal(rdev0->sb, rdev->sb)) { - printk("md: %s has same UUID but different superblock to %s\n", partition_name(rdev->dev), partition_name(rdev0->dev)); + printk(KERN_WARNING "md: %s has same UUID but different superblock to %s\n", + partition_name(rdev->dev), partition_name(rdev0->dev)); export_rdev(rdev); return -EINVAL; } @@ -2219,7 +2230,7 @@ static int add_new_disk (mddev_t * mddev, mdu_disk_info_t *info) if ((info->state & (1<<MD_DISK_FAULTY))==0) { err = md_import_device (dev, 0); if (err) { - printk("md: error, md_import_device() returned %d\n", err); + printk(KERN_WARNING "md: error, md_import_device() returned %d\n", err); return -EINVAL; } rdev = find_rdev_all(dev); @@ -2235,7 +2246,7 @@ static int add_new_disk (mddev_t * mddev, mdu_disk_info_t *info) persistent = !mddev->sb->not_persistent; if (!persistent) - printk("md: nonpersistent superblock ...\n"); + printk(KERN_INFO "md: nonpersistent superblock ...\n"); size = calc_dev_size(dev, mddev, persistent); rdev->sb_offset = calc_dev_sboffset(dev, mddev, persistent); @@ -2253,24 +2264,24 @@ static int add_new_disk (mddev_t * mddev, mdu_disk_info_t *info) } #undef SET_SB -static int hot_generate_error (mddev_t * mddev, kdev_t dev) +static int hot_generate_error(mddev_t * mddev, kdev_t dev) { struct request_queue *q; mdk_rdev_t *rdev; mdp_disk_t *disk; - + if (!mddev->pers) return -ENODEV; - - printk("md: trying to generate %s error in md%d ... \n", + + printk(KERN_INFO "md: trying to generate %s error in md%d ... \n", partition_name(dev), mdidx(mddev)); - + rdev = find_rdev(mddev, dev); if (!rdev) { MD_BUG(); return -ENXIO; } - + if (rdev->desc_nr == -1) { MD_BUG(); return -EINVAL; @@ -2278,19 +2289,19 @@ static int hot_generate_error (mddev_t * mddev, kdev_t dev) disk = &mddev->sb->disks[rdev->desc_nr]; if (!disk_active(disk)) return -ENODEV; - + q = blk_get_queue(rdev->dev); if (!q) { MD_BUG(); return -ENODEV; } - printk("md: okay, generating error!\n"); + printk(KERN_INFO "md: okay, generating error!\n"); // q->oneshot_error = 1; // disabled for now - + return 0; } -static int hot_remove_disk (mddev_t * mddev, kdev_t dev) +static int hot_remove_disk(mddev_t * mddev, kdev_t dev) { int err; mdk_rdev_t *rdev; @@ -2299,12 +2310,12 @@ static int hot_remove_disk (mddev_t * mddev, kdev_t dev) if (!mddev->pers) return -ENODEV; - printk("md: trying to remove %s from md%d ... \n", + printk(KERN_INFO "md: trying to remove %s from md%d ... \n", partition_name(dev), mdidx(mddev)); if (!mddev->pers->diskop) { - printk("md%d: personality does not support diskops!\n", - mdidx(mddev)); + printk(KERN_WARNING "md%d: personality does not support diskops!\n", + mdidx(mddev)); return -EINVAL; } @@ -2325,7 +2336,7 @@ static int hot_remove_disk (mddev_t * mddev, kdev_t dev) MD_BUG(); return -EINVAL; } - + err = mddev->pers->diskop(mddev, &disk, DISKOP_HOT_REMOVE_DISK); if (err == -EBUSY) { MD_BUG(); @@ -2343,12 +2354,12 @@ static int hot_remove_disk (mddev_t * mddev, kdev_t dev) return 0; busy: - printk("md: cannot remove active disk %s from md%d ... \n", + printk(KERN_WARNING "md: cannot remove active disk %s from md%d ... \n", partition_name(dev), mdidx(mddev)); return -EBUSY; } -static int hot_add_disk (mddev_t * mddev, kdev_t dev) +static int hot_add_disk(mddev_t * mddev, kdev_t dev) { int i, err, persistent; unsigned int size; @@ -2358,12 +2369,12 @@ static int hot_add_disk (mddev_t * mddev, kdev_t dev) if (!mddev->pers) return -ENODEV; - printk("md: trying to hot-add %s to md%d ... \n", + printk(KERN_INFO "md: trying to hot-add %s to md%d ... \n", partition_name(dev), mdidx(mddev)); if (!mddev->pers->diskop) { - printk("md%d: personality does not support diskops!\n", - mdidx(mddev)); + printk(KERN_WARNING "md%d: personality does not support diskops!\n", + mdidx(mddev)); return -EINVAL; } @@ -2371,7 +2382,7 @@ static int hot_add_disk (mddev_t * mddev, kdev_t dev) size = calc_dev_size(dev, mddev, persistent); if (size < mddev->sb->size) { - printk("md%d: disk size %d blocks < array size %d\n", + printk(KERN_WARNING "md%d: disk size %d blocks < array size %d\n", mdidx(mddev), size, mddev->sb->size); return -ENOSPC; } @@ -2382,7 +2393,7 @@ static int hot_add_disk (mddev_t * mddev, kdev_t dev) err = md_import_device (dev, 0); if (err) { - printk("md: error, md_import_device() returned %d\n", err); + printk(KERN_WARNING "md: error, md_import_device() returned %d\n", err); return -EINVAL; } rdev = find_rdev_all(dev); @@ -2391,7 +2402,7 @@ static int hot_add_disk (mddev_t * mddev, kdev_t dev) return -EINVAL; } if (rdev->faulty) { - printk("md: can not hot-add faulty %s disk to md%d!\n", + printk(KERN_WARNING "md: can not hot-add faulty %s disk to md%d!\n", partition_name(dev), mdidx(mddev)); err = -EINVAL; goto abort_export; @@ -2416,7 +2427,8 @@ static int hot_add_disk (mddev_t * mddev, kdev_t dev) break; } if (i == MD_SB_DISKS) { - printk("md%d: can not hot-add to full array!\n", mdidx(mddev)); + printk(KERN_WARNING "md%d: can not hot-add to full array!\n", + mdidx(mddev)); err = -EBUSY; goto abort_unbind_export; } @@ -2470,7 +2482,7 @@ abort_export: } #define SET_SB(x) mddev->sb->x = info->x -static int set_array_info (mddev_t * mddev, mdu_array_info_t *info) +static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) { if (alloc_array_sb(mddev)) @@ -2511,37 +2523,37 @@ static int set_array_info (mddev_t * mddev, mdu_array_info_t *info) } #undef SET_SB -static int set_disk_info (mddev_t * mddev, void * arg) +static int set_disk_info(mddev_t * mddev, void * arg) { - printk("md: not yet"); + printk(KERN_INFO "md: not yet"); return -EINVAL; } -static int clear_array (mddev_t * mddev) +static int clear_array(mddev_t * mddev) { - printk("md: not yet"); + printk(KERN_INFO "md: not yet"); return -EINVAL; } -static int write_raid_info (mddev_t * mddev) +static int write_raid_info(mddev_t * mddev) { - printk("md: not yet"); + printk(KERN_INFO "md: not yet"); return -EINVAL; } -static int protect_array (mddev_t * mddev) +static int protect_array(mddev_t * mddev) { - printk("md: not yet"); + printk(KERN_INFO "md: not yet"); return -EINVAL; } -static int unprotect_array (mddev_t * mddev) +static int unprotect_array(mddev_t * mddev) { - printk("md: not yet"); + printk(KERN_INFO "md: not yet"); return -EINVAL; } -static int set_disk_faulty (mddev_t *mddev, kdev_t dev) +static int set_disk_faulty(mddev_t *mddev, kdev_t dev) { int ret; @@ -2549,7 +2561,7 @@ static int set_disk_faulty (mddev_t *mddev, kdev_t dev) return ret; } -static int md_ioctl (struct inode *inode, struct file *file, +static int md_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { unsigned int minor; @@ -2627,7 +2639,7 @@ static int md_ioctl (struct inode *inode, struct file *file, case SET_ARRAY_INFO: case START_ARRAY: if (mddev) { - printk("md: array md%d already exists!\n", + printk(KERN_WARNING "md: array md%d already exists!\n", mdidx(mddev)); err = -EEXIST; goto abort; @@ -2649,12 +2661,13 @@ static int md_ioctl (struct inode *inode, struct file *file, */ err = lock_mddev(mddev); if (err) { - printk("md: ioctl, reason %d, cmd %d\n", err, cmd); + printk(KERN_WARNING "md: ioctl, reason %d, cmd %d\n", + err, cmd); goto abort; } if (mddev->sb) { - printk("md: array md%d already has a superblock!\n", + printk(KERN_WARNING "md: array md%d already has a superblock!\n", mdidx(mddev)); err = -EBUSY; goto abort_unlock; @@ -2667,7 +2680,7 @@ static int md_ioctl (struct inode *inode, struct file *file, } err = set_array_info(mddev, &info); if (err) { - printk("md: couldnt set array info. %d\n", err); + printk(KERN_WARNING "md: couldnt set array info. %d\n", err); goto abort_unlock; } } @@ -2679,7 +2692,7 @@ static int md_ioctl (struct inode *inode, struct file *file, */ err = autostart_array((kdev_t)arg, dev); if (err) { - printk("md: autostart %s failed!\n", + printk(KERN_WARNING "md: autostart %s failed!\n", partition_name((kdev_t)arg)); goto abort; } @@ -2698,7 +2711,7 @@ static int md_ioctl (struct inode *inode, struct file *file, } err = lock_mddev(mddev); if (err) { - printk("md: ioctl lock interrupted, reason %d, cmd %d\n",err, cmd); + printk(KERN_INFO "md: ioctl lock interrupted, reason %d, cmd %d\n",err, cmd); goto abort; } /* if we don't have a superblock yet, only ADD_NEW_DISK or STOP_ARRAY is allowed */ @@ -2839,7 +2852,9 @@ static int md_ioctl (struct inode *inode, struct file *file, } default: - printk(KERN_WARNING "md: %s(pid %d) used obsolete MD ioctl, upgrade your software to use new ictls.\n", current->comm, current->pid); + printk(KERN_WARNING "md: %s(pid %d) used obsolete MD ioctl, " + "upgrade your software to use new ictls.\n", + current->comm, current->pid); err = -EINVAL; goto abort_unlock; } @@ -2852,12 +2867,12 @@ abort_unlock: return err; done: if (err) - printk("md: huh12?\n"); + MD_BUG(); abort: return err; } -static int md_open (struct inode *inode, struct file *file) +static int md_open(struct inode *inode, struct file *file) { /* * Always succeed, but increment the usage count @@ -2868,7 +2883,7 @@ static int md_open (struct inode *inode, struct file *file) return (0); } -static int md_release (struct inode *inode, struct file * file) +static int md_release(struct inode *inode, struct file * file) { mddev_t *mddev = kdev_to_mddev(inode->i_rdev); if (mddev) @@ -2937,11 +2952,8 @@ int md_thread(void * arg) run(thread->data); run_task_queue(&tq_disk); } - if (md_signal_pending(current)) { - printk("md: %8s(%d) flushing signals.\n", current->comm, - current->pid); + if (md_signal_pending(current)) md_flush_signals(); - } } complete(thread->event); return 0; @@ -2954,22 +2966,22 @@ void md_wakeup_thread(mdk_thread_t *thread) wake_up(&thread->wqueue); } -mdk_thread_t *md_register_thread (void (*run) (void *), +mdk_thread_t *md_register_thread(void (*run) (void *), void *data, const char *name) { mdk_thread_t *thread; int ret; struct completion event; - + thread = (mdk_thread_t *) kmalloc (sizeof(mdk_thread_t), GFP_KERNEL); if (!thread) return NULL; - + memset(thread, 0, sizeof(mdk_thread_t)); md_init_waitqueue_head(&thread->wqueue); - init_completion(&event); + init_completion(&event); thread->event = &event; thread->run = run; thread->data = data; @@ -2983,22 +2995,22 @@ mdk_thread_t *md_register_thread (void (*run) (void *), return thread; } -void md_interrupt_thread (mdk_thread_t *thread) +void md_interrupt_thread(mdk_thread_t *thread) { if (!thread->tsk) { MD_BUG(); return; } - printk("md: interrupting MD-thread pid %d\n", thread->tsk->pid); + dprintk("interrupting MD-thread pid %d\n", thread->tsk->pid); send_sig(SIGKILL, thread->tsk, 1); } -void md_unregister_thread (mdk_thread_t *thread) +void md_unregister_thread(mdk_thread_t *thread) { struct completion event; init_completion(&event); - + thread->event = &event; thread->run = NULL; thread->name = NULL; @@ -3007,7 +3019,7 @@ void md_unregister_thread (mdk_thread_t *thread) kfree(thread); } -void md_recover_arrays (void) +void md_recover_arrays(void) { if (!md_recovery_thread) { MD_BUG(); @@ -3017,12 +3029,15 @@ void md_recover_arrays (void) } -int md_error (mddev_t *mddev, kdev_t rdev) +int md_error(mddev_t *mddev, kdev_t rdev) { mdk_rdev_t * rrdev; -/* printk("md_error dev:(%d:%d), rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",MAJOR(dev),MINOR(dev),MAJOR(rdev),MINOR(rdev), __builtin_return_address(0),__builtin_return_address(1),__builtin_return_address(2),__builtin_return_address(3)); - */ + dprintk("md_error dev:(%d:%d), rdev:(%d:%d), (caller: %p,%p,%p,%p).\n", + MAJOR(dev),MINOR(dev),MAJOR(rdev),MINOR(rdev), + __builtin_return_address(0),__builtin_return_address(1), + __builtin_return_address(2),__builtin_return_address(3)); + if (!mddev) { MD_BUG(); return 0; @@ -3030,7 +3045,7 @@ int md_error (mddev_t *mddev, kdev_t rdev) rrdev = find_rdev(mddev, rdev); if (!rrdev || rrdev->faulty) return 0; - if (mddev->pers->error_handler == NULL + if (!mddev->pers->error_handler || mddev->pers->error_handler(mddev,rdev) <= 0) { free_disk_sb(rrdev); rrdev->faulty = 1; @@ -3048,7 +3063,7 @@ int md_error (mddev_t *mddev, kdev_t rdev) return 0; } -static int status_unused (char * page) +static int status_unused(char * page) { int sz = 0, i = 0; mdk_rdev_t *rdev; @@ -3074,7 +3089,7 @@ static int status_unused (char * page) } -static int status_resync (char * page, mddev_t * mddev) +static int status_resync(char * page, mddev_t * mddev) { int sz = 0; unsigned long max_blocks, resync, res, dt, db, rt; @@ -3084,7 +3099,7 @@ static int status_resync (char * page, mddev_t * mddev) /* * Should not happen. - */ + */ if (!max_blocks) { MD_BUG(); return 0; @@ -3126,7 +3141,7 @@ static int status_resync (char * page, mddev_t * mddev) if (!dt) dt++; db = resync - (mddev->resync_mark_cnt/2); rt = (dt * ((max_blocks-resync) / (db/100+1)))/100; - + sz += sprintf(page + sz, " finish=%lu.%lumin", rt / 60, (rt % 60)/6); sz += sprintf(page + sz, " speed=%ldK/sec", db/dt); @@ -3160,7 +3175,7 @@ static int md_status_read_proc(char *page, char **start, off_t off, sz += sprintf(page + sz, "md%d : %sactive", mdidx(mddev), mddev->pers ? "" : "in"); if (mddev->pers) { - if (mddev->ro) + if (mddev->ro) sz += sprintf(page + sz, " (read-only)"); sz += sprintf(page + sz, " %s", mddev->pers->name); } @@ -3200,12 +3215,12 @@ static int md_status_read_proc(char *page, char **start, off_t off, } sz += sprintf(page + sz, "\n"); } - sz += status_unused (page + sz); + sz += status_unused(page + sz); return sz; } -int register_md_personality (int pnum, mdk_personality_t *p) +int register_md_personality(int pnum, mdk_personality_t *p) { if (pnum >= MAX_PERSONALITY) { MD_BUG(); @@ -3222,7 +3237,7 @@ int register_md_personality (int pnum, mdk_personality_t *p) return 0; } -int unregister_md_personality (int pnum) +int unregister_md_personality(int pnum) { if (pnum >= MAX_PERSONALITY) { MD_BUG(); @@ -3273,7 +3288,7 @@ void md_sync_acct(kdev_t dev, unsigned long nr_sectors) sync_io[major][index] += nr_sectors; } -static int is_mddev_idle (mddev_t *mddev) +static int is_mddev_idle(mddev_t *mddev) { mdk_rdev_t * rdev; struct md_list_head *tmp; @@ -3291,9 +3306,7 @@ static int is_mddev_idle (mddev_t *mddev) curr_events = kstat.dk_drive_rblk[major][idx] + kstat.dk_drive_wblk[major][idx] ; curr_events -= sync_io[major][idx]; -// printk("md: events(major: %d, idx: %d): %ld\n", major, idx, curr_events); if ((curr_events - rdev->last_events) > 32) { -// printk("!I(%ld)%x", curr_events - rdev->last_events, rdev->dev); rdev->last_events = curr_events; idle = 0; } @@ -3321,7 +3334,7 @@ int md_do_sync(mddev_t *mddev, mdp_disk_t *spare) unsigned int max_sectors, currspeed, j, window, err, serialize; unsigned long mark[SYNC_MARKS]; - unsigned long mark_cnt[SYNC_MARKS]; + unsigned long mark_cnt[SYNC_MARKS]; int last_mark,m; struct md_list_head *tmp; unsigned long last_check; @@ -3337,7 +3350,9 @@ recheck: if (mddev2 == mddev) continue; if (mddev2->curr_resync && match_mddev_units(mddev,mddev2)) { - printk(KERN_INFO "md: delaying resync of md%d until md%d has finished resync (they share one or more physical units)\n", mdidx(mddev), mdidx(mddev2)); + printk(KERN_INFO "md: delaying resync of md%d until md%d " + "has finished resync (they share one or more physical units)\n", + mdidx(mddev), mdidx(mddev2)); serialize = 1; break; } @@ -3359,7 +3374,9 @@ recheck: printk(KERN_INFO "md: syncing RAID array md%d\n", mdidx(mddev)); printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed: %d KB/sec/disc.\n", sysctl_speed_limit_min); - printk(KERN_INFO "md: using maximum available idle IO bandwith (but not more than %d KB/sec) for reconstruction.\n", sysctl_speed_limit_max); + printk(KERN_INFO "md: using maximum available idle IO bandwith " + "(but not more than %d KB/sec) for reconstruction.\n", + sysctl_speed_limit_max); /* * Resync has low priority. @@ -3379,7 +3396,8 @@ recheck: * Tune reconstruction: */ window = MAX_READAHEAD*(PAGE_SIZE/512); - printk(KERN_INFO "md: using %dk window, over a total of %d blocks.\n",window/2,max_sectors/2); + printk(KERN_INFO "md: using %dk window, over a total of %d blocks.\n", + window/2,max_sectors/2); atomic_set(&mddev->recovery_active, 0); init_waitqueue_head(&mddev->recovery_wait); @@ -3401,14 +3419,14 @@ recheck: continue; last_check = j; - + run_task_queue(&tq_disk); repeat: if (jiffies >= mark[last_mark] + SYNC_MARK_STEP ) { /* step marks */ int next = (last_mark+1) % SYNC_MARKS; - + mddev->resync_mark = mark[next]; mddev->resync_mark_cnt = mark_cnt[next]; mark[next] = jiffies; @@ -3422,7 +3440,7 @@ recheck: * got a signal, exit. */ mddev->curr_resync = 0; - printk("md: md_do_sync() got signal ... exiting\n"); + printk(KERN_INFO "md: md_do_sync() got signal ... exiting\n"); md_flush_signals(); err = -EINTR; goto out; @@ -3476,7 +3494,7 @@ out_nolock: * of my root partition with the first 0.5 gigs of my /home partition ... so * i'm a bit nervous ;) */ -void md_do_recovery (void *data) +void md_do_recovery(void *data) { int err; mddev_t *mddev; @@ -3495,15 +3513,18 @@ restart: if (sb->active_disks == sb->raid_disks) continue; if (!sb->spare_disks) { - printk(KERN_ERR "md%d: no spare disk to reconstruct array! -- continuing in degraded mode\n", mdidx(mddev)); + printk(KERN_ERR "md%d: no spare disk to reconstruct array! " + "-- continuing in degraded mode\n", mdidx(mddev)); continue; } /* * now here we get the spare and resync it. */ - if ((spare = get_spare(mddev)) == NULL) + spare = get_spare(mddev); + if (!spare) continue; - printk(KERN_INFO "md%d: resyncing spare disk %s to replace failed disk\n", mdidx(mddev), partition_name(MKDEV(spare->major,spare->minor))); + printk(KERN_INFO "md%d: resyncing spare disk %s to replace failed disk\n", + mdidx(mddev), partition_name(MKDEV(spare->major,spare->minor))); if (!mddev->pers->diskop) continue; if (mddev->pers->diskop(mddev, &spare, DISKOP_SPARE_WRITE)) @@ -3512,7 +3533,8 @@ restart: mddev->recovery_running = 1; err = md_do_sync(mddev, spare); if (err == -EIO) { - printk(KERN_INFO "md%d: spare disk %s failed, skipping to next spare.\n", mdidx(mddev), partition_name(MKDEV(spare->major,spare->minor))); + printk(KERN_INFO "md%d: spare disk %s failed, skipping to next spare.\n", + mdidx(mddev), partition_name(MKDEV(spare->major,spare->minor))); if (!disk_faulty(spare)) { mddev->pers->diskop(mddev,&spare,DISKOP_SPARE_INACTIVE); mark_disk_faulty(spare); @@ -3556,7 +3578,7 @@ restart: goto restart; } printk(KERN_INFO "md: recovery thread finished ...\n"); - + } int md_notify_reboot(struct notifier_block *this, @@ -3589,7 +3611,7 @@ struct notifier_block md_notifier = { priority: INT_MAX, /* before any real devices */ }; -static void md_geninit (void) +static void md_geninit(void) { int i; @@ -3611,18 +3633,18 @@ static void md_geninit (void) #endif } -int md__init md_init (void) +int md__init md_init(void) { static char * name = "mdrecoveryd"; int minor; - - printk (KERN_INFO "md: md driver %d.%d.%d MAX_MD_DEVS=%d, MD_SB_DISKS=%d\n", + + printk(KERN_INFO "md: md driver %d.%d.%d MAX_MD_DEVS=%d, MD_SB_DISKS=%d\n", MD_MAJOR_VERSION, MD_MINOR_VERSION, MD_PATCHLEVEL_VERSION, MAX_MD_DEVS, MD_SB_DISKS); if (devfs_register_blkdev (MAJOR_NR, "md", &md_fops)) { - printk (KERN_ALERT "md: Unable to get major %d for md\n", MAJOR_NR); + printk(KERN_ALERT "md: Unable to get major %d for md\n", MAJOR_NR); return (-1); } devfs_handle = devfs_mk_dir (NULL, "md", NULL); @@ -3637,7 +3659,7 @@ int md__init md_init (void) /* forward all md request to md_make_request */ blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), md_make_request); - + read_ahead[MAJOR_NR] = INT_MAX; @@ -3678,14 +3700,14 @@ struct { static int detected_devices[128]; static int dev_cnt; -void md_autodetect_dev (kdev_t dev) +void md_autodetect_dev(kdev_t dev) { if (dev_cnt >= 0 && dev_cnt < 127) detected_devices[dev_cnt++] = dev; } -static void autostart_arrays (void) +static void autostart_arrays(void) { mdk_rdev_t *rdev; int i; @@ -3753,21 +3775,22 @@ static int md__init md_setup(char *str) char *str1 = str; if (get_option(&str, &minor) != 2) { /* MD Number */ - printk("md: Too few arguments supplied to md=.\n"); + printk(KERN_WARNING "md: Too few arguments supplied to md=.\n"); return 0; } if (minor >= MAX_MD_DEVS) { - printk ("md: md=%d, Minor device number too high.\n", minor); + printk(KERN_WARNING "md: md=%d, Minor device number too high.\n", minor); return 0; } else if (md_setup_args.device_names[minor]) { - printk ("md: md=%d, Specified more then once. Replacing previous definition.\n", minor); + printk(KERN_WARNING "md: md=%d, Specified more then once. " + "Replacing previous definition.\n", minor); } switch (get_option(&str, &level)) { /* RAID Personality */ case 2: /* could be 0 or -1.. */ if (level == 0 || level == -1) { if (get_option(&str, &factor) != 2 || /* Chunk Size */ get_option(&str, &fault) != 2) { - printk("md: Too few arguments supplied to md=.\n"); + printk(KERN_WARNING "md: Too few arguments supplied to md=.\n"); return 0; } md_setup_args.pers[minor] = level; @@ -3782,8 +3805,9 @@ static int md__init md_setup(char *str) pername = "raid0"; break; default: - printk ("md: The kernel has not been configured for raid%d" - " support!\n", level); + printk(KERN_WARNING + "md: The kernel has not been configured for raid%d support!\n", + level); return 0; } md_setup_args.pers[minor] = level; @@ -3797,11 +3821,11 @@ static int md__init md_setup(char *str) md_setup_args.pers[minor] = 0; pername="super-block"; } - - printk ("md: Will configure md%d (%s) from %s, below.\n", + + printk(KERN_INFO "md: Will configure md%d (%s) from %s, below.\n", minor, pername, str); md_setup_args.device_names[minor] = str; - + return 1; } @@ -3819,13 +3843,14 @@ void md__init md_setup_drive(void) mdu_disk_info_t dinfo; if ((devname = md_setup_args.device_names[minor]) == 0) continue; - + for (i = 0; i < MD_SB_DISKS && devname != 0; i++) { char *p; void *handle; - - if ((p = strchr(devname, ',')) != NULL) + + p = strchr(devname, ','); + if (p) *p++ = 0; dev = name_to_kdev_t(devname); @@ -3837,29 +3862,31 @@ void md__init md_setup_drive(void) dev = MKDEV(major, minor); } if (dev == 0) { - printk ("md: Unknown device name: %s\n", devname); + printk(KERN_WARNING "md: Unknown device name: %s\n", devname); break; } - + devices[i] = dev; md_setup_args.device_set[minor] = 1; - + devname = p; } devices[i] = 0; - + if (md_setup_args.device_set[minor] == 0) continue; - + if (mddev_map[minor].mddev) { - printk("md: Ignoring md=%d, already autodetected. (Use raid=noautodetect)\n", minor); + printk(KERN_WARNING + "md: Ignoring md=%d, already autodetected. (Use raid=noautodetect)\n", + minor); continue; } - printk("md: Loading md%d: %s\n", minor, md_setup_args.device_names[minor]); - + printk(KERN_INFO "md: Loading md%d: %s\n", minor, md_setup_args.device_names[minor]); + mddev = alloc_mddev(MKDEV(MD_MAJOR,minor)); - if (mddev == NULL) { - printk("md: kmalloc failed - cannot start array %d\n", minor); + if (!mddev) { + printk(KERN_ERR "md: kmalloc failed - cannot start array %d\n", minor); continue; } if (md_setup_args.pers[minor]) { @@ -3905,7 +3932,7 @@ void md__init md_setup_drive(void) if (err) { mddev->sb_dirty = 0; do_md_stop(mddev, 0); - printk("md: starting md%d failed\n", minor); + printk(KERN_WARNING "md: starting md%d failed\n", minor); } } } @@ -3950,7 +3977,7 @@ __initcall(md_run_setup); #else /* It is a MODULE */ -int init_module (void) +int init_module(void) { return md_init(); } @@ -3965,7 +3992,7 @@ static void free_device_names(void) } -void cleanup_module (void) +void cleanup_module(void) { md_unregister_thread(md_recovery_thread); devfs_unregister(devfs_handle); @@ -3984,7 +4011,7 @@ void cleanup_module (void) blk_size[MAJOR_NR] = NULL; max_readahead[MAJOR_NR] = NULL; hardsect_size[MAJOR_NR] = NULL; - + free_device_names(); } diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 68b3035ff289..952c0225e216 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -137,7 +137,7 @@ an MMIO register read. */ #define DRV_NAME "8139too" -#define DRV_VERSION "0.9.18a" +#define DRV_VERSION "0.9.19" #include <linux/config.h> @@ -620,6 +620,7 @@ static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); static struct net_device_stats *rtl8139_get_stats (struct net_device *dev); static inline u32 ether_crc (int length, unsigned char *data); static void rtl8139_set_rx_mode (struct net_device *dev); +static void __set_rx_mode (struct net_device *dev); static void rtl8139_hw_start (struct net_device *dev); #ifdef USE_IO_OPS @@ -962,6 +963,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, dev->do_ioctl = netdev_ioctl; dev->tx_timeout = rtl8139_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; dev->irq = pdev->irq; @@ -1725,18 +1727,21 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) assert (tp->tx_info[entry].mapping == 0); tp->tx_info[entry].skb = skb; - if ((long) skb->data & 3) { /* Must use alignment buffer. */ - /* tp->tx_info[entry].mapping = 0; */ - memcpy (tp->tx_buf[entry], skb->data, skb->len); - dma_addr = tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs); - } else { + if ( !((unsigned long)skb->data & 3) && skb_shinfo(skb)->nr_frags == 0 && + skb->ip_summed != CHECKSUM_HW) { tp->xstats.tx_buf_mapped++; tp->tx_info[entry].mapping = pci_map_single (tp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); dma_addr = tp->tx_info[entry].mapping; - } - + } else if (skb->len < TX_BUF_SIZE) { + skb_copy_and_csum_dev(skb, tp->tx_buf[entry]); + dma_addr = tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs); + } else { + dev_kfree_skb(skb); + tp->tx_info[entry].skb = NULL; + return 0; + } /* Note: the chip doesn't have auto-pad! */ spin_lock_irq(&tp->lock); RTL_W32_F (TxAddr0 + (entry * 4), dma_addr); @@ -1847,8 +1852,8 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev, struct rtl8139_private *tp, void *ioaddr) { u8 tmp8; - int tmp_work = 1000; - + int tmp_work; + DPRINTK ("%s: Ethernet frame had errors, status %8.8x.\n", dev->name, rx_status); if (rx_status & RxTooLong) { @@ -1863,33 +1868,52 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev, tp->stats.rx_length_errors++; if (rx_status & RxCRCErr) tp->stats.rx_crc_errors++; + /* Reset the receiver, based on RealTek recommendation. (Bug?) */ - tp->cur_rx = 0; /* disable receive */ - RTL_W8 (ChipCmd, CmdTxEnb); - - /* A.C.: Reset the multicast list. */ - rtl8139_set_rx_mode (dev); - - /* XXX potentially temporary hack to - * restart hung receiver */ + RTL_W8_F (ChipCmd, CmdTxEnb); + tmp_work = 200; while (--tmp_work > 0) { - barrier(); + udelay(1); + tmp8 = RTL_R8 (ChipCmd); + if (!(tmp8 & CmdRxEnb)) + break; + } + if (tmp_work <= 0) + printk (KERN_WARNING PFX "rx stop wait too long\n"); + /* restart receive */ + tmp_work = 200; + while (--tmp_work > 0) { + RTL_W8_F (ChipCmd, CmdRxEnb | CmdTxEnb); + udelay(1); tmp8 = RTL_R8 (ChipCmd); if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb)) break; - RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); } - - /* G.S.: Re-enable receiver */ - /* XXX temporary hack to work around receiver hang */ - rtl8139_set_rx_mode (dev); - if (tmp_work <= 0) printk (KERN_WARNING PFX "tx/rx enable wait too long\n"); -} + /* and reinitialize all rx related registers */ + RTL_W8_F (Cfg9346, Cfg9346_Unlock); + /* Must enable Tx/Rx before setting transfer thresholds! */ + RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); + + tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys; + RTL_W32 (RxConfig, tp->rx_config); + tp->cur_rx = 0; + + DPRINTK("init buffer addresses\n"); + + /* Lock Config[01234] and BMCR register writes */ + RTL_W8 (Cfg9346, Cfg9346_Lock); + + /* init Rx ring buffer DMA address */ + RTL_W32_F (RxBuf, tp->rx_ring_dma); + + /* A.C.: Reset the multicast list. */ + __set_rx_mode (dev); +} static void rtl8139_rx_interrupt (struct net_device *dev, struct rtl8139_private *tp, void *ioaddr) @@ -2312,11 +2336,10 @@ static inline u32 ether_crc (int length, unsigned char *data) } -static void rtl8139_set_rx_mode (struct net_device *dev) +static void __set_rx_mode (struct net_device *dev) { struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; - unsigned long flags; u32 mc_filter[2]; /* Multicast hash filter */ int i, rx_mode; u32 tmp; @@ -2353,22 +2376,28 @@ static void rtl8139_set_rx_mode (struct net_device *dev) } } - spin_lock_irqsave (&tp->lock, flags); - /* We can safely update without stopping the chip. */ tmp = rtl8139_rx_config | rx_mode; if (tp->rx_config != tmp) { - RTL_W32 (RxConfig, tmp); + RTL_W32_F (RxConfig, tmp); tp->rx_config = tmp; } RTL_W32_F (MAR0 + 0, mc_filter[0]); RTL_W32_F (MAR0 + 4, mc_filter[1]); - spin_unlock_irqrestore (&tp->lock, flags); DPRINTK ("EXIT\n"); } +static void rtl8139_set_rx_mode (struct net_device *dev) +{ + unsigned long flags; + struct rtl8139_private *tp = dev->priv; + + spin_lock_irqsave (&tp->lock, flags); + __set_rx_mode(dev); + spin_unlock_irqrestore (&tp->lock, flags); +} #ifdef CONFIG_PM diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 422894612d64..c73bd6401356 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -65,6 +65,23 @@ * Wake on lan support (Erik Gilling) * MXDMA fixes for serverworks * EEPROM reload + + version 1.0.9 (Manfred Spraul) + * Main change: fix lack of synchronize + netif_close/netif_suspend against a last interrupt + or packet. + * do not enable superflous interrupts (e.g. the + drivers relies on TxDone - TxIntr not needed) + * wait that the hardware has really stopped in close + and suspend. + * workaround for the (at least) gcc-2.95.1 compiler + problem. Also simplifies the code a bit. + * disable_irq() in tx_timeout - needed to protect + against rx interrupts. + * stop the nic before switching into silent rx mode + for wol (required according to docu). + + TODO: * big endian support with CFG:BEM instead of cpu_to_le32 * support for an external PHY @@ -72,8 +89,8 @@ */ #define DRV_NAME "natsemi" -#define DRV_VERSION "1.07+LK1.0.8" -#define DRV_RELDATE "Aug 07, 2001" +#define DRV_VERSION "1.07+LK1.0.9" +#define DRV_RELDATE "Oct 02, 2001" /* Updated to recommendations in pci-skeleton v2.03. */ @@ -345,6 +362,8 @@ enum intr_status_bits { IntrNormalSummary=0x025f, IntrAbnormalSummary=0xCD20, }; +#define DEFAULT_INTR 0x00f1cd65 + /* Bits in the RxMode register. */ enum rx_mode_bits { AcceptErr=0x20, AcceptRunt=0x10, @@ -435,6 +454,7 @@ struct netdev_private { static int eeprom_read(long ioaddr, int location); static int mdio_read(struct net_device *dev, int phy_id, int location); static void natsemi_reset(struct net_device *dev); +static void natsemi_stop_rxtx(struct net_device *dev); static int netdev_open(struct net_device *dev); static void check_link(struct net_device *dev); static void netdev_timer(unsigned long data); @@ -460,6 +480,7 @@ static int netdev_set_sopass(struct net_device *dev, u8 *newval); static int netdev_get_sopass(struct net_device *dev, u8 *data); static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd); static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd); +static void enable_wol_mode(struct net_device *dev, int enable_intr); static int netdev_close(struct net_device *dev); @@ -709,7 +730,26 @@ static void natsemi_reset(struct net_device *dev) } } - +static void natsemi_stop_rxtx(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + int i; + + writel(RxOff | TxOff, ioaddr + ChipCmd); + for(i=0;i< NATSEMI_HW_TIMEOUT;i++) { + if ((readl(ioaddr + ChipCmd) & (TxOn|RxOn)) == 0) + break; + udelay(5); + } + if (i==NATSEMI_HW_TIMEOUT && debug) { + printk(KERN_INFO "%s: Tx/Rx process did not stop in %d usec.\n", + dev->name, i*5); + } else if (debug > 2) { + printk(KERN_DEBUG "%s: Tx/Rx process stopped in %d usec.\n", + dev->name, i*5); + } +} + static int netdev_open(struct net_device *dev) { struct netdev_private *np = dev->priv; @@ -731,7 +771,9 @@ static int netdev_open(struct net_device *dev) return i; } init_ring(dev); + spin_lock_irq(&np->lock); init_registers(dev); + spin_unlock_irq(&np->lock); netif_start_queue(dev); @@ -865,7 +907,7 @@ static void init_registers(struct net_device *dev) __set_rx_mode(dev); /* Enable interrupts by setting the interrupt mask. */ - writel(IntrNormalSummary | IntrAbnormalSummary, ioaddr + IntrMask); + writel(DEFAULT_INTR, ioaddr + IntrMask); writel(1, ioaddr + IntrEnable); writel(RxOn | TxOn, ioaddr + ChipCmd); @@ -892,30 +934,51 @@ static void netdev_timer(unsigned long data) add_timer(&np->timer); } -static void tx_timeout(struct net_device *dev) +static void dump_ring(struct net_device *dev) { struct netdev_private *np = dev->priv; - long ioaddr = dev->base_addr; - printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," - " resetting...\n", dev->name, (int)readl(ioaddr + TxRingPtr)); - - { + if (debug > 2) { int i; - printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring); - for (i = 0; i < RX_RING_SIZE; i++) - printk(" %8.8x", (unsigned int)np->rx_ring[i].cmd_status); - printk("\n"KERN_DEBUG" Tx ring %p: ", np->tx_ring); + printk(KERN_DEBUG " Tx ring at %8.8x:\n", + (int)np->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) - printk(" %4.4x", np->tx_ring[i].cmd_status); - printk("\n"); + printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n", + i, np->tx_ring[i].next_desc, + np->tx_ring[i].cmd_status, np->tx_ring[i].addr); + printk(KERN_DEBUG " Rx ring %8.8x:\n", + (int)np->rx_ring); + for (i = 0; i < RX_RING_SIZE; i++) { + printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n", + i, np->rx_ring[i].next_desc, + np->rx_ring[i].cmd_status, np->rx_ring[i].addr); + } } +} + +static void tx_timeout(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; + + + disable_irq(dev->irq); spin_lock_irq(&np->lock); - natsemi_reset(dev); - drain_ring(dev); - init_ring(dev); - init_registers(dev); + if (netif_device_present(dev)) { + printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," + " resetting...\n", dev->name, readl(ioaddr + IntrStatus)); + dump_ring(dev); + + natsemi_reset(dev); + drain_ring(dev); + init_ring(dev); + init_registers(dev); + } else { + printk(KERN_WARNING "%s: tx_timeout while in suspended state?\n", + dev->name); + } spin_unlock_irq(&np->lock); + enable_irq(dev->irq); dev->trans_start = jiffies; np->stats.tx_errors++; @@ -946,14 +1009,17 @@ static void init_ring(struct net_device *dev) np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); np->rx_head_desc = &np->rx_ring[0]; + /* Please be carefull before changing this loop - at least gcc-2.95.1 + * miscompiles it otherwise. + */ /* Initialize all Rx descriptors. */ for (i = 0; i < RX_RING_SIZE; i++) { - np->rx_ring[i].next_desc = cpu_to_le32(np->ring_dma+sizeof(struct netdev_desc)*(i+1)); + np->rx_ring[i].next_desc = cpu_to_le32(np->ring_dma + +sizeof(struct netdev_desc) + *((i+1)%RX_RING_SIZE)); np->rx_ring[i].cmd_status = cpu_to_le32(DescOwn); np->rx_skbuff[i] = NULL; } - /* Mark the last entry as wrapping the ring. */ - np->rx_ring[i-1].next_desc = cpu_to_le32(np->ring_dma); /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { @@ -965,18 +1031,18 @@ static void init_ring(struct net_device *dev) np->rx_dma[i] = pci_map_single(np->pci_dev, skb->data, skb->len, PCI_DMA_FROMDEVICE); np->rx_ring[i].addr = cpu_to_le32(np->rx_dma[i]); - np->rx_ring[i].cmd_status = cpu_to_le32(DescIntr | np->rx_buf_sz); + np->rx_ring[i].cmd_status = cpu_to_le32(np->rx_buf_sz); } np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); for (i = 0; i < TX_RING_SIZE; i++) { np->tx_skbuff[i] = NULL; np->tx_ring[i].next_desc = cpu_to_le32(np->ring_dma - +sizeof(struct netdev_desc)*(i+1+RX_RING_SIZE)); + +sizeof(struct netdev_desc) + *((i+1)%TX_RING_SIZE+RX_RING_SIZE)); np->tx_ring[i].cmd_status = 0; } - np->tx_ring[i-1].next_desc = cpu_to_le32(np->ring_dma - +sizeof(struct netdev_desc)*(RX_RING_SIZE)); + dump_ring(dev); } static void drain_ring(struct net_device *dev) @@ -1035,25 +1101,25 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) np->tx_ring[entry].addr = cpu_to_le32(np->tx_dma[entry]); spin_lock_irq(&np->lock); - -#if 0 - np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | DescIntr | skb->len); -#else - np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | skb->len); -#endif - /* StrongARM: Explicitly cache flush np->tx_ring and skb->data,skb->len. */ - wmb(); - np->cur_tx++; - if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1) { - netdev_tx_done(dev); - if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1) - netif_stop_queue(dev); + + if (netif_device_present(dev)) { + np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | skb->len); + /* StrongARM: Explicitly cache flush np->tx_ring and skb->data,skb->len. */ + wmb(); + np->cur_tx++; + if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1) { + netdev_tx_done(dev); + if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1) + netif_stop_queue(dev); + } + /* Wake the potentially-idle transmit channel. */ + writel(TxOn, dev->base_addr + ChipCmd); + } else { + dev_kfree_skb_irq(skb); + np->stats.tx_dropped++; } spin_unlock_irq(&np->lock); - /* Wake the potentially-idle transmit channel. */ - writel(TxOn, dev->base_addr + ChipCmd); - dev->trans_start = jiffies; if (debug > 4) { @@ -1115,7 +1181,9 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) ioaddr = dev->base_addr; np = dev->priv; - + + if (!netif_device_present(dev)) + return; do { /* Reading automatically acknowledges all int sources. */ u32 intr_status = readl(ioaddr + IntrStatus); @@ -1239,7 +1307,7 @@ static void netdev_rx(struct net_device *dev) np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]); } np->rx_ring[entry].cmd_status = - cpu_to_le32(DescIntr | np->rx_buf_sz); + cpu_to_le32(np->rx_buf_sz); } /* Restart Rx engine if stopped. */ @@ -1305,11 +1373,13 @@ static struct net_device_stats *get_stats(struct net_device *dev) /* The chip only need report frame silently dropped. */ spin_lock_irq(&np->lock); - __get_stats(dev); + if (netif_running(dev) && netif_device_present(dev)) + __get_stats(dev); spin_unlock_irq(&np->lock); return &np->stats; } + /* The little-endian AUTODIN II ethernet CRC calculations. A big-endian version is also available. This is slow but compact code. Do not use this routine for bulk data, @@ -1408,7 +1478,8 @@ static void set_rx_mode(struct net_device *dev) { struct netdev_private *np = dev->priv; spin_lock_irq(&np->lock); - __set_rx_mode(dev); + if (netif_device_present(dev)) + __set_rx_mode(dev); spin_unlock_irq(&np->lock); } @@ -1718,76 +1789,94 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } } +static void enable_wol_mode(struct net_device *dev, int enable_intr) +{ + long ioaddr = dev->base_addr; + + if (debug > 1) + printk(KERN_INFO "%s: remaining active for wake-on-lan\n", + dev->name); + /* For WOL we must restart the rx process in silent mode. + * Write NULL to the RxRingPtr. Only possible if + * rx process is stopped + */ + writel(0, ioaddr + RxRingPtr); + + /* and restart the rx process */ + writel(RxOn, ioaddr + ChipCmd); + + if (enable_intr) { + /* enable the WOL interrupt. + * Could be used to send a netlink message. + */ + writel(readl(ioaddr + IntrMask) | WOLPkt, ioaddr + IntrMask); + } +} + static int netdev_close(struct net_device *dev) { long ioaddr = dev->base_addr; struct netdev_private *np = dev->priv; - u32 wol = readl(ioaddr + WOLCmd) & WakeOptsSummary; - u32 clkrun; netif_stop_queue(dev); - netif_carrier_off(dev); if (debug > 1) { - printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.", + printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n", dev->name, (int)readl(ioaddr + ChipCmd)); printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); } - /* Only shut down chip if wake on lan is not set */ - if (!wol) { - /* Disable interrupts using the mask. */ - writel(0, ioaddr + IntrMask); - writel(0, ioaddr + IntrEnable); - writel(2, ioaddr + StatsCtrl); /* Freeze Stats */ - - /* Stop the chip's Tx and Rx processes. */ - writel(RxOff | TxOff, ioaddr + ChipCmd); - } else if (debug > 1) { - printk(KERN_INFO "%s: remaining active for wake-on-lan\n", - dev->name); - /* spec says write 0 here */ - writel(0, ioaddr + RxRingPtr); - /* allow wake-event interrupts now */ - writel(readl(ioaddr + IntrMask) | WOLPkt, ioaddr + IntrMask); - } del_timer_sync(&np->timer); -#ifdef __i386__ - if (debug > 2) { - int i; - printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", - (int)np->tx_ring); - for (i = 0; i < TX_RING_SIZE; i++) - printk(" #%d desc. %8.8x %8.8x.\n", - i, np->tx_ring[i].cmd_status, np->tx_ring[i].addr); - printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", - (int)np->rx_ring); - for (i = 0; i < RX_RING_SIZE; i++) { - printk(KERN_DEBUG " #%d desc. %8.8x %8.8x\n", - i, np->rx_ring[i].cmd_status, np->rx_ring[i].addr); - } - } -#endif /* __i386__ debugging only */ + disable_irq(dev->irq); + spin_lock_irq(&np->lock); + + writel(0, ioaddr + IntrEnable); + writel(0, ioaddr + IntrMask); + writel(2, ioaddr + StatsCtrl); /* Freeze Stats */ + + /* Stop the chip's Tx and Rx processes. */ + natsemi_stop_rxtx(dev); + __get_stats(dev); + spin_unlock_irq(&np->lock); + + /* race: shared irq and as most nics the DP83815 + * reports _all_ interrupt conditions in IntrStatus, even + * disabled ones. + * packet received after disable_irq, but before stop_rxtx + * --> race. intr_handler would restart the rx process. + * netif_device_{de,a}tach around {enable,free}_irq. + */ + netif_device_detach(dev); + enable_irq(dev->irq); free_irq(dev->irq, dev); + netif_device_attach(dev); + /* clear the carrier last - an interrupt could reenable it otherwise */ + netif_carrier_off(dev); + + dump_ring(dev); drain_ring(dev); free_ring(dev); - clkrun = np->SavedClkRun; - if (wol) { - /* make sure to enable PME */ - clkrun |= 0x100; - } - - /* Restore PME enable bit */ - writel(np->SavedClkRun, ioaddr + ClkRun); - + { + u32 wol = readl(ioaddr + WOLCmd) & WakeOptsSummary; + u32 clkrun = np->SavedClkRun; + /* Restore PME enable bit */ + if (wol) { + /* restart the NIC in WOL mode. + * The nic must be stopped for this. + */ + enable_wol_mode(dev, 0); + /* make sure to enable PME */ + clkrun |= 0x100; + } + writel(clkrun, ioaddr + ClkRun); #if 0 - writel(0x0200, ioaddr + ChipConfig); /* Power down Xcvr. */ + writel(0x0200, ioaddr + ChipConfig); /* Power down Xcvr. */ #endif - + } return 0; } @@ -1805,49 +1894,71 @@ static void __devexit natsemi_remove1 (struct pci_dev *pdev) #ifdef CONFIG_PM +/* + * suspend/resume synchronization: + * entry points: + * netdev_open, netdev_close, netdev_ioctl, set_rx_mode, intr_handler, + * start_tx, tx_timeout + * Reading from some registers can restart the nic! + * No function accesses the hardware without checking netif_device_present(). + * the check occurs under spin_lock_irq(&np->lock); + * exceptions: + * * netdev_ioctl, netdev_open. + * net/core checks netif_device_present() before calling them. + * * netdev_close: doesn't hurt. + * * netdev_timer: timer stopped by natsemi_suspend. + * * intr_handler: doesn't acquire the spinlock. suspend calls + * disable_irq() to enforce synchronization. + * + * netif_device_detach must occur under spin_unlock_irq(), interrupts from a detached + * device would cause an irq storm. + */ + static int natsemi_suspend (struct pci_dev *pdev, u32 state) { struct net_device *dev = pci_get_drvdata (pdev); struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; - netif_device_detach(dev); - /* no more calls to tx_timeout, hard_start_xmit, set_rx_mode */ rtnl_lock(); - rtnl_unlock(); - /* noone within ->open */ if (netif_running (dev)) { - int i; del_timer_sync(&np->timer); - /* no more link beat timer calls */ + + disable_irq(dev->irq); spin_lock_irq(&np->lock); - writel(RxOff | TxOff, ioaddr + ChipCmd); - for(i=0;i< NATSEMI_HW_TIMEOUT;i++) { - if ((readl(ioaddr + ChipCmd) & (TxOn|RxOn)) == 0) - break; - udelay(5); - } - if (i==NATSEMI_HW_TIMEOUT && debug) { - printk(KERN_INFO "%s: Tx/Rx process did not stop in %d usec.\n", - dev->name, i*5); - } else if (debug > 2) { - printk(KERN_DEBUG "%s: Tx/Rx process stopped in %d usec.\n", - dev->name, i*5); - } - /* Tx and Rx processes stopped */ writel(0, ioaddr + IntrEnable); - /* all irq events disabled. */ - spin_unlock_irq(&np->lock); - - synchronize_irq(); + natsemi_stop_rxtx(dev); + netif_stop_queue(dev); + netif_device_detach(dev); + spin_unlock_irq(&np->lock); + enable_irq(dev->irq); + /* Update the error counts. */ __get_stats(dev); /* pci_power_off(pdev, -1); */ drain_ring(dev); + { + u32 wol = readl(ioaddr + WOLCmd) & WakeOptsSummary; + u32 clkrun = np->SavedClkRun; + /* Restore PME enable bit */ + if (wol) { + /* restart the NIC in WOL mode. + * The nic must be stopped for this. + * FIXME: use the WOL interupt + */ + enable_wol_mode(dev, 0); + /* make sure to enable PME */ + clkrun |= 0x100; + } + writel(clkrun, ioaddr + ClkRun); + } + } else { + netif_device_detach(dev); } + rtnl_unlock(); return 0; } @@ -1857,18 +1968,27 @@ static int natsemi_resume (struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata (pdev); struct netdev_private *np = dev->priv; - if (netif_running (dev)) { + rtnl_lock(); + if (netif_device_present(dev)) + goto out; + if (netif_running(dev)) { pci_enable_device(pdev); /* pci_power_on(pdev); */ natsemi_reset(dev); init_ring(dev); + spin_lock_irq(&np->lock); init_registers(dev); + netif_device_attach(dev); + spin_unlock_irq(&np->lock); np->timer.expires = jiffies + 1*HZ; add_timer(&np->timer); + } else { + netif_device_attach(dev); } - netif_device_attach(dev); +out: + rtnl_unlock(); return 0; } diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c index 3bee3b574fc2..beb1430cc431 100644 --- a/drivers/net/tulip/eeprom.c +++ b/drivers/net/tulip/eeprom.c @@ -148,10 +148,10 @@ subsequent_board: for (i = 0; i < count; i++) { unsigned char media_block = *p++; int media_code = media_block & MEDIA_MASK; - if (media_code & 0x40) + if (media_block & 0x40) p += 6; printk(KERN_INFO "%s: 21041 media #%d, %s.\n", - dev->name, media_code & 15, medianame[media_code & 15]); + dev->name, media_code, medianame[media_code]); } } else { unsigned char *p = (void *)ee_data + ee_data[27]; diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c index 797e1d83281c..053fdc3bdd06 100644 --- a/drivers/net/tulip/interrupt.c +++ b/drivers/net/tulip/interrupt.c @@ -301,7 +301,7 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs) long ioaddr = dev->base_addr; int csr5; int entry; - int missed; + int csr8; int rx = 0; int tx = 0; int oi = 0; @@ -434,7 +434,6 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs) } } if (csr5 & RxDied) { /* Missed a Rx frame. */ - tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; #ifdef CONFIG_NET_HW_FLOWCONTROL if (tp->fc_bit && !test_bit(tp->fc_bit, &netdev_fc_xoff)) { tp->stats.rx_errors++; @@ -548,9 +547,8 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs) } } - if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) { - tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed; - } + csr8 = inl(ioaddr + CSR8); + tp->stats.rx_dropped += (csr8 & 0x1ffff) + ((csr8 >> 17) & 0xfff); if (tulip_debug > 4) printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n", diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index f130784958ff..810ceaad146a 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -15,8 +15,8 @@ */ #define DRV_NAME "tulip" -#define DRV_VERSION "0.9.15-pre6" -#define DRV_RELDATE "July 2, 2001" +#define DRV_VERSION "0.9.15-pre7" +#define DRV_RELDATE "Oct 2, 2001" #include <linux/config.h> #include <linux/module.h> diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 6a90f5b5f1b5..3066566e8199 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -341,6 +341,7 @@ static int do8bitIO = 0; /* The RIDs */ #define RID_CAPABILITIES 0xFF00 +#define RID_RSSI 0xFF04 #define RID_CONFIG 0xFF10 #define RID_SSID 0xFF11 #define RID_APLIST 0xFF12 @@ -627,6 +628,16 @@ typedef struct { u16 atimWindow; } BSSListRid; +typedef struct { + u8 rssipct; + u8 rssidBm; +} tdsRssiEntry; + +typedef struct { + u16 len; + tdsRssiEntry x[256]; +} tdsRssiRid; + #pragma pack() #define TXCTL_TXOK (1<<1) /* report if tx is ok */ @@ -774,6 +785,7 @@ struct airo_info { int whichbap); int (*header_parse)(struct sk_buff*, unsigned char *); unsigned short *flash; + tdsRssiEntry *rssi; #ifdef WIRELESS_EXT int need_commit; // Need to set config struct iw_statistics wstats; // wireless stats @@ -1076,6 +1088,8 @@ void stop_airo_card( struct net_device *dev, int freeres ) struct airo_info *ai = (struct airo_info*)dev->priv; if (ai->flash) kfree(ai->flash); + if (ai->rssi) + kfree(ai->rssi); takedown_proc_entry( dev, ai ); if (ai->registered) { unregister_netdev( dev ); @@ -1382,7 +1396,10 @@ static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) { if (!memcmp(sa,apriv->spy_address[i],6)) { apriv->spy_stat[i].qual = hdr.rssi[0]; - apriv->spy_stat[i].level = hdr.rssi[1]; + if (apriv->rssi) + apriv->spy_stat[i].level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm; + else + apriv->spy_stat[i].level = (hdr.rssi[1] + 321) / 2; apriv->spy_stat[i].noise = 0; apriv->spy_stat[i].updated = 3; break; @@ -1568,9 +1585,29 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, if ( config->len ) { cfg = *config; } else { + tdsRssiRid rssi_rid; + // general configuration (read/modify/write) status = readConfigRid(ai, &cfg); if ( status != SUCCESS ) return ERROR; + + status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid)); + if ( status == SUCCESS ) { + if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL) + memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); + } + else { + CapabilityRid cap_rid; + if (ai->rssi) { + kfree(ai->rssi); + ai->rssi = NULL; + } + status = readCapabilityRid(ai, &cap_rid); + if ((status == SUCCESS) && (cap_rid.softCap & 8)) + cfg.rmode |= RXMODE_NORMALIZED_RSSI; + else + printk(KERN_WARNING "airo: unknown received signal level\n"); + } cfg.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS; /* Save off the MAC */ @@ -3814,7 +3851,7 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) /* Hum... Should put the right values there */ range.max_qual.qual = 10; - range.max_qual.level = 100; + range.max_qual.level = 0; range.max_qual.noise = 0; range.sensitivity = 65535; @@ -3976,7 +4013,10 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) loseSync = 0; memcpy(s[i].sa_data, BSSList.bssid, 6); s[i].sa_family = ARPHRD_ETHER; - qual[i].level = BSSList.rssi; + if (local->rssi) + qual[i].level = 0x100 - local->rssi[BSSList.rssi].rssidBm; + else + qual[i].level = (BSSList.rssi + 321) / 2; qual[i].qual = qual[i].noise = 0; qual[i].updated = 2; if (BSSList.index == 0xffff) break; @@ -4190,7 +4230,10 @@ struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) /* Signal quality and co. But where is the noise level ??? */ local->wstats.qual.qual = status_rid.signalQuality; - local->wstats.qual.level = status_rid.normalizedSignalStrength; + if (local->rssi) + local->wstats.qual.level = 0x100 - local->rssi[status_rid.sigQuality].rssidBm; + else + local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2; local->wstats.qual.noise = 0; local->wstats.qual.updated = 3; diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c index 3c567682930c..17a347777392 100644 --- a/drivers/net/wireless/hermes.c +++ b/drivers/net/wireless/hermes.c @@ -14,8 +14,31 @@ * particular order). * * Copyright (C) 2000, David Gibson, Linuxcare Australia <hermes@gibson.dropbear.id.au> + * Copyright (C) 2001, David Gibson, IBM <hermes@gibson.dropbear.id.au> * - * This file distributed under the GPL, version 2. */ + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> @@ -30,10 +53,10 @@ #include "hermes.h" -static char version[] __initdata = "hermes.c: 1 Aug 2001 David Gibson <hermes@gibson.dropbear.id.au>"; +static char version[] __initdata = "hermes.c: 3 Oct 2001 David Gibson <hermes@gibson.dropbear.id.au>"; MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller"); MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("Dual MPL/GPL"); /* These are maximum timeouts. Most often, card wil react much faster */ #define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */ @@ -42,9 +65,6 @@ MODULE_LICENSE("GPL"); #define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */ #define BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */ -#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) -#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) - /* * Debugging helpers */ @@ -292,7 +312,7 @@ int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid) * from firmware * * Callable from any context */ -static int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset) +int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset) { int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0; int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0; @@ -305,9 +325,14 @@ static int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset) k = BAP_BUSY_TIMEOUT; reg = hermes_read_reg(hw, oreg); + while ((reg & HERMES_OFFSET_BUSY) & k) { + k--; + udelay(1); + reg = hermes_read_reg(hw, oreg); + } if (reg & HERMES_OFFSET_BUSY) - return -EBUSY; + return -ETIMEDOUT; /* Now we actually set up the transfer */ hermes_write_reg(hw, sreg, id); @@ -342,7 +367,7 @@ static int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset) * * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware */ -int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, +int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len, uint16_t id, uint16_t offset) { int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; @@ -356,7 +381,7 @@ int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, goto out; /* Actually do the transfer */ - hermes_read_data(hw, dreg, buf, len/2); + hermes_read_words(hw, dreg, buf, len/2); out: return err; @@ -368,7 +393,7 @@ int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, * * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware */ -int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len, +int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len, uint16_t id, uint16_t offset) { int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; @@ -382,7 +407,7 @@ int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len, goto out; /* Actually do the transfer */ - hermes_write_data(hw, dreg, buf, len/2); + hermes_write_words(hw, dreg, buf, len/2); out: return err; @@ -434,17 +459,7 @@ int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen, lengths in the records seem to be wrong, frequently */ count = buflen / 2; -#if 0 - if (length) - count = (MIN(buflen, rlength) + 1) / 2; - else { - count = buflen / 2; - if (rlength != buflen) - printk(KERN_WARNING "hermes_read_ltv(): Incorrect \ -record length %d instead of %d on RID 0x%04x\n", rlength, buflen, rid); - } -#endif - hermes_read_data(hw, dreg, buf, count); + hermes_read_words(hw, dreg, buf, count); out: return err; @@ -470,7 +485,7 @@ int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, count = length - 1; - hermes_write_data(hw, dreg, value, count); + hermes_write_words(hw, dreg, value, count); err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, rid, &resp); diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h index 58c663331b5b..a8cfaf4f7d56 100644 --- a/drivers/net/wireless/hermes.h +++ b/drivers/net/wireless/hermes.h @@ -50,6 +50,7 @@ #define HERMES_FRAME_LEN_MAX (2304) #define HERMES_MAX_MULTICAST (16) #define HERMES_MAGIC (0x7d1f) +#define HERMES_SYMBOL_MAX_VER (14) /* * Hermes register offsets @@ -202,24 +203,21 @@ #define HERMES_RID_WEP_AVAIL (0xfd4f) #define HERMES_RID_CURRENT_CHANNEL (0xfdc1) #define HERMES_RID_DATARATES (0xfdc6) -#define HERMES_RID_SYMBOL_PRIMARY_VER (0xfd03) -#define HERMES_RID_SYMBOL_SECONDARY_VER (0xfd21) +#define HERMES_RID_SYMBOL_SECONDARY_VER (0xfd24) #define HERMES_RID_SYMBOL_KEY_LENGTH (0xfc2B) /* * Frame structures and constants */ -#define __PACKED__ __attribute__ ((packed)) - typedef struct hermes_frame_desc { /* Hermes - i.e. little-endian byte-order */ - uint16_t status __PACKED__; - uint16_t res1, res2 __PACKED__; - uint16_t q_info __PACKED__; - uint16_t res3, res4 __PACKED__; - uint16_t tx_ctl __PACKED__; -} hermes_frame_desc_t; + uint16_t status; + uint16_t res1, res2; + uint16_t q_info; + uint16_t res3, res4; + uint16_t tx_ctl; +} __attribute__ ((packed)) hermes_frame_desc_t; #define HERMES_RXSTAT_ERR (0x0003) #define HERMES_RXSTAT_MACPORT (0x0700) @@ -265,20 +263,16 @@ typedef struct hermes_multicast { #define hermes_read_regn(hw, name) (hermes_read_reg((hw), HERMES_##name)) #define hermes_write_regn(hw, name, val) (hermes_write_reg((hw), HERMES_##name, (val))) -/* Note that for the next two, the count is in 16-bit words, not bytes */ -#define hermes_read_data(hw, off, buf, count) (insw((hw)->iobase + (off), (buf), (count))) -#define hermes_write_data(hw, off, buf, count) (outsw((hw)->iobase + (off), (buf), (count))) - /* Function prototypes */ void hermes_struct_init(hermes_t *hw, uint io); int hermes_reset(hermes_t *hw); int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp); int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid); - -int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, +int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset); +int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len, uint16_t id, uint16_t offset); -int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len, +int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len, uint16_t id, uint16_t offset); int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen, uint16_t *length, void *buf); @@ -323,6 +317,10 @@ static inline int hermes_disable_port(hermes_t *hw, int port) #define HERMES_BYTES_TO_RECLEN(n) ( ((n) % 2) ? (((n)+1)/2)+1 : ((n)/2)+1 ) #define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 ) +/* Note that for the next two, the count is in 16-bit words, not bytes */ +#define hermes_read_words(hw, off, buf, count) (insw((hw)->iobase + (off), (buf), (count))) +#define hermes_write_words(hw, off, buf, count) (outsw((hw)->iobase + (off), (buf), (count))) + #define HERMES_READ_RECORD(hw, bap, rid, buf) \ (hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf))) #define HERMES_WRITE_RECORD(hw, bap, rid, buf) \ diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 777faa3e56b8..3d5505048ef2 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -1,4 +1,4 @@ -/* orinoco.c 0.07 - (formerly known as dldwd_cs.c and orinoco_cs.c) +/* orinoco.c 0.08 - (formerly known as dldwd_cs.c and orinoco_cs.c) * * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ @@ -190,13 +190,35 @@ * Rx path, but don't make as much noise about it. * o Firmware detection cleanups. * + * v0.07 -> v0.08 - 3/10/2001 - David Gibson + * o Fixed a possible buffer overrun found by the Stanford checker (in + * dldwd_ioctl_setiwencode()). Can only be called by root anyway, so not + * a big problem. + * o Turned has_big_wep on for Intersil cards. That's not true for all of them + * but we should at least let the capable ones try. + * o Wait for BUSY to clear at the beginning of hermes_bap_seek(). I + * realised that my assumption that the driver's serialization + * would prevent the BAP being busy on entry was possibly false, because + * things other than seeks may make the BAP busy. + * o Use "alternate" (oui 00:00:00) encapsulation by default. + * Setting use_old_encaps will mimic the old behaviour, but I + * think we will be able to eliminate this. + * o Don't try to make __initdata const (the version string). + * This can't work because of the way the __initdata sectioning + * works. + * o Added MODULE_LICENSE tags. + * o Support for PLX (transparent PCMCIA->PCI brdge) cards. + * o Improved support for Symbol firmware - we can actually tell + * the version now. * * TODO - Jean II - * o inline functions (lot's of candidate, need to reorder code) + * o inline functions (lots of candidate, need to reorder code) * o Test PrismII/Symbol cards & firmware versions * o Mini-PCI support (some people have reported success - JII) */ +#include <linux/config.h> + #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> @@ -227,7 +249,7 @@ #include "hermes.h" #include "orinoco.h" -static char version[] __initdata = "orinoco.c 0.07 (David Gibson <hermes@gibson.dropbear.id.au> and others)"; +static char version[] __initdata = "orinoco.c 0.08 (David Gibson <hermes@gibson.dropbear.id.au> and others)"; MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>"); MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based and similar wireless cards"); MODULE_LICENSE("Dual MPL/GPL"); @@ -238,10 +260,8 @@ int dldwd_debug = ORINOCO_DEBUG; MODULE_PARM(dldwd_debug, "i"); #endif -/* FIXME: We need a better way of handling this */ -/* Set this flag to use 00:00:00 for the encapsulation oui instead of 00:00:F8 */ -static int use_alternate_encaps; /* =0 */ -MODULE_PARM(use_alternate_encaps, "i"); +int use_old_encaps = 0; +MODULE_PARM(use_old_encaps, "i"); const long channel_frequency[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, @@ -307,12 +327,13 @@ struct dldwd_frame_hdr { /* 802.2 LLL header SNAP used for SNAP encapsulation over 802.11 */ struct p8022_hdr encaps_hdr = { - 0xaa, 0xaa, 0x03, {0x00, 0x00, 0xf8} -}; -struct p8022_hdr alternate_encaps_hdr = { 0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00} }; +struct p8022_hdr old_encaps_hdr = { + 0xaa, 0xaa, 0x03, {0x00, 0x00, 0xf8} +}; + /* How many times to retry if we get an EIO reading the BAP in the Rx path */ #define RX_EIO_RETRY 10 @@ -881,7 +902,7 @@ static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, num = le16_to_cpu(list.len); *numrates = num; - num = MIN(num, max); + num = min(num, max); for (i = 0; i < num; i++) { rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ @@ -1286,7 +1307,7 @@ static void determine_firmware(struct net_device *dev) if (sta_id.vendor == 1) { /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, - ELSE, Meloc, HP, IBM, Dell 1150 */ + ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */ printk(KERN_DEBUG "%s: Looks like a Lucent/Agere firmware " "version %d.%02d\n", dev->name, sta_id.major, sta_id.minor); @@ -1303,7 +1324,7 @@ static void determine_firmware(struct net_device *dev) priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell Gold cards from the others? */ priv->has_mwo = (firmver >= 0x60000); - priv->has_pm = (firmver >= 0x40020); + priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ priv->has_preamble = 0; priv->ibss_port = 1; /* Tested with Lucent firmware : @@ -1314,27 +1335,59 @@ static void determine_firmware(struct net_device *dev) /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ /* Intel MAC : 00:02:B3:* */ /* 3Com MAC : 00:50:DA:* */ + union symbol_sta_id { + char raw[HERMES_SYMBOL_MAX_VER]; + char string[HERMES_SYMBOL_MAX_VER + 1]; + } symbol_sta_id; + + /* Get the Symbol firmware version */ + err = HERMES_READ_RECORD(hw, USER_BAP, + HERMES_RID_SYMBOL_SECONDARY_VER, + &(symbol_sta_id.raw)); + if (err) { + printk(KERN_WARNING "%s: Error %d reading Symbol firmware info. Wildly guessing capabilities...\n", + dev->name, err); + firmver = 0; + symbol_sta_id.string[0] = '\0'; + } else { + /* The firmware revision is a string, the format is + * something like : "V2.20-01". + * Quick and dirty parsing... - Jean II + */ + firmver = ((symbol_sta_id.raw[1] - '0') << 16) + | ((symbol_sta_id.raw[3] - '0') << 12) + | ((symbol_sta_id.raw[4] - '0') << 8) + | ((symbol_sta_id.raw[6] - '0') << 4) + | (symbol_sta_id.raw[7] - '0'); + + symbol_sta_id.string[HERMES_SYMBOL_MAX_VER] = '\0'; + } + printk(KERN_DEBUG "%s: Looks like a Symbol firmware " - "(unknown version)\n", dev->name); + "version [%s] (parsing to %X)\n", dev->name, + symbol_sta_id.string, firmver); - /* FIXME : we need to get Symbol firmware revision. - * I tried to use SYMBOL_***ARY_VER, but it didn't - * returned anything proper... */ priv->firmware_type = FIRMWARE_TYPE_SYMBOL; priv->tx_rate_ctrl = 0xF; /* 11 Mb/s auto */ priv->need_card_reset = 1; priv->broken_reset = 0; priv->broken_allocate = 1; priv->has_port3 = 1; - priv->has_ibss = 1; /* FIXME */ - priv->has_wep = 1; /* FIXME */ - priv->has_big_wep = 1; /* RID_SYMBOL_KEY_LENGTH */ + priv->has_ibss = (firmver >= 0x20000); + priv->has_wep = (firmver >= 0x15012); + priv->has_big_wep = (firmver >= 0x20000); priv->has_mwo = 0; - priv->has_pm = 1; /* FIXME */ - priv->has_preamble = 0; /* FIXME */ + priv->has_pm = (firmver >= 0x20000) && (firmver < 0x22000); + priv->has_preamble = (firmver >= 0x20000); priv->ibss_port = 4; - /* Tested with Intel firmware : v15 => Jean II */ + /* Tested with Intel firmware : 0x20015 => Jean II */ + /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */ } else { + /* D-Link, Linksys, Adtron, ZoomAir, and many others... + * Samsung, Compaq 100/200 and Proxim are slightly + * different and less well tested */ + /* D-Link MAC : 00:40:05:* */ + /* Addtron MAC : 00:90:D1:* */ printk(KERN_DEBUG "%s: Looks like an Intersil firmware " "version %d.%02d\n", dev->name, sta_id.major, sta_id.minor); @@ -1347,7 +1400,7 @@ static void determine_firmware(struct net_device *dev) priv->has_port3 = 1; priv->has_ibss = (firmver >= 0x00007); /* FIXME */ priv->has_wep = (firmver >= 0x00008); - priv->has_big_wep = 0; + priv->has_big_wep = priv->has_wep; priv->has_mwo = 0; priv->has_pm = (firmver >= 0x00007); priv->has_preamble = 0; @@ -1427,9 +1480,9 @@ dldwd_init(struct net_device *dev) goto out; } if ( nickbuf.len ) - len = MIN(IW_ESSID_MAX_SIZE, le16_to_cpu(nickbuf.len)); + len = min(IW_ESSID_MAX_SIZE, le16_to_cpu(nickbuf.len)); else - len = MIN(IW_ESSID_MAX_SIZE, 2 * reclen); + len = min(IW_ESSID_MAX_SIZE, 2 * reclen); memcpy(priv->nick, &nickbuf.val, len); priv->nick[len] = '\0'; @@ -1556,20 +1609,12 @@ dldwd_get_wireless_stats(struct net_device *dev) err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_COMMSQUALITY, &cq); - le16_to_cpus(&cq.qual); - le16_to_cpus(&cq.signal); - le16_to_cpus(&cq.noise); - DEBUG(3, "%s: Global stats = %X-%X-%X\n", dev->name, cq.qual, cq.signal, cq.noise); - /* Why are we using MIN/MAX ? We don't really care - * if the value goes above max, because we export the - * raw dBm values anyway. The normalisation should be done - * in user space - Jean II */ - wstats->qual.qual = MAX(MIN(cq.qual, 0x8b-0x2f), 0); - wstats->qual.level = MAX(MIN(cq.signal, 0x8a), 0x2f) - 0x95; - wstats->qual.noise = MAX(MIN(cq.noise, 0x8a), 0x2f) - 0x95; + wstats->qual.qual = le16_to_cpu(cq.qual); + wstats->qual.level = le16_to_cpu(cq.signal); + wstats->qual.noise = le16_to_cpu(cq.noise); wstats->qual.updated = 7; } @@ -1593,9 +1638,9 @@ static inline void dldwd_spy_gather(struct net_device *dev, * source address with out list, and if match, get the stats... */ for (i = 0; i < priv->spy_number; i++) if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) { - priv->spy_stat[i].qual = MAX(MIN(cq->qual, 0x8b-0x2f), 0); - priv->spy_stat[i].level = MAX(MIN(cq->signal, 0x8a), 0x2f) - 0x95; - priv->spy_stat[i].noise = MAX(MIN(cq->noise, 0x8a), 0x2f) - 0x95; + priv->spy_stat[i].qual = cq->qual; + priv->spy_stat[i].level = cq->signal; + priv->spy_stat[i].noise = cq->noise; priv->spy_stat[i].updated = 7; } } @@ -1674,7 +1719,7 @@ dldwd_xmit(struct sk_buff *skb, struct net_device *dev) dldwd_lock(priv); /* Length of the packet body */ - len = MAX(skb->len - ETH_HLEN, ETH_ZLEN); + len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN); eh = (struct ethhdr *)skb->data; @@ -1699,12 +1744,13 @@ dldwd_xmit(struct sk_buff *skb, struct net_device *dev) hdr.p8023.h_proto = htons(data_len + ENCAPS_OVERHEAD); /* 802.2 header */ - /* FIXME: ugh, what a hack for the 00:00:00 APs. Need to find a better way */ - if (use_alternate_encaps) - memcpy(&hdr.p8022, &alternate_encaps_hdr, sizeof(alternate_encaps_hdr)); + if (! use_old_encaps) + memcpy(&hdr.p8022, &encaps_hdr, + sizeof(encaps_hdr)); else - memcpy(&hdr.p8022, &encaps_hdr, sizeof(encaps_hdr)); - + memcpy(&hdr.p8022, &encaps_hdr, + sizeof(old_encaps_hdr)); + hdr.ethertype = eh->h_proto; err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), txfid, 0); @@ -1933,12 +1979,12 @@ static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq) uint16_t xlen = 0; int err = 0; char keybuf[MAX_KEY_SIZE]; - + if (erq->pointer) { /* We actually have a key to set */ - if(erq->length > MAX_KEY_SIZE) + if ( (erq->length < SMALL_KEY_SIZE) || (erq->length > MAX_KEY_SIZE) ) return -EINVAL; - + if (copy_from_user(keybuf, erq->pointer, erq->length)) return -EFAULT; } @@ -3512,7 +3558,7 @@ dldwd_proc_get_hermes_recs(char *page, char **start, off_t requested_offset, buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name, rid, length, (length-1)*2); - len = MIN( MAX(minlen, (length-1)*2), maxlen); + len = min( (int)max(minlen, ((int)length-1)*2), maxlen); switch (record_table[i].displaytype) { case DISPLAY_WORDS: @@ -3531,7 +3577,7 @@ dldwd_proc_get_hermes_recs(char *page, char **start, off_t requested_offset, break; case DISPLAY_STRING: - len = MIN(len, le16_to_cpu(val16[0])+2); + len = min(len, le16_to_cpu(val16[0])+2); val8[len] = '\0'; buf += sprintf(buf, "\"%s\"", (char *)&val16[1]); break; diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index 07d94110e486..c5f30c36cd9d 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -25,7 +25,7 @@ #define DLDWD_MACPORT 0 #define IRQ_LOOP_MAX 10 #define TX_NICBUF_SIZE 2048 -#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Intel firmware */ +#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */ #define MAX_KEYS 4 #define MAX_KEY_SIZE 14 #define LARGE_KEY_SIZE 13 @@ -110,7 +110,7 @@ extern struct list_head dldwd_instances; #ifdef ORINOCO_DEBUG extern int dldwd_debug; -#define DEBUG(n, args...) if (dldwd_debug>(n)) printk(KERN_DEBUG args) +#define DEBUG(n, args...) do { if (dldwd_debug>(n)) printk(KERN_DEBUG args); } while(0) #define DEBUGMORE(n, args...) do { if (dldwd_debug>(n)) printk(args); } while (0) #else #define DEBUG(n, args...) do { } while (0) @@ -120,9 +120,6 @@ extern int dldwd_debug; #define TRACE_ENTER(devname) DEBUG(2, "%s: -> " __FUNCTION__ "()\n", devname); #define TRACE_EXIT(devname) DEBUG(2, "%s: <- " __FUNCTION__ "()\n", devname); -#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) -#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) - #define RUP_EVEN(a) ( (a) % 2 ? (a) + 1 : (a) ) /* struct net_device methods */ diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index 651ee6c81925..996eb4c6f680 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -1,4 +1,4 @@ -/* orinoco_cs.c 0.07 - (formerly known as dldwd_cs.c) +/* orinoco_cs.c 0.08 - (formerly known as dldwd_cs.c) * * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ @@ -10,6 +10,8 @@ * Copyright notice & release notes in file orinoco.c */ +#include <linux/config.h> + #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> @@ -42,7 +44,7 @@ /*====================================================================*/ -static char version[] __initdata = "orinoco_cs.c 0.07 (David Gibson <hermes@gibson.dropbear.id.au> and others)"; +static char version[] __initdata = "orinoco_cs.c 0.08 (David Gibson <hermes@gibson.dropbear.id.au> and others)"; MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>"); MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco, Prism II based and similar wireless cards"); diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids index b1f338e0aea5..45966f06cb69 100644 --- a/drivers/pci/pci.ids +++ b/drivers/pci/pci.ids @@ -27,6 +27,8 @@ 0e11 Compaq Computer Corporation 0001 PCI to EISA Bridge 0002 PCI to ISA Bridge + 0049 NC7132 Gigabit Upgrade Module + 004a NC6136 Gigabit Server Adapter 0508 Netelligent 4/16 Token Ring 1000 Triflex/Pentium Bridge, Model 1000 2000 Triflex/Pentium Bridge, Model 2000 @@ -40,6 +42,8 @@ a0f0 Advanced System Management Controller a0f3 Triflex PCI to ISA Bridge a0f7 PCI Hotplug Controller + 8086 002a PCI Hotplug Controller A + 8086 002b PCI Hotplug Controller B a0f8 USB Open Host Controller ae10 Smart-2/P RAID Controller 0e11 4030 Smart-2/P Array Controller @@ -61,13 +65,29 @@ ae6d NorthStar CPU to PCI Bridge b011 Integrated Netelligent 10/100 b012 Netelligent 10 T/2 + b01e NC3120 Fast Ethernet NIC + b01f NC3122 Fast Ethernet NIC + b02f NC1120 Ethernet NIC b030 Netelligent WS 5100 - b04a 10/100TX WOL UTP Controller - b0c6 10/100TX Embedded WOL UTP Controller - b0d7 NC3121 (Rev A & B) + b04a 10/100 TX PCI Intel WOL UTP Controller + b0c6 NC3161 Fast Ethernet NIC + b0c7 NC3160 Fast Ethernet NIC + b0d7 NC3121 Fast Ethernet NIC + b0dd NC3131 Fast Ethernet NIC + b0de NC3132 Fast Ethernet Module + b0df NC6132 Gigabit Module + b0e0 NC6133 Gigabit Module + b0e1 NC3133 Fast Ethernet Module + b123 NC6134 Gigabit NIC + b134 NC3163 Fast Ethernet NIC + b13c NC3162 Fast Ethernet NIC + b144 NC3123 Fast Ethernet NIC + b163 NC3134 Fast Ethernet NIC + b164 NC3135 Fast Ethernet Upgrade Module + b1a4 NC7131 Gigabit Server Adapter f130 NetFlex-3/P ThunderLAN 1.0 f150 NetFlex-3/P ThunderLAN 2.3 -1000 Symbios Logic Inc. (formerly NCR) +1000 LSI Logic / Symbios Logic (formerly NCR) 0001 53c810 1000 1000 8100S 0002 53c820 @@ -141,16 +161,19 @@ 0e11 b10e 3D Rage LT Pro (Compaq Armada 1750) 1028 0085 Rage 3D LT Pro 4c44 3D Rage LT Pro AGP-66 - 4c46 Mobility M3 AGP 2x + 4c45 Rage Mobility M3 AGP + 4c46 Rage Mobility M3 AGP 2x 4c47 3D Rage LT-G 215LG 4c49 3D Rage LT Pro - 4c4d 3D Rage P/M Mobility AGP 2x - 4c4e 3D Rage L Mobility AGP 2x + 4c4d Rage Mobility P/M AGP 2x + 4c4e Rage Mobility L AGP 2x 4c50 3D Rage LT Pro 4c51 3D Rage LT Pro - 4c52 3D Rage P/M Mobility - 4c53 3D Rage L Mobility + 4c52 Rage Mobility P/M + 4c53 Rage Mobility L 4c54 264LT [Mach64 LT] + 4d46 Rage Mobility M4 AGP + 4d4c Rage Mobility M4 AGP 5041 Rage 128 PA 5042 Rage 128 PB 5043 Rage 128 PC @@ -244,7 +267,7 @@ 000f OHCI Compliant FireWire Controller 0011 National PCI System I/O 0012 USB Controller - 0020 DP83815 (MacPhyter) Ethernet Controller + 0020 DP83815 d001 87410 IDE 100c Tseng Labs Inc 3202 ET4000/W32p rev A @@ -276,6 +299,8 @@ 1113 1207 EN-1207-TX Fast Ethernet 1186 1100 DFE-500TX Fast Ethernet 1186 1112 DFE-570TX Fast Ethernet + 1186 1140 DFE-660 Cardbus Ethernet 10/100 + 1186 1142 DFE-660 Cardbus Ethernet 10/100 1282 9100 AEF-380TXD Fast Ethernet 1385 1100 FA310TX Fast Ethernet 2646 0001 KNE100TX Fast Ethernet @@ -374,7 +399,7 @@ 0020 MCA 0022 IBM27-82351 002d Python - 002e ServeRAID controller + 002e ServeRAID-3x 0036 Miami 003a CPU to PCI Bridge 003e 16/4 Token ring UTP/STP controller @@ -415,6 +440,10 @@ 0144 Yotta Video Compositor Output 1014 0145 Yotta Output Controller (ytout) 0156 405GP PLB to PCI Bridge + 01bd Netfinity ServeRAID controller + 01be ServeRAID-4M + 01bf ServeRAID-4L + 022e ServeRAID-4H ffff MPIC-2 interrupt controller 1015 LSI Logic Corp of Canada 1016 ICL Personal Systems @@ -438,6 +467,9 @@ 9712 Pipeline 9712 c24a 90C 101e American Megatrends Inc. + 1960 MegaRAID + 1028 0471 PowerEdge RAID Controller 3/QC + 1028 0493 PowerEdge RAID Controller 3/DC 9010 MegaRAID 9030 EIDE Controller 9031 EIDE Controller @@ -589,6 +621,7 @@ 0005 PowerEdge Expandable RAID Controller 3/Di 0006 PowerEdge Expandable RAID Controller 3/Di 0008 PowerEdge Expandable RAID Controller 3/Di + 000a PowerEdge Expandable RAID Controller 3/Di 1029 Siemens Nixdorf IS 102a LSI Logic 0000 HYDRA @@ -642,6 +675,8 @@ 0e11 b16f Matrox MGA-G400 AGP 102b 0328 Millennium G400 16Mb SDRAM 102b 0338 Millennium G400 16Mb SDRAM + 102b 0378 Millennium G400 32Mb SDRAM + 102b 0641 Millennium G450 32Mb SDRAM 102b 19d8 Millennium G400 16Mb SGRAM 102b 19f8 Millennium G400 32Mb SGRAM 102b 2159 Millennium G400 Dual Head 16Mb @@ -664,6 +699,8 @@ 102b ff05 MGA-G100 Productiva AGP Multi-Monitor 110a 001e MGA-G100 AGP 2007 MGA Mistral + 2527 MGA G550 AGP + 102b 0f84 Millennium G550 Dual Head DDR 32Mb 4536 VIA Framegrabber 6573 Shark 10/100 Multiport SwitchNIC 102c Chips and Technologies @@ -984,6 +1021,7 @@ 4802 Falcon 4803 Hawk 4806 CPX8216 + 4d68 20268 5600 SM56 PCI Modem 1057 0300 SM56 PCI Speakerphone Modem 1057 0301 SM56 PCI Voice Modem @@ -1129,19 +1167,26 @@ 0012 YMF-754 [DS-1E Audio Controller] 1073 0012 DS-XG PCI Audio Codec 0020 DS-1 Audio + 2000 DS2416 Digital Mixing Card + 1073 2000 DS2416 Digital Mixing Card 1074 NexGen Microsystems 4e78 82c500/1 1075 Advanced Integrations Research 1076 Chaintech Computer Co. Ltd -1077 Q Logic +1077 QLogic Corp. + 1016 QLA10160 1020 ISP1020 1022 ISP1022 - 1080 ISP1080 - 1240 ISP1240 - 1280 ISP1280 + 1080 QLA1080 + 1216 QLA12160 + 101e 8471 QLA12160 on AMI MegaRAID + 101e 8493 QLA12160 on AMI MegaRAID + 1240 QLA1240 + 1280 QLA1280 2020 ISP2020A - 2100 ISP2100 - 2200 ISP2200 + 2100 QLA2100 + 2200 QLA2200 + 2300 QLA2300 1078 Cyrix Corporation 0000 5510 [Grappa] 0001 PCI Master @@ -1291,7 +1336,7 @@ 109e Brooktree Corporation 0350 Bt848 TV with DMA push 0351 Bt849A Video capture - 036c Bt879(?) Video Capture + 036c Bt879(??) Video Capture 13e9 0070 Win/TV (Video Section) 036e Bt878 0070 13eb WinTV/GO @@ -1476,6 +1521,8 @@ 906e 9060ES 9080 9080 10b5 9080 9080 [real subsystem ID not set] + a001 GTEK Jetport II 2 port serial adaptor + c001 GTEK Cyclone 16/32 port serial adaptor 10b6 Madge Networks 0001 Smart 16/4 PCI Ringnode 0002 Smart 16/4 PCI Ringnode Mk2 @@ -1505,13 +1552,13 @@ 10b7 3590 TokenLink Velocity XL Adapter 4500 3c450 Cyclone/unknown 5055 3c555 Laptop Hurricane - 6055 3c556 Laptop Tornado + 6055 3c556 Laptop Hurricane 6056 3c556B Laptop Hurricane 5057 3c575 [Megahertz] 10/100 LAN CardBus 10b7 5a57 3C575 Megahertz 10/100 LAN Cardbus PC Card - 5157 3CCFE575BT Cyclone CardBus + 5157 3c575 [Megahertz] 10/100 LAN CardBus 10b7 5b57 3C575 Megahertz 10/100 LAN Cardbus PC Card - 5257 3CCFE575CT Tornado CardBus + 5257 3CCFE575CT Cyclone CardBus 5900 3c590 10BaseT [Vortex] 5920 3c592 EISA 10mbps Demon/Vortex 5950 3c595 100BaseTX [Vortex] @@ -1521,8 +1568,8 @@ 5b57 3c595 [Megahertz] 10/100 LAN CardBus 10b7 5b57 3C575 Megahertz 10/100 LAN Cardbus PC Card 6560 3CCFE656 Cyclone CardBus - 6562 3CCFEM656B Cyclone CardBus - 6564 3CXFEM656C Tornado CardBus + 6562 3CCFEM656 [id 6562] Cyclone CardBus + 6564 3CCFEM656 [id 6564] Cyclone CardBus 7646 3cSOHO100-TX Hurricane 8811 Token ring 9000 3c900 10BaseT [Boomerang] @@ -1564,8 +1611,8 @@ 10b7 1000 3C905C-TX Fast Etherlink for PC Management NIC 9800 3c980-TX [Fast Etherlink XL Server Adapter] 10b7 9800 3c980-TX Fast Etherlink XL Server Adapter - 9805 3c982 Dual Port Server Cyclone - 10b7 9805 3c982 Dual Port Server Cyclone + 9805 3c980-TX 10/100baseTX NIC [Python-T] + 10b7 9805 3c980 10/100baseTX NIC [Python-T] 10b8 Standard Microsystems Corp [SMC] 0005 83C170QF 1055 e000 LANEPIC @@ -1674,6 +1721,8 @@ 10f7 8312 MagicGraph 128XD 0005 [MagicMedia 256AV] 0006 NM2360 [MagicMedia 256ZX] + 0016 NM2380 [MagicMedia 256XL+] + 10c8 0016 MagicMedia 256XL+ 0083 [MagicGraph 128ZV Plus] 8005 [MagicMedia 256AV Audio] 0e11 b0d1 MagicMedia 256AV Audio Device on Discovery @@ -1730,7 +1779,7 @@ 0008 EDGE 3D [NV1] 0009 EDGE 3D [NV1] 0010 Mutara V08 [NV2] - 0020 Riva TnT 128 [NV04] + 0020 Riva TnT [NV04] 1043 0200 V3400 TNT 1048 0c18 Erazor II SGRAM 1092 0550 Viper V550 @@ -1803,14 +1852,16 @@ 1102 102e CT6971 GeForce 256 DDR 14af 5021 3D Prophet DDR-DVI 0103 Quadro (GeForce 256 GL) - 0110 NV11 - 0111 NV11 DDR - 0113 NV11 GL - 0150 NV15 (Geforce2 GTS) + 0110 NV11 (GeForce2 MX) + 0111 NV11 (GeForce2 MX DDR) + 0112 GeForce2 Go + 0113 NV11 (GeForce2 MXR) + 0150 NV15 (Geforce2 Pro) 107d 2840 WinFast GeForce2 GTS with TV output 0151 NV15 DDR (Geforce2 GTS) - 0152 NV15 Bladerunner (Geforce2 GTS) - 0153 NV15 GL (Quadro2) + 0152 NV15 Bladerunner (Geforce2 Ultra) + 0153 NV15 GL (Quadro2 Pro) + 0203 Quadro DCC 10df Emulex Corporation 10df Light Pulse Fibre Channel Adapter 1ae5 LP6000 Fibre Channel Host Adapter @@ -1824,6 +1875,7 @@ 9128 IMS9129 [Twin turbo 128] 10e1 Tekram Technology Co.,Ltd. 0391 TRM-S1040 + 10e1 0391 DC-315U SCSI-3 Host Adapter 690c DC-690c dc29 DC-290 10e2 Aptix Corporation @@ -1877,6 +1929,7 @@ 1025 8921 ALN-325 10bd 0320 EP-320X-R 10ec 8139 RT8139 + 1186 1300 DFE-538TX 1186 1320 SN5200 1259 2500 AT-2500TX 1429 d010 ND010 @@ -1926,7 +1979,7 @@ 9401 INI-950 9500 360P 1102 Creative Labs - 0002 SB Live! EMU10000 + 0002 SB Live! EMU10k1 1102 0020 CT4850 SBLive! Value 1102 0021 CT4620 SBLive! 1102 002f SBLive! mainboard implementation @@ -1942,9 +1995,10 @@ 1102 8051 CT4850 SBLive! Value 7002 SB Live! 1102 0020 Gameport Joystick -1103 HighPoint Technologies, Inc. - 0003 HPT343 UltraDMA 33 IDE Controller - 0004 HPT366/370 UltraDMA 66/100 IDE Controller +1103 Triones Technologies, Inc. + 0003 HPT343 + 0004 HPT366 / HPT370 + 1103 0005 HPT370 UDMA100 1104 RasterOps Corp. 1105 Sigma Designs, Inc. 8300 REALmagic Hollywood Plus DVD Decoder @@ -1955,7 +2009,7 @@ 0505 VT82C505 0561 VT82C561 0571 Bus Master IDE - 0576 VT82C576 [Apollo Master] + 0576 VT82C576 3V [Apollo Master] 0585 VT82C585VP [Apollo VP1/VPX] 0586 VT82C586/A/B PCI-to-ISA [Apollo VP] 1106 0000 MVP3 ISA Bridge @@ -1973,12 +2027,12 @@ 1106 0686 VT82C686/A PCI to ISA Bridge 0691 VT82C693A/694x [Apollo PRO133x] 1458 0691 VT82C691 Apollo Pro System Controller - 0698 VT82C693A [Apollo Pro133 AGP] 0693 VT82C693 [Apollo Pro Plus] + 0698 VT82C693A [Apollo Pro133 AGP] 0926 VT82C926 [Amazon] 1000 VT82C570MV 1106 VT82C570MV - 1571 VT82C576 IDE [Apollo Master] + 1571 VT82C416MV 1595 VT82C595/97 [Apollo VP2/97] 3038 UHCI USB 1234 0925 MVP3 USB Controller @@ -2012,8 +2066,8 @@ 8598 VT82C598/694x [Apollo MVP3/Pro133x AGP] 8601 VT8601 [Apollo ProMedia AGP] 8605 VT8605 [PM133 AGP] - B091 VT8633 [Apollo Pro266 AGP] - B099 VT8367 [KT266 AGP] + b091 VT8633 [Apollo Pro266 AGP] + b099 VT8367 [KT266 AGP] 8691 VT82C691 [Apollo Pro] 1107 Stratus Computers 0576 VIA VT82C570MV [Apollo] (Wrong vendor ID!) @@ -2073,7 +2127,7 @@ 1118 Berg Electronics 1119 ICP Vortex Computersysteme GmbH 0000 GDT 6000/6020/6050 - 0001 GDT 6000b/6010 + 0001 GDT 6000B/6010 0002 GDT 6110/6510 0003 GDT 6120/6520 0004 GDT 6530 @@ -2081,9 +2135,9 @@ 0006 GDT 6x17 0007 GDT 6x27 0008 GDT 6537 - 0009 GDT 5557 - 000a GDT 6x15 - 000b GDT 6x25 + 0009 GDT 6557 + 000a GDT 6115/6515 + 000b GDT 6125/6525 000c GDT 6535 000d GDT 6555 0100 GDT 6117RP/6517RP @@ -2092,30 +2146,34 @@ 0103 GDT 6557RP 0104 GDT 6111RP/6511RP 0105 GDT 6121RP/6521RP - 0110 GDT 6117RP1/6517RP1 - 0111 GDT 6127RP1/6527RP1 - 0112 GDT 6537RP1 - 0113 GDT 6557RP1 - 0114 GDT 6111RP1/6511RP1 - 0115 GDT 6121RP1/6521RP1 - 0118 GDT 6x18RD - 0119 GDT 6x28RD - 011a GDT 6x38RD - 011b GDT 6x58RD - 0120 GDT 6117RP2/6517RP2 - 0121 GDT 6127RP2/6527RP2 - 0122 GDT 6537RP2 - 0123 GDT 6557RP2 - 0124 GDT 6111RP2/6511RP2 - 0125 GDT 6121RP2/6521RP2 - 0168 GDT 7x18RN - 0169 GDT 7x28RN - 016a GDT 7x38RN - 016b GDT 7x58RN - 0210 GDT 6x19RD - 0211 GDT 6x29RD - 0260 GDT 7x19RN - 0261 GDT 7x29RN + 0110 GDT 6117RD/6517RD + 0111 GDT 6127RD/6527RD + 0112 GDT 6537RD + 0113 GDT 6557RD + 0114 GDT 6111RD/6511RD + 0115 GDT 6121RD/6521RD + 0118 GDT 6118RD/6518RD/6618RD + 0119 GDT 6128RD/6528RD/6628RD + 011a GDT 6538RD/6638RD + 011b GDT 6558RD/6658RD + 0138 GDT 6118RS/6518RS/6618RS + 0139 GDT 6128RS/6528RS/6628RS + 013a GDT 6538RS/6638RS + 013b GDT 6558RS/6658RS + 0166 GDT 7113RN/7513RN/7613RN + 0167 GDT 7123RN/7523RN/7623RN + 0168 GDT 7118RN/7518RN/7518RN + 0169 GDT 7128RN/7528RN/7628RN + 016a GDT 7538RN/7638RN + 016b GDT 7558RN/7658RN + 016c GDT 7533RN/7633RN + 016d GDT 7543RN/7643RN + 016e GDT 7553RN/7653RN + 016f GDT 7563RN/7663RN + 0210 GDT 6519RD/6619RD + 0211 GDT 6529RD/6629RD + 0260 GDT 7519RN/7619RN + 0261 GDT 7529RN/7629RN 111a Efficient Networks, Inc 0000 155P-MF1 (FPGA) 0002 155P-MF1 (ASIC) @@ -2235,7 +2293,7 @@ 1145 Workbit Corporation 1146 Force Computers 1147 Interface Corp -1148 SysKonnect GmbH +1148 Syskonnect (Schneider & Koch) 4000 FDDI Adapter 0e11 b03b Netelligent 100 FDDI DAS Fibre SC 0e11 b03c Netelligent 100 FDDI SAS Fibre SC @@ -2252,7 +2310,7 @@ 1148 5841 FDDI SK-5841 (SK-NET FDDI-FP64) 1148 5843 FDDI SK-5843 (SK-NET FDDI-LP64) 1148 5844 FDDI SK-5844 (SK-NET FDDI-LP64 DAS) - 4200 Token Ring adapter + 4200 Token ring adaptor 4300 Gigabit Ethernet 1148 9821 SK-9821 (1000Base-T single link) 1148 9822 SK-9822 (1000Base-T dual link) @@ -2429,6 +2487,7 @@ 118b Hypertec Pty Limited 118c Corollary, Inc 0014 PCIB [C-bus II to PCI bus host bridge chip] + 1117 Intel 8-way XEON Profusion Chipset [Cache Coherency Filter] 118d BitFlow Inc 0001 Raptor-PCI framegrabber 0012 Model 12 Road Runner Frame Grabber @@ -2478,7 +2537,7 @@ 1221 82C092G 119c Information Technology Inst. 119d Bug, Inc. Sapporo Japan -119e Fujitsu Microelectronics Europe GMBH +119e Fujitsu Microelectronics Ltd. 0001 FireStream 155 0003 FireStream 50 119f Bull HN Information Systems @@ -2692,6 +2751,7 @@ 11f5 Computing Devices International 11f6 Compex 0112 ENet100VG4 + 0113 FreedomLine 100 1401 ReadyLink 2000 2011 RL100-ATX 10/100 2201 ReadyLink 100TX (Winbond W89C840) @@ -2803,7 +2863,8 @@ 121a 0060 Voodoo3 3500 TV (NTSC) 121a 0061 Voodoo3 3500 TV (PAL) 121a 0062 Voodoo3 3500 TV (SECAM) - 0009 Voodoo 4 + 0009 Voodoo 4 / Voodoo 5 + 121a 0009 Voodoo5 AGP 5500/6000 121b Advanced Telecommunications Modules 121c Nippon Texaco., Ltd 121d Lippert Automationstechnik GmbH @@ -3029,13 +3090,13 @@ 8086 5753 ES1371, ES1373 AudioPCI On Motherboard WS440BX 5000 ES1370 [AudioPCI] 4942 4c4c Creative Sound Blaster AudioPCI128 - 5880 CT5880 [AudioPCI] + 5880 5880 AudioPCI 1274 2000 Creative Sound Blaster AudioPCI128 1274 5880 Creative Sound Blaster AudioPCI128 - 1462 6880 CT5880 AudioPCI On Motherboard MS-6188 1.00 - 270f 2001 CT5880 AudioPCI On Motherboard 6CTR - 270f 2200 CT5880 AudioPCI On Motherboard 6WTX - 270f 7040 CT5880 AudioPCI On Motherboard 6ATA4 + 1462 6880 5880 AudioPCI On Motherboard MS-6188 1.00 + 270f 2001 5880 AudioPCI On Motherboard 6CTR + 270f 2200 5880 AudioPCI On Motherboard 6WTX + 270f 7040 5880 AudioPCI On Motherboard 6ATA4 1275 Network Appliance Corporation 1276 Switched Network Technologies, Inc. 1277 Comstream @@ -3146,8 +3207,9 @@ 12ac Measurex Corporation 12ad Multidata GmbH 12ae Alteon Networks Inc. - 0001 AceNIC Gigabit Ethernet + 0001 AceNIC Gigabit Ethernet (Fibre) 1410 0104 Gigabit Ethernet-SX PCI Adapter (14100401) + 0002 AceNIC Gigabit Ethernet (Copper) 12af TDK USA Corp 12b0 Jorge Scientific Corp 12b1 GammaLink @@ -3368,7 +3430,8 @@ 1312 Acuity Imaging, Inc 1313 Yaskawa Electric Co. 1316 Teradyne Inc -1317 Bridgecom, Inc +1317 Linksys + 0985 Network Everywhere Fast Ethernet 10/100 model NC100 1318 Packet Engines Inc. 0911 PCI Ethernet Adapter 1319 Fortemedia, Inc @@ -3528,6 +3591,7 @@ 1384 Reality Simulation Systems Inc 1385 Netgear 620a GA620 + f311 FA311 1386 Video Domain Technologies 1387 Systran Corp 1388 Hitachi Information Technology Co Ltd @@ -3920,7 +3984,31 @@ 14e2 INFOLIBRIA 14e3 AMTELCO 14e4 BROADCOM Corporation - 1644 Tigon3 + 1644 NetXtreme BCM5700 Gigabit Ethernet + 10b7 1000 3C996-T 1000BaseTX + 10b7 1001 3C996B-T 1000BaseTX + 10b7 1002 3C996C-T 1000BaseTX + 10b7 1003 3C997-T 1000BaseTX + 10b7 1004 3C996-SX 1000BaseSX + 10b7 1005 3C997-SX 1000BaseSX + 14e4 0002 NetXtreme 1000BaseSX + 14e4 0003 NetXtreme 1000BaseSX + 14e4 0004 NetXtreme 1000BaseTX + 14e4 1644 NetXtreme BCM5700 1000BaseTX + 1645 NetXtreme BCM5701 Gigabit Ethernet + 0e11 007d NC6770 1000BaseSX + 0e11 007c NC7770 1000BaseTX + 0e11 0085 NC7780 1000BaseTX + 10b7 1004 3C996-SX 1000BaseSX + 10b7 1006 3C996B-T 1000BaseTX + 10b7 1007 3C1000-T 1000BaseTX + 10b7 1008 3C940-BR01 1000BaseTX + 14e4 0001 NetXtreme BCM5701 1000BaseTX + 14e4 0005 NetXtreme BCM5701 1000BaseTX + 14e4 0006 NetXtreme BCM5701 1000BaseTX + 14e4 0007 NetXtreme BCM5701 1000BaseSX + 14e4 0008 NetXtreme BCM5701 1000BaseTX + 14e4 8008 NetXtreme BCM5701 1000BaseTX 14e5 Pixelfusion Ltd 14e6 SHINING Technology Inc 14e7 3CX @@ -3955,6 +4043,8 @@ 14f1 2015 SoftK56 Speakerphone Winmodem 2016 SoftK56 Speakerphone Winmodem 14f1 2016 SoftK56 Speakerphone Winmodem + 2443 SoftK56 Speakerphone Winmodem + 14f1 2443 SoftK56 Speakerphone Winmodem 14f2 MOBILITY Electronics 14f3 BROADLOGIC 14f4 TOKYO Electronic Industry CO Ltd @@ -3979,7 +4069,7 @@ # 1507 HTEC Ltd # Commented out because there are no known HTEC chips and 1507 is already # used by mistake by Motorola (see vendor ID 1057) -1507 Motorola ? / HTEC +1507 Motorola ?? / HTEC 0001 MPC105 [Eagle] 0002 MPC106 [Grackle] 0003 MPC8240 [Kahlua] @@ -4300,7 +4390,7 @@ 270b Xantel Corporation 270f Chaintech Computer Co. Ltd 2711 AVID Technology Inc. -2a15 3D Vision(?) +2a15 3D Vision(???) 3000 Hansol Electronics Inc. 3142 Post Impression Systems. 3388 Hint Corp @@ -4332,6 +4422,7 @@ 3d3d 0125 Oxygen VX1 3d3d 0127 Permedia3 Create! 000a GLINT R3 + 3d3d 0121 Oxygen VX1 0100 Permedia II 2D+3D 1004 Permedia 3d04 Permedia @@ -4476,12 +4567,16 @@ 5333 9125 86C394-397 Savage4 SGRAM 125 5333 9143 86C394-397 Savage4 SGRAM 143 8a23 Savage 4 + 8a25 ProSavage PM133 + 8a26 ProSavage KM133 8c00 ViRGE/M3 8c01 ViRGE/MX 8c02 ViRGE/MX+ 8c03 ViRGE/MX+MV - 8c10 86C270-294 Savage/MX-/IX - 8c12 86C270-294 Savage/MX-/IX + 8c10 86C270-294 Savage/MX-MV + 8c11 82C270-294 Savage/MX + 8c12 86C270-294 Savage/IX-MV + 8c13 86C270-294 Savage/IX 9102 86C410 Savage 2000 1092 5932 Viper II Z200 1092 5934 Viper II Z200 @@ -4496,6 +4591,8 @@ 5455 Technische University Berlin 4458 S5933 5519 Cnet Technologies, Inc. +5544 Dunord Technologies + 0001 I-30xx Scanner Interface 5555 Genroco, Inc 0003 TURBOstor HFP-832 [HiPPI NIC] 5700 Netpower @@ -4523,22 +4620,37 @@ 04a3 82434LX [Mercury/Neptune] 04d0 82437FX [Triton FX] 0960 80960RP [i960 RP Microprocessor/Bridge] - 1000 82542 Gigabit Ethernet Adapter + 0964 80960RP [i960 RP Microprocessor/Bridge] + 1000 82542 Gigabit Ethernet Controller 0e11 b0df NC1632 Gigabit Ethernet Adapter 0e11 b0e0 NC1633 Gigabit Ethernet Adapter 0e11 b123 NC1634 Gigabit Ethernet Adapter 1014 0119 Netfinity Gigabit Ethernet SX Adapter - 8086 1000 EtherExpress PRO/1000 Gigabit Server Adapter + 1001 82543GC Gigabit Ethernet Controller + 1004 82543GC Gigabit Ethernet Controller + 1008 82544EI Gigabit Ethernet Controller + 100c 82544GC Gigabit Ethernet Controller + 100d 82544GC Gigabit Ethernet Controller 1030 82559 InBusiness 10/100 + 1031 82801CAM (ICH3) Chipset Ethernet Controller + 1032 82801CAM (ICH3) Chipset Ethernet Controller + 1033 82801CAM (ICH3) Chipset Ethernet Controller + 1034 82801CAM (ICH3) Chipset Ethernet Controller + 1035 82801CAM (ICH3) Chipset Ethernet Controller + 1036 82801CAM (ICH3) Chipset Ethernet Controller + 1037 82801CAM (ICH3) Chipset Ethernet Controller + 1038 82801CAM (ICH3) Chipset Ethernet Controller + 1130 82815 815 Chipset Host Bridge and Memory Controller Hub + 1132 82815 CGC [Chipset Graphics Controller] 1161 82806AA PCI64 Hub Advanced Programmable Interrupt Controller 1209 82559ER 1221 82092AA_0 1222 82092AA_1 1223 SAA7116 1225 82452KX/GX [Orion] - 1226 82596 - 1227 82865 [Ether Express Pro 100] - 1228 82556 [Ether Express Pro 100 Smart] + 1226 82596 PRO/10 PCI + 1227 82865 EtherExpress PRO/100A + 1228 82556 EtherExpress PRO/100 Smart 1229 82557 [Ethernet Pro 100] 0e11 b01e NC3120 0e11 b01f NC3122 @@ -4550,6 +4662,7 @@ 0e11 b0dd NC3131 0e11 b0de NC3132 0e11 b0e1 NC3133 + 0e11 b144 NC3123 (82559) 1014 005c 82558B Ethernet Pro 10/100 1014 105c Netfinity 10/100 1033 8000 PC-9821X-B06 @@ -4604,6 +4717,9 @@ 1960 80960RP [i960RP Microprocessor] 101e 0438 MegaRaid 438 101e 0466 MegaRaid 466 + 101e 0467 MegaRaid 467 + 1028 0467 PowerEdge Expandable RAID Controller 2/DC + 1028 1111 PowerEdge Expandable RAID Controller 2/SC 103c 10c6 MegaRaid 438 103c 10c7 MegaRaid T5 1111 1111 MegaRaid 466 @@ -4630,18 +4746,18 @@ 11d4 0048 SoundMAX Integrated Digital Audio 2426 82801AB AC'97 Modem 2428 82801AB PCI Bridge - 2440 82801BA ISA Bridge (ICH2) - 2442 82801BA(M) USB (Hub A) - 2443 82801BA(M) SMBus - 2444 82801BA(M) USB (Hub B) - 2445 82801BA(M) AC'97 Audio - 2446 82801BA(M) AC'97 Modem - 2448 82801BA PCI - 2449 82801BA(M) Ethernet - 244a 82801BAM IDE U100 - 244b 82801BA IDE U100 - 244c 82801BAM ISA Bridge (ICH2) - 244e 82801BAM PCI + 2440 82820 820 (Camino 2) Chipset ISA Bridge (ICH2) + 2442 82820 820 (Camino 2) Chipset USB (Hub A) + 2443 82820 820 (Camino 2) Chipset SMBus + 2444 82820 820 (Camino 2) Chipset USB (Hub B) + 2445 82820 820 (Camino 2) Chipset AC'97 Audio Controller + 2446 82820 820 (Camino 2) Chipset AC'97 Modem Controller + 2448 82820 820 (Camino 2) Chipset PCI (-M) + 2449 82820 (ICH2) Chipset Ethernet Controller + 244a 82820 820 (Camino 2) Chipset IDE U100 (-M) + 244b 82820 820 (Camino 2) Chipset IDE U100 + 244c 82820 820 (Camino 2) Chipset ISA Bridge (ICH2-M) + 244e 82820 820 (Camino 2) Chipset PCI 2500 82820 820 (Camino) Chipset Host Bridge (MCH) 1043 801c P3C-2000 system chipset 2501 82820 820 (Camino) Chipset Host Bridge (MCH) @@ -4651,10 +4767,13 @@ 2520 82805AA MTH Memory Translator Hub 2521 82804AA MRH-S Memory Repeater Hub for SDRAM 2530 82850 850 (Tehama) Chipset Host Bridge (MCH) + 2531 82850 860 (Wombat) Chipset Host Bridge (MCH) 2532 82850 850 (Tehama) Chipset AGP Bridge - 5200 EtherExpress PRO/100 - 5201 EtherExpress PRO/100 + 2533 82860 860 (Wombat) Chipset AGP Bridge + 5200 EtherExpress PRO/100 Intelligent Server + 5201 EtherExpress PRO/100 Intelligent Server 8086 0001 EtherExpress PRO/100 Server Ethernet Adapter + 530d 80310 IOP [IO Processor] 7000 82371SB PIIX3 ISA [Natoma/Triton II] 7010 82371SB PIIX3 IDE [Natoma/Triton II] 7020 82371SB PIIX3 USB [Natoma/Triton II] @@ -4717,7 +4836,7 @@ 9004 Adaptec # FIXME: [dj] In one document I have, lot of these AIC's are actually AHA's 1078 AIC-7810 - 1160 AIC-1160 [Family Fiber Channel Adapter] + 1160 AIC-1160 [Family Fibre Channel Adapter] 2178 AIC-7821 3860 AHA-2930CU 3b78 AHA-4844W/4844UW @@ -4834,6 +4953,7 @@ 00c0 7899A 00c1 7899B 00c3 7899D + 00c5 RAID subsystem HBA 00cf 7899P 907f Atronics 2015 IDE-2015PL @@ -5017,7 +5137,7 @@ C 0c Serial bus controller 10 OHCI 80 Unspecified Fe USB Device - 04 Fiber Channel + 04 Fibre Channel 05 SMBus 06 InfiniBand C 0d Wireless controller diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 83368d4cc5f2..488e7d496f92 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -12,7 +12,7 @@ Copyright 1992 - 2001 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Sun Aug 12 12:34:28 2001 by makisara@kai.makisara.local + Last modified: Wed Oct 3 22:17:59 2001 by makisara@kai.makisara.local Some small formal changes - aeb, 950809 Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support @@ -21,7 +21,7 @@ error handling will be discarded. */ -static char *verstr = "20010812"; +static char *verstr = "20011003"; #include <linux/module.h> @@ -89,6 +89,8 @@ MODULE_PARM_DESC(max_buffers, "Maximum number of buffer allocated at initialisat MODULE_PARM(max_sg_segs, "i"); MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (32)"); +EXPORT_NO_SYMBOLS; + #ifndef MODULE static struct st_dev_parm { char *name; @@ -669,6 +671,7 @@ static int st_open(struct inode *inode, struct file *filp) if (STp->device->host->hostt->module) __MOD_INC_USE_COUNT(STp->device->host->hostt->module); + STp->device->access_count++; if (!scsi_block_when_processing_errors(STp->device)) { retval = (-ENXIO); @@ -909,6 +912,7 @@ static int st_open(struct inode *inode, struct file *filp) STp->buffer = NULL; } STp->in_use = 0; + STp->device->access_count--; if (STp->device->host->hostt->module) __MOD_DEC_USE_COUNT(STp->device->host->hostt->module); return retval; @@ -1066,6 +1070,7 @@ static int st_release(struct inode *inode, struct file *filp) STp->in_use = 0; write_unlock_irqrestore(&st_dev_arr_lock, flags); + STp->device->access_count--; if (STp->device->host->hostt->module) __MOD_DEC_USE_COUNT(STp->device->host->hostt->module); diff --git a/drivers/video/clgenfb.c b/drivers/video/clgenfb.c index 6b220143dc90..b0235faa4e1e 100644 --- a/drivers/video/clgenfb.c +++ b/drivers/video/clgenfb.c @@ -31,7 +31,7 @@ * */ -#define CLGEN_VERSION "1.9.8" +#define CLGEN_VERSION "1.9.9" #include <linux/config.h> #include <linux/module.h> @@ -273,6 +273,7 @@ static const struct { { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5434_8 }, { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5434_4 }, { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5430 }, /* GD-5440 has identical id */ + { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_7543 }, { BT_GD5480, NULL, PCI_DEVICE_ID_CIRRUS_5480 }, /* MacPicasso probably */ { BT_PICASSO4, NULL, PCI_DEVICE_ID_CIRRUS_5446 }, /* Picasso 4 is a GD5446 */ { BT_LAGUNA, "CL Laguna", PCI_DEVICE_ID_CIRRUS_5462 }, diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index a3ca017d6c23..52ca30f5a42a 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -51,6 +51,7 @@ #include <asm/io.h> #include <asm/prom.h> #include <asm/pgtable.h> +#include <asm/btext.h> #include <video/fbcon.h> #include <video/fbcon-cfb8.h> @@ -757,6 +758,12 @@ static void control_set_hardware(struct fb_info_control *p, struct fb_par_contro console_fb_info = &p->info; } #endif /* CONFIG_FB_COMPAT_XPMAC */ +#ifdef CONFIG_BOOTX_TEXT + btext_update_display(p->frame_buffer_phys + CTRLFB_OFF, + p->par.xres, p->par.yres, + (cmode == CMODE_32? 32: cmode == CMODE_16? 16: 8), + p->par.pitch); +#endif /* CONFIG_BOOTX_TEXT */ } diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 4aa1d3f6b36c..80621868bd1c 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -32,7 +32,9 @@ #endif #include <asm/io.h> #include <asm/prom.h> +#ifdef CONFIG_BOOTX_TEXT #include <asm/bootx.h> +#endif #include <video/fbcon.h> #include <video/fbcon-cfb8.h> @@ -95,8 +97,9 @@ static int offb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); - +#ifdef CONFIG_BOOTX_TEXT extern boot_infos_t *boot_infos; +#endif static void offb_init_nodriver(struct device_node *); static void offb_init_fb(const char *name, const char *full_name, int width, @@ -253,6 +256,7 @@ int __init offb_init(void) { struct device_node *dp; unsigned int dpy; +#ifdef CONFIG_BOOTX_TEXT struct device_node *displays = find_type_devices("display"); struct device_node *macos_display = NULL; @@ -315,6 +319,7 @@ int __init offb_init(void) boot_infos->dispDeviceDepth, boot_infos->dispDeviceRowBytes, addr, NULL); } +#endif for (dpy = 0; dpy < prom_num_displays; dpy++) { if ((dp = find_path_device(prom_display_paths[dpy]))) @@ -426,7 +431,8 @@ static void __init offb_init_fb(const char *name, const char *full_name, unsigned long regbase = dp->addrs[2].address; info->cmap_adr = ioremap(regbase, 0x1FFF); info->cmap_type = cmap_r128; - } else if (dp && !strncmp(name, "ATY,RageM3pA", 12)) { + } else if (dp && (!strncmp(name, "ATY,RageM3pA", 12) + || !strncmp(name, "ATY,RageM3p12A", 14))) { unsigned long regbase = dp->parent->addrs[2].address; info->cmap_adr = ioremap(regbase, 0x1FFF); info->cmap_type = cmap_M3A; diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 76b6c22490d7..ee93f1f75d83 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -76,6 +76,8 @@ static struct linux_binfmt elf_format = { NULL, THIS_MODULE, load_elf_binary, load_elf_library, elf_core_dump, ELF_EXEC_PAGESIZE }; +#define BAD_ADDR(x) ((unsigned long)(x) > TASK_SIZE) + static void set_brk(unsigned long start, unsigned long end) { start = ELF_PAGEALIGN(start); @@ -298,6 +300,8 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, elf_type |= MAP_FIXED; map_addr = elf_map(interpreter, load_addr + vaddr, eppnt, elf_prot, elf_type); + if (BAD_ADDR(map_addr)) + goto out_close; if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { load_addr = map_addr - ELF_PAGESTART(vaddr); @@ -649,6 +653,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) } error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags); + if (BAD_ADDR(error)) + continue; if (!load_addr_set) { load_addr_set = 1; @@ -697,7 +703,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) fput(interpreter); kfree(elf_interpreter); - if (elf_entry == ~0UL) { + if (BAD_ADDR(elf_entry)) { printk(KERN_ERR "Unable to load interpreter\n"); kfree(elf_phdata); send_sig(SIGSEGV, current, 0); diff --git a/fs/block_dev.c b/fs/block_dev.c index 8ce2918bf78d..2df9d2a00686 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -549,36 +549,23 @@ int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg) return res; } -int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags, int kind) +static int do_open(struct block_device *bdev, struct inode *inode, struct file *file) { - int ret = -ENODEV; - kdev_t rdev = to_kdev_t(bdev->bd_dev); /* this should become bdev */ - down(&bdev->bd_sem); + int ret = -ENXIO; + kdev_t dev = to_kdev_t(bdev->bd_dev); + down(&bdev->bd_sem); lock_kernel(); if (!bdev->bd_op) - bdev->bd_op = get_blkfops(MAJOR(rdev)); + bdev->bd_op = get_blkfops(MAJOR(dev)); if (bdev->bd_op) { - /* - * This crockload is due to bad choice of ->open() type. - * It will go away. - * For now, block device ->open() routine must _not_ - * examine anything in 'inode' argument except ->i_rdev. - */ - struct file fake_file = {}; - struct dentry fake_dentry = {}; - ret = -ENOMEM; - fake_file.f_mode = mode; - fake_file.f_flags = flags; - fake_file.f_dentry = &fake_dentry; - fake_dentry.d_inode = bdev->bd_inode; ret = 0; if (bdev->bd_op->open) - ret = bdev->bd_op->open(bdev->bd_inode, &fake_file); + ret = bdev->bd_op->open(inode, file); if (!ret) { bdev->bd_openers++; - bdev->bd_inode->i_size = blkdev_size(rdev); - bdev->bd_inode->i_blkbits = blksize_bits(block_size(rdev)); + bdev->bd_inode->i_size = blkdev_size(dev); + bdev->bd_inode->i_blkbits = blksize_bits(block_size(dev)); } else if (!bdev->bd_openers) bdev->bd_op = NULL; } @@ -589,9 +576,26 @@ int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags, int kind) return ret; } +int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags, int kind) +{ + /* + * This crockload is due to bad choice of ->open() type. + * It will go away. + * For now, block device ->open() routine must _not_ + * examine anything in 'inode' argument except ->i_rdev. + */ + struct file fake_file = {}; + struct dentry fake_dentry = {}; + fake_file.f_mode = mode; + fake_file.f_flags = flags; + fake_file.f_dentry = &fake_dentry; + fake_dentry.d_inode = bdev->bd_inode; + + return do_open(bdev, bdev->bd_inode, &fake_file); +} + int blkdev_open(struct inode * inode, struct file * filp) { - int ret; struct block_device *bdev; /* @@ -604,29 +608,8 @@ int blkdev_open(struct inode * inode, struct file * filp) bd_acquire(inode); bdev = inode->i_bdev; - down(&bdev->bd_sem); - ret = -ENXIO; - lock_kernel(); - if (!bdev->bd_op) - bdev->bd_op = get_blkfops(MAJOR(inode->i_rdev)); - - if (bdev->bd_op) { - ret = 0; - if (bdev->bd_op->open) - ret = bdev->bd_op->open(inode,filp); - if (!ret) { - bdev->bd_openers++; - bdev->bd_inode->i_size = blkdev_size(inode->i_rdev); - } else if (!bdev->bd_openers) - bdev->bd_op = NULL; - } - - unlock_kernel(); - up(&bdev->bd_sem); - if (ret) - bdput(bdev); - return ret; + return do_open(bdev, inode, filp); } int blkdev_put(struct block_device *bdev, int kind) diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index d3339912a25d..7b2eaba253e6 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -15,6 +15,7 @@ #define __KERNEL_SYSCALLS__ #include <linux/config.h> #include <linux/module.h> +#include <linux/init.h> #include <linux/sched.h> #include <linux/errno.h> @@ -55,6 +56,7 @@ static DECLARE_WAIT_QUEUE_HEAD(lockd_exit); */ unsigned long nlm_grace_period; unsigned long nlm_timeout = LOCKD_DFLT_TIMEO; +unsigned long nlm_udpport, nlm_tcpport; static unsigned long set_grace_period(void) { @@ -241,9 +243,9 @@ lockd_up(void) goto out; } - if ((error = svc_makesock(serv, IPPROTO_UDP, 0)) < 0 + if ((error = svc_makesock(serv, IPPROTO_UDP, nlm_udpport)) < 0 #ifdef CONFIG_NFSD_TCP - || (error = svc_makesock(serv, IPPROTO_TCP, 0)) < 0 + || (error = svc_makesock(serv, IPPROTO_TCP, nlm_tcpport)) < 0 #endif ) { if (warned++ == 0) @@ -323,6 +325,8 @@ MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); MODULE_DESCRIPTION("NFS file locking service version " LOCKD_VERSION "."); MODULE_PARM(nlm_grace_period, "10-240l"); MODULE_PARM(nlm_timeout, "3-20l"); +MODULE_PARM(nlm_udpport, "0-65535l"); +MODULE_PARM(nlm_tcpport, "0-65535l"); int init_module(void) @@ -340,6 +344,24 @@ cleanup_module(void) /* FIXME: delete all NLM clients */ nlm_shutdown_hosts(); } +#else +/* not a module, so process bootargs + * lockd.udpport and lockd.tcpport + */ + +static int __init udpport_set(char *str) +{ + nlm_udpport = simple_strtoul(str, NULL, 0); + return 1; +} +static int __init tcpport_set(char *str) +{ + nlm_tcpport = simple_strtoul(str, NULL, 0); + return 1; +} +__setup("lockd.udpport=", udpport_set); +__setup("lockd.tcpport=", tcpport_set); + #endif /* diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 46340e88f1c8..537b685ce576 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -550,15 +550,15 @@ struct flags { { NFSEXP_INSECURE_PORT, {"insecure", ""}}, { NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}}, { NFSEXP_ALLSQUASH, {"all_squash", ""}}, - { NFSEXP_ASYNC, {"async", ""}}, - { NFSEXP_GATHERED_WRITES, {"wdelay", ""}}, + { NFSEXP_ASYNC, {"async", "sync"}}, + { NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}}, { NFSEXP_UIDMAP, {"uidmap", ""}}, { NFSEXP_KERBEROS, { "kerberos", ""}}, { NFSEXP_SUNSECURE, { "sunsecure", ""}}, { NFSEXP_CROSSMNT, {"nohide", ""}}, { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}}, { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}}, -#ifdef NSMFS +#ifdef MSNFS { NFSEXP_MSNFS, {"msnfs", ""}}, #endif { 0, {"", ""}} diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index aa35c9aae007..e3b037803b0e 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -99,7 +99,7 @@ decode_pathname(u32 *p, char **namp, int *lenp) char *name; int i; - if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXPATHLEN)) != NULL) { + if ((p = xdr_decode_string(p, namp, lenp, NFS3_MAXPATHLEN)) != NULL) { for (i = 0, name = *namp; i < *lenp; i++, name++) { if (*name == '\0') return NULL; diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index bc7315c87c05..417b4173c477 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -731,8 +731,10 @@ inline int _fh_update(struct dentry *dentry, struct svc_export *exp, { struct super_block *sb = dentry->d_inode->i_sb; - if (dentry == exp->ex_dentry) + if (dentry == exp->ex_dentry) { + *maxsize = 0; return 0; + } if (sb->s_op->dentry_to_fh) { int need_parent = !S_ISDIR(dentry->d_inode->i_mode) && diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 25d8ddf63af6..debae923e8f2 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -65,7 +65,7 @@ decode_filename(u32 *p, char **namp, int *lenp) char *name; int i; - if ((p = xdr_decode_string(p, namp, lenp, NFS_MAXNAMLEN)) != NULL) { + if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXNAMLEN)) != NULL) { for (i = 0, name = *namp; i < *lenp; i++, name++) { if (*name == '\0' || *name == '/') return NULL; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 2aaa9149758a..015ef90095e0 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -227,7 +227,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, #define MAX_TOUCH_TIME_ERROR (30*60) if (err && (iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET - && iap->ia_mtime == iap->ia_ctime + && iap->ia_mtime == iap->ia_atime ) { /* looks good. now just make sure time is in the right ballpark. * solaris, at least, doesn't seem to care what the time request is diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c index d0afb47eec09..e87f0a717314 100644 --- a/fs/partitions/acorn.c +++ b/fs/partitions/acorn.c @@ -22,15 +22,16 @@ #include "acorn.h" static void -adfspart_setgeometry(kdev_t dev, unsigned int secspertrack, unsigned int heads, - unsigned long totalblocks) +adfspart_setgeometry(kdev_t dev, unsigned int secspertrack, unsigned int heads) { +#ifdef CONFIG_BLK_DEV_MFM extern void xd_set_geometry(kdev_t dev, unsigned char, unsigned char, unsigned long, unsigned int); -#ifdef CONFIG_BLK_DEV_MFM - if (MAJOR(dev) == MFM_ACORN_MAJOR) + if (MAJOR(dev) == MFM_ACORN_MAJOR) { + unsigned long totalblocks = hd->part[MINOR(dev)].nr_sects; xd_set_geometry(dev, secspertrack, heads, totalblocks, 1); + } #endif } @@ -60,32 +61,26 @@ adfs_partition(struct gendisk *hd, char *name, char *data, #ifdef CONFIG_ACORN_PARTITION_RISCIX static int -riscix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sect, - int minor, unsigned long nr_sects) +riscix_partition(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sect, int minor, unsigned long nr_sects) { - struct buffer_head *bh; + Sector sect; struct riscix_record *rr; - unsigned int riscix_minor; - if(get_ptable_blocksize(dev)!=1024) - return 0; + rr = (struct riscix_record *)read_dev_sector(bdev, first_sect, §); + if (!rr) + return -1; printk(" [RISCiX]"); - add_gd_partition(hd, riscix_minor = minor++, first_sect, nr_sects); - hd->sizes[riscix_minor] = hd->part[riscix_minor].nr_sects >> - (BLOCK_SIZE_BITS - 9); - dev = MKDEV(hd->major, riscix_minor); - - if (!(bh = bread(dev, 0, 1024))) - return -1; - rr = (struct riscix_record *)bh->b_data; if (rr->magic == RISCIX_MAGIC) { + unsigned long size = nr_sects > 2 ? 2 : nr_sects; int part; printk(" <"); + add_gd_partition(hd, minor++, first_sect, size); for (part = 0; part < 8; part++) { if (rr->part[part].one && memcmp(rr->part[part].name, "All\0", 4)) { @@ -97,38 +92,32 @@ riscix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sect, } printk(" >\n"); - - if (hd->part[riscix_minor].nr_sects > 2) - hd->part[riscix_minor].nr_sects = 2; + } else { + add_gd_partition(hd, minor++, first_sect, nr_sects); } - brelse(bh); + put_dev_sector(sect); return minor; } #endif static int -linux_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sect, - int minor, unsigned long nr_sects) +linux_partition(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sect, int minor, unsigned long nr_sects) { - struct buffer_head *bh; + Sector sect; struct linux_part *linuxp; - unsigned int linux_minor, mask = (1 << hd->minor_shift) - 1; + unsigned int mask = (1 << hd->minor_shift) - 1; + unsigned long size = nr_sects > 2 ? 2 : nr_sects; - if(get_ptable_blocksize(dev)!=1024) - return 0; - printk(" [Linux]"); - add_gd_partition(hd, linux_minor = minor++, first_sect, nr_sects); - hd->sizes[linux_minor] = hd->part[linux_minor].nr_sects >> - (BLOCK_SIZE_BITS - 9); - dev = MKDEV(hd->major, linux_minor); + add_gd_partition(hd, minor++, first_sect, size); - if (!(bh = bread(dev, 0, 1024))) + linuxp = (struct linux_part *)read_dev_sector(bdev, first_sect, §); + if (!linuxp) return -1; - linuxp = (struct linux_part *)bh->b_data; printk(" <"); while (linuxp->magic == cpu_to_le32(LINUX_NATIVE_MAGIC) || linuxp->magic == cpu_to_le32(LINUX_SWAP_MAGIC)) { @@ -140,29 +129,22 @@ linux_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sect, linuxp ++; } printk(" >"); - /* - * Prevent someone doing a mkswap or mkfs on this partition - */ - if(hd->part[linux_minor].nr_sects > 2) - hd->part[linux_minor].nr_sects = 2; - brelse(bh); + put_dev_sector(sect); return minor; } #ifdef CONFIG_ACORN_PARTITION_CUMANA static int -adfspart_check_CUMANA(struct gendisk *hd, kdev_t dev, +adfspart_check_CUMANA(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int minor) { unsigned int start_blk = 0, mask = (1 << hd->minor_shift) - 1; - struct buffer_head *bh = NULL; + Sector sect; + unsigned char *data; char *name = "CUMANA/ADFS"; int first = 1; - if(get_ptable_blocksize(dev)!=1024) - return 0; - /* * Try Cumana style partitions - sector 3 contains ADFS boot block * with pointer to next 'drive'. @@ -183,16 +165,17 @@ adfspart_check_CUMANA(struct gendisk *hd, kdev_t dev, if (!(minor & mask)) break; - if (!(bh = bread(dev, start_blk + 3, 1024))) + data = read_dev_sector(bdev, start_blk * 2 + 6, §); + if (!data) return -1; - dr = adfs_partition(hd, name, bh->b_data, - first_sector, minor++); + dr = adfs_partition(hd, name, data, first_sector, minor++); if (!dr) break; + name = NULL; - nr_sects = (bh->b_data[0x1fd] + (bh->b_data[0x1fe] << 8)) * + nr_sects = (data[0x1fd] + (data[0x1fe] << 8)) * (dr->heads + (dr->lowsector & 0x40 ? 1 : 0)) * dr->secspertrack; @@ -204,30 +187,28 @@ adfspart_check_CUMANA(struct gendisk *hd, kdev_t dev, start_blk += nr_sects >> (BLOCK_SIZE_BITS - 9); nr_sects = 0; /* hmm - should be partition size */ - switch (bh->b_data[0x1fc] & 15) { + switch (data[0x1fc] & 15) { case 0: /* No partition / ADFS? */ break; #ifdef CONFIG_ACORN_PARTITION_RISCIX case PARTITION_RISCIX_SCSI: /* RISCiX - we don't know how to find the next one. */ - minor = riscix_partition(hd, dev, first_sector, + minor = riscix_partition(hd, bdev, first_sector, minor, nr_sects); break; #endif case PARTITION_LINUX: - minor = linux_partition(hd, dev, first_sector, + minor = linux_partition(hd, bdev, first_sector, minor, nr_sects); break; } - brelse(bh); - bh = NULL; + put_dev_sector(sect); if (minor == -1) return minor; } while (1); - if (bh) - bforget(bh); + put_dev_sector(sect); return first ? 0 : 1; } #endif @@ -248,73 +229,73 @@ adfspart_check_CUMANA(struct gendisk *hd, kdev_t dev, * hda2 = non-ADFS partition. */ static int -adfspart_check_ADFS(struct gendisk *hd, kdev_t dev, +adfspart_check_ADFS(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int minor) { unsigned long start_sect, nr_sects, sectscyl, heads; - struct buffer_head *bh; + Sector sect; + unsigned char *data; struct adfs_discrecord *dr; + unsigned char id; - if(get_ptable_blocksize(dev)!=1024) - return 0; - - if (!(bh = bread(dev, 3, 1024))) + data = read_dev_sector(bdev, 6, §); + if (!data) return -1; - dr = adfs_partition(hd, "ADFS", bh->b_data, first_sector, minor++); + dr = adfs_partition(hd, "ADFS", data, first_sector, minor++); if (!dr) { - bforget(bh); + put_dev_sector(sect); return 0; } heads = dr->heads + ((dr->lowsector >> 6) & 1); - adfspart_setgeometry(dev, dr->secspertrack, heads, - hd->part[MINOR(dev)].nr_sects); sectscyl = dr->secspertrack * heads; + start_sect = ((data[0x1fe] << 8) + data[0x1fd]) * sectscyl; + id = data[0x1fc] & 15; + put_dev_sector(sect); + + adfspart_setgeometry(to_kdev_t(bdev->bd_dev), dr->secspertrack, heads); + invalidate_bdev(bdev, 1); + truncate_inode_pages(bdev->bd_inode->i_mapping, 0); /* * Work out start of non-adfs partition. */ - start_sect = ((bh->b_data[0x1fe] << 8) + bh->b_data[0x1fd]) * sectscyl; - nr_sects = hd->part[MINOR(dev)].nr_sects - start_sect; + nr_sects = hd->part[MINOR(to_kdev_t(bdev->bd_dev))].nr_sects - start_sect; if (start_sect) { first_sector += start_sect; - switch (bh->b_data[0x1fc] & 15) { + switch (id) { #ifdef CONFIG_ACORN_PARTITION_RISCIX case PARTITION_RISCIX_SCSI: case PARTITION_RISCIX_MFM: - minor = riscix_partition(hd, dev, first_sector, + minor = riscix_partition(hd, bdev, first_sector, minor, nr_sects); break; #endif case PARTITION_LINUX: - minor = linux_partition(hd, dev, first_sector, + minor = linux_partition(hd, bdev, first_sector, minor, nr_sects); break; } } - brelse(bh); return 1; } #endif #ifdef CONFIG_ACORN_PARTITION_ICS -static int adfspart_check_ICSLinux(kdev_t dev, unsigned long block) +static int adfspart_check_ICSLinux(struct block_device *bdev, unsigned long block) { - struct buffer_head *bh; - unsigned int offset = block & 1 ? 512 : 0; + Sector sect; + unsigned char *data = read_dev_sector(bdev, block, §); int result = 0; - bh = bread(dev, block >> 1, 1024); - - if (bh != NULL) { - if (memcmp(bh->b_data + offset, "LinuxPart", 9) == 0) + if (data) { + if (memcmp(data, "LinuxPart", 9) == 0) result = 1; - - brelse(bh); + put_dev_sector(sect); } return result; @@ -333,38 +314,37 @@ static int adfspart_check_ICSLinux(kdev_t dev, unsigned long block) * ..etc.. */ static int -adfspart_check_ICS(struct gendisk *hd, kdev_t dev, +adfspart_check_ICS(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int minor) { - struct buffer_head *bh; + Sector sect; + unsigned char *data; unsigned long sum; unsigned int i, mask = (1 << hd->minor_shift) - 1; struct ics_part *p; - if(get_ptable_blocksize(dev)!=1024) - return 0; - /* * Try ICS style partitions - sector 0 contains partition info. */ - if (!(bh = bread(dev, 0, 1024))) + data = read_dev_sector(bdev, 0, §); + if (!data) return -1; /* * check for a valid checksum */ for (i = 0, sum = 0x50617274; i < 508; i++) - sum += bh->b_data[i]; + sum += data[i]; - sum -= le32_to_cpu(*(__u32 *)(&bh->b_data[508])); + sum -= le32_to_cpu(*(__u32 *)(&data[508])); if (sum) { - bforget(bh); + put_dev_sector(sect); return 0; /* not ICS partition table */ } printk(" [ICS]"); - for (p = (struct ics_part *)bh->b_data; p->size; p++) { + for (p = (struct ics_part *)data; p->size; p++) { unsigned long start; long size; @@ -381,7 +361,7 @@ adfspart_check_ICS(struct gendisk *hd, kdev_t dev, * We use the first sector to identify what type * this partition is... */ - if (size > 1 && adfspart_check_ICSLinux(dev, start)) { + if (size > 1 && adfspart_check_ICSLinux(bdev, start)) { start += 1; size -= 1; } @@ -393,12 +373,11 @@ adfspart_check_ICS(struct gendisk *hd, kdev_t dev, } } - brelse(bh); + put_dev_sector(sect); return 1; } #endif -#ifdef CONFIG_ACORN_PARTITION_POWERTEC /* * Purpose: allocate ICS partitions. * Params : hd - pointer to gendisk structure to store partition info. @@ -411,29 +390,32 @@ adfspart_check_ICS(struct gendisk *hd, kdev_t dev, * hda2 = ADFS partition 1 on first drive. * ..etc.. */ +#ifdef CONFIG_ACORN_PARTITION_POWERTEC static int -adfspart_check_POWERTEC(struct gendisk *hd, kdev_t dev, +adfspart_check_POWERTEC(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int minor) { - struct buffer_head *bh; + Sector sect; + unsigned char *data; struct ptec_partition *p; unsigned char checksum; int i; - if (!(bh = bread(dev, 0, 1024))) + data = read_dev_sector(bdev, 0, §); + if (!data) return -1; for (checksum = 0x2a, i = 0; i < 511; i++) - checksum += bh->b_data[i]; + checksum += data[i]; - if (checksum != bh->b_data[511]) { - bforget(bh); + if (checksum != data[511]) { + put_dev_sector(sect); return 0; } printk(" [POWERTEC]"); - for (i = 0, p = (struct ptec_partition *)bh->b_data; i < 12; i++, p++) { + for (i = 0, p = (struct ptec_partition *)data; i < 12; i++, p++) { unsigned long start; unsigned long size; @@ -446,24 +428,24 @@ adfspart_check_POWERTEC(struct gendisk *hd, kdev_t dev, minor++; } - brelse(bh); + put_dev_sector(sect); return 1; } #endif -static int (*partfn[])(struct gendisk *, kdev_t, unsigned long, int) = { +static int (*partfn[])(struct gendisk *, struct block_device *, unsigned long, int) = { #ifdef CONFIG_ACORN_PARTITION_ICS adfspart_check_ICS, #endif +#ifdef CONFIG_ACORN_PARTITION_POWERTEC + adfspart_check_POWERTEC, +#endif #ifdef CONFIG_ACORN_PARTITION_CUMANA adfspart_check_CUMANA, #endif #ifdef CONFIG_ACORN_PARTITION_ADFS adfspart_check_ADFS, #endif -#ifdef CONFIG_ACORN_PARTITION_POWERTEC - adfspart_check_POWERTEC, -#endif NULL }; /* @@ -478,17 +460,18 @@ static int (*partfn[])(struct gendisk *, kdev_t, unsigned long, int) = { * * Returns: -1 on error, 0 if not ADFS format, 1 if ok. */ -int acorn_partition(struct gendisk *hd, kdev_t dev, +int acorn_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sect, int first_minor) { - int r = 0, i; - - for (i = 0; partfn[i] && r == 0; i++) - r = partfn[i](hd, dev, first_sect, first_minor); + int i; - if (r < 0 && warn_no_part) - printk(" unable to read boot sectors / partition sectors\n"); - if (r > 0) - printk("\n"); - return r; + for (i = 0; partfn[i]; i++) { + int r = partfn[i](hd, bdev, first_sect, first_minor); + if (r) { + if (r > 0) + printk("\n"); + return r; + } + } + return 0; } diff --git a/fs/partitions/acorn.h b/fs/partitions/acorn.h index e1d0a3830e8b..f4b3b80d383c 100644 --- a/fs/partitions/acorn.h +++ b/fs/partitions/acorn.h @@ -50,6 +50,6 @@ struct ptec_partition { }; -int acorn_partition(struct gendisk *hd, kdev_t dev, +int acorn_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sect, int first_minor); diff --git a/fs/partitions/amiga.c b/fs/partitions/amiga.c index 4717a1b5f0a0..3ecf9c4f88b4 100644 --- a/fs/partitions/amiga.c +++ b/fs/partitions/amiga.c @@ -31,90 +31,82 @@ checksum_block(u32 *m, int size) } int -amiga_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int first_part_minor) +amiga_partition(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sector, int first_part_minor) { - struct buffer_head *bh; - struct RigidDiskBlock *rdb; - struct PartitionBlock *pb; - int start_sect; - int nr_sects; - int blk; - int part, res; - int old_blocksize; - int blocksize; + Sector sect; + unsigned char *data; + struct RigidDiskBlock *rdb; + struct PartitionBlock *pb; + int start_sect, nr_sects, blk, part, res = 0; + kdev_t dev = to_kdev_t(bdev->bd_dev); - old_blocksize = get_ptable_blocksize(dev); - blocksize = get_hardsect_size(dev); + for (blk = 0; ; blk++, put_dev_sector(sect)) { + if (blk == RDB_ALLOCATION_LIMIT) + goto rdb_done; + data = read_dev_sector(bdev, blk, §); + if (!data) { + if (warn_no_part) + printk("Dev %s: unable to read RDB block %d\n", + bdevname(dev), blk); + goto rdb_done; + } + if (*(u32 *)data != cpu_to_be32(IDNAME_RIGIDDISK)) + continue; - if (blocksize < 512) - blocksize = 512; + rdb = (struct RigidDiskBlock *)data; + if (checksum_block((u32 *)data, be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F) == 0) + break; + /* Try again with 0xdc..0xdf zeroed, Windows might have + * trashed it. + */ + *(u32 *)(data+0xdc) = 0; + if (checksum_block((u32 *)data, + be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)==0) { + printk("Warning: Trashed word at 0xd0 in block %d " + "ignored in checksum calculation\n",blk); + break; + } - set_blocksize(dev,blocksize); - res = 0; + printk("Dev %s: RDB in block %d has bad checksum\n", + bdevname(dev),blk); + } - for (blk = 0; blk < RDB_ALLOCATION_LIMIT; blk++) { - if(!(bh = bread(dev,blk,blocksize))) { - if (warn_no_part) printk("Dev %s: unable to read RDB block %d\n", - kdevname(dev),blk); + printk(" RDSK"); + blk = be32_to_cpu(rdb->rdb_PartitionList); + put_dev_sector(sect); + for (part = 1; blk>0 && part<=16; part++, put_dev_sector(sect)) { + data = read_dev_sector(bdev, blk, §); + if (!data) { + if (warn_no_part) + printk("Dev %s: unable to read partition block %d\n", + bdevname(dev),blk); goto rdb_done; } - if (*(u32 *)bh->b_data == cpu_to_be32(IDNAME_RIGIDDISK)) { - rdb = (struct RigidDiskBlock *)bh->b_data; - if (checksum_block((u32 *)bh->b_data,be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)) { - /* Try again with 0xdc..0xdf zeroed, Windows might have - * trashed it. - */ - *(u32 *)(&bh->b_data[0xdc]) = 0; - if (checksum_block((u32 *)bh->b_data, - be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)) { - brelse(bh); - printk("Dev %s: RDB in block %d has bad checksum\n", - kdevname(dev),blk); - continue; - } - printk("Warning: Trashed word at 0xd0 in block %d " - "ignored in checksum calculation\n",blk); - } - printk(" RDSK"); - blk = be32_to_cpu(rdb->rdb_PartitionList); - brelse(bh); - for (part = 1; blk > 0 && part <= 16; part++) { - if (!(bh = bread(dev,blk,blocksize))) { - if (warn_no_part) printk("Dev %s: unable to read partition block %d\n", - kdevname(dev),blk); - goto rdb_done; - } - pb = (struct PartitionBlock *)bh->b_data; - blk = be32_to_cpu(pb->pb_Next); - if (pb->pb_ID == cpu_to_be32(IDNAME_PARTITION) && checksum_block( - (u32 *)pb,be32_to_cpu(pb->pb_SummedLongs) & 0x7F) == 0 ) { + pb = (struct PartitionBlock *)data; + blk = be32_to_cpu(pb->pb_Next); + if (pb->pb_ID != cpu_to_be32(IDNAME_PARTITION)) + continue; + if (checksum_block((u32 *)pb, be32_to_cpu(pb->pb_SummedLongs) & 0x7F) != 0 ) + continue; - /* Tell Kernel about it */ + /* Tell Kernel about it */ - if (!(nr_sects = (be32_to_cpu(pb->pb_Environment[10]) + 1 - - be32_to_cpu(pb->pb_Environment[9])) * - be32_to_cpu(pb->pb_Environment[3]) * - be32_to_cpu(pb->pb_Environment[5]))) { - brelse(bh); - continue; - } - start_sect = be32_to_cpu(pb->pb_Environment[9]) * - be32_to_cpu(pb->pb_Environment[3]) * - be32_to_cpu(pb->pb_Environment[5]); - add_gd_partition(hd,first_part_minor,start_sect,nr_sects); - first_part_minor++; - res = 1; - } - brelse(bh); - } - printk("\n"); - break; - } - else - brelse(bh); + nr_sects = (be32_to_cpu(pb->pb_Environment[10]) + 1 - + be32_to_cpu(pb->pb_Environment[9])) * + be32_to_cpu(pb->pb_Environment[3]) * + be32_to_cpu(pb->pb_Environment[5]); + if (!nr_sects) + continue; + start_sect = be32_to_cpu(pb->pb_Environment[9]) * + be32_to_cpu(pb->pb_Environment[3]) * + be32_to_cpu(pb->pb_Environment[5]); + add_gd_partition(hd,first_part_minor,start_sect,nr_sects); + first_part_minor++; + res = 1; } + printk("\n"); rdb_done: - set_blocksize(dev,old_blocksize); return res; } diff --git a/fs/partitions/amiga.h b/fs/partitions/amiga.h index 37c6ec144627..4f4f8a2772d9 100644 --- a/fs/partitions/amiga.h +++ b/fs/partitions/amiga.h @@ -3,6 +3,6 @@ */ int -amiga_partition(struct gendisk *hd, kdev_t dev, +amiga_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int first_part_minor); diff --git a/fs/partitions/atari.c b/fs/partitions/atari.c index 0180daca8ef4..11a7b4a79625 100644 --- a/fs/partitions/atari.c +++ b/fs/partitions/atari.c @@ -33,146 +33,130 @@ be32_to_cpu((pi)->st) <= (hdsiz) && \ be32_to_cpu((pi)->st) + be32_to_cpu((pi)->siz) <= (hdsiz)) -int atari_partition (struct gendisk *hd, kdev_t dev, +static inline int OK_id(char *s) +{ + return memcmp (s, "GEM", 3) == 0 || memcmp (s, "BGM", 3) == 0 || + memcmp (s, "LNX", 3) == 0 || memcmp (s, "SWP", 3) == 0 || + memcmp (s, "RAW", 3) == 0 ; +} + +int atari_partition (struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int minor) { - int m_lim = minor + hd->max_p; - struct buffer_head *bh; - struct rootsector *rs; - struct partition_info *pi; - u32 extensect; - u32 hd_size; + int m_lim = minor + hd->max_p; + Sector sect; + struct rootsector *rs; + struct partition_info *pi; + u32 extensect; + u32 hd_size; #ifdef ICD_PARTS - int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */ + int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */ #endif - bh = bread (dev, 0, get_ptable_blocksize(dev)); - if (!bh) { - if (warn_no_part) printk (" unable to read block 0 (partition table)\n"); - return -1; - } - - /* Verify this is an Atari rootsector: */ - rs = (struct rootsector *) bh->b_data; - hd_size = hd->part[minor - 1].nr_sects; - if (!VALID_PARTITION(&rs->part[0], hd_size) && - !VALID_PARTITION(&rs->part[1], hd_size) && - !VALID_PARTITION(&rs->part[2], hd_size) && - !VALID_PARTITION(&rs->part[3], hd_size)) { - /* if there's no valid primary partition, assume that no Atari - format partition table (there's no reliable magic or the like - :-() */ - brelse(bh); - return 0; - } - - pi = &rs->part[0]; - printk (" AHDI"); - for (; pi < &rs->part[4] && minor < m_lim; minor++, pi++) - { - if (pi->flg & 1) - /* active partition */ - { - if (memcmp (pi->id, "XGM", 3) == 0) - /* extension partition */ - { - struct rootsector *xrs; - struct buffer_head *xbh; - ulong partsect; + rs = (struct rootsector *) read_dev_sector(bdev, 0, §); + if (!rs) + return -1; + + /* Verify this is an Atari rootsector: */ + hd_size = hd->part[minor - 1].nr_sects; + if (!VALID_PARTITION(&rs->part[0], hd_size) && + !VALID_PARTITION(&rs->part[1], hd_size) && + !VALID_PARTITION(&rs->part[2], hd_size) && + !VALID_PARTITION(&rs->part[3], hd_size)) { + /* + * if there's no valid primary partition, assume that no Atari + * format partition table (there's no reliable magic or the like + * :-() + */ + put_dev_sector(sect); + return 0; + } + pi = &rs->part[0]; + printk (" AHDI"); + for (; pi < &rs->part[4] && minor < m_lim; minor++, pi++) { + struct rootsector *xrs; + Sector sect2; + ulong partsect; + + if ( !(pi->flg & 1) ) + continue; + /* active partition */ + if (memcmp (pi->id, "XGM", 3) != 0) { + /* we don't care about other id's */ + add_gd_partition (hd, minor, be32_to_cpu(pi->st), + be32_to_cpu(pi->siz)); + continue; + } + /* extension partition */ #ifdef ICD_PARTS - part_fmt = 1; + part_fmt = 1; #endif - printk(" XGM<"); - partsect = extensect = be32_to_cpu(pi->st); - while (1) - { - xbh = bread (dev, partsect / 2, get_ptable_blocksize(dev)); - if (!xbh) - { - printk (" block %ld read failed\n", partsect); - brelse(bh); - return 0; - } - if (partsect & 1) - xrs = (struct rootsector *) &xbh->b_data[512]; - else - xrs = (struct rootsector *) &xbh->b_data[0]; - - /* ++roman: sanity check: bit 0 of flg field must be set */ - if (!(xrs->part[0].flg & 1)) { - printk( "\nFirst sub-partition in extended partition is not valid!\n" ); - break; - } - - add_gd_partition(hd, minor, + printk(" XGM<"); + partsect = extensect = be32_to_cpu(pi->st); + while (1) { + xrs = (struct rootsector *)read_dev_sector(bdev, partsect, §2); + if (!xrs) { + printk (" block %ld read failed\n", partsect); + put_dev_sector(sect); + return 0; + } + + /* ++roman: sanity check: bit 0 of flg field must be set */ + if (!(xrs->part[0].flg & 1)) { + printk( "\nFirst sub-partition in extended partition is not valid!\n" ); + put_dev_sector(sect2); + break; + } + + add_gd_partition(hd, minor, partsect + be32_to_cpu(xrs->part[0].st), be32_to_cpu(xrs->part[0].siz)); - if (!(xrs->part[1].flg & 1)) { - /* end of linked partition list */ - brelse( xbh ); - break; - } - if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) { - printk( "\nID of extended partition is not XGM!\n" ); - brelse( xbh ); - break; - } - - partsect = be32_to_cpu(xrs->part[1].st) + extensect; - brelse (xbh); - minor++; - if (minor >= m_lim) { - printk( "\nMaximum number of partitions reached!\n" ); - break; - } + if (!(xrs->part[1].flg & 1)) { + /* end of linked partition list */ + put_dev_sector(sect2); + break; + } + if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) { + printk("\nID of extended partition is not XGM!\n"); + put_dev_sector(sect2); + break; + } + + partsect = be32_to_cpu(xrs->part[1].st) + extensect; + put_dev_sector(sect2); + minor++; + if (minor >= m_lim) { + printk( "\nMaximum number of partitions reached!\n" ); + break; + } } - printk(" >"); - } - else - { - /* we don't care about other id's */ - add_gd_partition (hd, minor, be32_to_cpu(pi->st), - be32_to_cpu(pi->siz)); - } + printk(" >"); } - } #ifdef ICD_PARTS - if ( part_fmt!=1 ) /* no extended partitions -> test ICD-format */ - { - pi = &rs->icdpart[0]; - /* sanity check: no ICD format if first partition invalid */ - if (memcmp (pi->id, "GEM", 3) == 0 || - memcmp (pi->id, "BGM", 3) == 0 || - memcmp (pi->id, "LNX", 3) == 0 || - memcmp (pi->id, "SWP", 3) == 0 || - memcmp (pi->id, "RAW", 3) == 0 ) - { - printk(" ICD<"); - for (; pi < &rs->icdpart[8] && minor < m_lim; minor++, pi++) - { - /* accept only GEM,BGM,RAW,LNX,SWP partitions */ - if (pi->flg & 1 && - (memcmp (pi->id, "GEM", 3) == 0 || - memcmp (pi->id, "BGM", 3) == 0 || - memcmp (pi->id, "LNX", 3) == 0 || - memcmp (pi->id, "SWP", 3) == 0 || - memcmp (pi->id, "RAW", 3) == 0) ) - { - part_fmt = 2; - add_gd_partition (hd, minor, be32_to_cpu(pi->st), - be32_to_cpu(pi->siz)); - } - } - printk(" >"); - } - } + if ( part_fmt!=1 ) { /* no extended partitions -> test ICD-format */ + pi = &rs->icdpart[0]; + /* sanity check: no ICD format if first partition invalid */ + if (OK_id(pi->id)) { + printk(" ICD<"); + for (; pi < &rs->icdpart[8] && minor < m_lim; minor++, pi++) { + /* accept only GEM,BGM,RAW,LNX,SWP partitions */ + if (!((pi->flg & 1) && OK_id(pi->id))) + continue; + part_fmt = 2; + add_gd_partition (hd, minor, + be32_to_cpu(pi->st), + be32_to_cpu(pi->siz)); + } + printk(" >"); + } + } #endif - brelse (bh); + put_dev_sector(sect); - printk ("\n"); + printk ("\n"); - return 1; + return 1; } diff --git a/fs/partitions/atari.h b/fs/partitions/atari.h index 6d19c93e561a..6a14eb75947d 100644 --- a/fs/partitions/atari.h +++ b/fs/partitions/atari.h @@ -31,6 +31,6 @@ struct rootsector u16 checksum; /* checksum for bootable disks */ } __attribute__((__packed__)); -int atari_partition (struct gendisk *hd, kdev_t dev, +int atari_partition (struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int first_part_minor); diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 6d00b601a179..ee0ce88fed84 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -38,7 +38,7 @@ extern int *blk_size[]; int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/ -static int (*check_part[])(struct gendisk *hd, kdev_t dev, unsigned long first_sect, int first_minor) = { +static int (*check_part[])(struct gendisk *hd, struct block_device *bdev, unsigned long first_sect, int first_minor) = { #ifdef CONFIG_ACORN_PARTITION acorn_partition, #endif @@ -215,54 +215,12 @@ void add_gd_partition(struct gendisk *hd, int minor, int start, int size) #endif } -unsigned int get_ptable_blocksize(kdev_t dev) -{ - int ret = 1024; - - /* - * See whether the low-level driver has given us a minumum blocksize. - * If so, check to see whether it is larger than the default of 1024. - */ - if (!blksize_size[MAJOR(dev)]) - return ret; - - /* - * Check for certain special power of two sizes that we allow. - * With anything larger than 1024, we must force the blocksize up to - * the natural blocksize for the device so that we don't have to try - * and read partial sectors. Anything smaller should be just fine. - */ - - switch (blksize_size[MAJOR(dev)][MINOR(dev)]) { - case 2048: - ret = 2048; - break; - case 4096: - ret = 4096; - break; - case 8192: - ret = 8192; - break; - case 1024: - case 512: - case 256: - case 0: - /* - * These are all OK. - */ - break; - default: - panic("Strange blocksize for partition table\n"); - } - - return ret; -} - static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor) { devfs_handle_t de = NULL; static int first_time = 1; unsigned long first_sector; + struct block_device *bdev; char buf[64]; int i; @@ -287,12 +245,23 @@ static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor printk(KERN_INFO " /dev/%s:", buf + i); else printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf)); - for (i = 0; check_part[i]; i++) - if (check_part[i](hd, dev, first_sector, first_part_minor)) + bdev = bdget(kdev_t_to_nr(dev)); + bdev->bd_inode->i_size = (loff_t)hd->part[MINOR(dev)].nr_sects << 9; + for (i = 0; check_part[i]; i++) { + int res; + res = check_part[i](hd, bdev, first_sector, first_part_minor); + if (res) { + if (res < 0 && warn_no_part) + printk(" unable to read partition table\n"); goto setup_devfs; + } + } printk(" unknown partition table\n"); setup_devfs: + invalidate_bdev(bdev, 1); + truncate_inode_pages(bdev->bd_inode->i_mapping, 0); + bdput(bdev); i = first_part_minor - 1; devfs_register_partitions (hd, i, hd->sizes ? 0 : 1); } @@ -428,3 +397,26 @@ void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size) blk_size[dev->major] = dev->sizes; } } + +unsigned char *read_dev_sector(struct block_device *bdev, unsigned long n, Sector *p) +{ + struct address_space *mapping = bdev->bd_inode->i_mapping; + int sect = PAGE_CACHE_SIZE / 512; + struct page *page; + + page = read_cache_page(mapping, n/sect, + (filler_t *)mapping->a_ops->readpage, NULL); + if (!IS_ERR(page)) { + wait_on_page(page); + if (!Page_Uptodate(page)) + goto fail; + if (PageError(page)) + goto fail; + p->v = page; + return (unsigned char *)page_address(page) + 512 * (n % sect); +fail: + page_cache_release(page); + } + p->v = NULL; + return NULL; +} diff --git a/fs/partitions/check.h b/fs/partitions/check.h index c2dde3a97edf..32d7940469a4 100644 --- a/fs/partitions/check.h +++ b/fs/partitions/check.h @@ -4,9 +4,13 @@ */ void add_gd_partition(struct gendisk *hd, int minor, int start, int size); -/* - * Get the default block size for this device - */ -unsigned int get_ptable_blocksize(kdev_t dev); +typedef struct {struct page *v;} Sector; + +unsigned char *read_dev_sector(struct block_device *, unsigned long, Sector *); + +static inline void put_dev_sector(Sector p) +{ + page_cache_release(p.v); +} extern int warn_no_part; diff --git a/fs/partitions/ibm.c b/fs/partitions/ibm.c index 8e2b6d5da229..cc6e7470eb7f 100644 --- a/fs/partitions/ibm.c +++ b/fs/partitions/ibm.c @@ -42,30 +42,6 @@ static char* part_names[] = { [ibm_partition_lnx1] = "LNX1", [ibm_partition_none] = "(nonl)" }; -static int -get_drive_geometry(int kdev,struct hd_geometry *geo) -{ - struct block_device *bdev = bdget(kdev_t_to_nr(kdev)); - int rc = blkdev_get(bdev, 0, 1, BDEV_FILE); - if ( rc == 0 ) { - rc = ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo); - blkdev_put(bdev, BDEV_FILE); - } - return rc; -} - -static int -get_drive_info(int kdev,dasd_information_t *info) -{ - struct block_device *bdev = bdget(kdev_t_to_nr(kdev)); - int rc = blkdev_get(bdev, 0, 1, BDEV_FILE); - if ( rc == 0 ) { - rc = ioctl_by_bdev(bdev, BIODASDINFO, (unsigned long)(info)); - blkdev_put(bdev, BDEV_FILE); - } - return rc; -} - static ibm_partition_t get_partition_type ( char * type ) { @@ -89,10 +65,8 @@ two_partitions(struct gendisk *hd, int offset, int size) { - add_gd_partition( hd, minor, 0,size); - add_gd_partition( hd, minor + 1, - offset * (blocksize >> 9), - size-offset*(blocksize>>9)); + add_gd_partition( hd, minor, 0, size); + add_gd_partition( hd, minor+1, offset*blocksize, size-offset*blocksize); } @@ -119,10 +93,11 @@ cchhb2blk (cchhb_t *ptr, struct hd_geometry *geo) { } int -ibm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int -first_part_minor) +ibm_partition(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sector, int first_part_minor) { - struct buffer_head *bh, *buf; + Sector sect, sect2; + unsigned char *data; ibm_partition_t partition_type; char type[5] = {0,}; char name[7] = {0,}; @@ -133,40 +108,41 @@ first_part_minor) format1_label_t f1; volume_label_t vlabel; dasd_information_t *info; + kdev_t dev = to_kdev_t(bdev->bd_dev); - if ( first_sector != 0 ) { + if ( first_sector != 0 ) BUG(); - } + info = (struct dasd_information_t *)kmalloc(sizeof(dasd_information_t), GFP_KERNEL); if ( info == NULL ) return 0; - if (get_drive_info (dev,info)) + if (ioctl_by_bdev(bdev, BIODASDINFO, (unsigned long)(info))) return 0; geo = (struct hd_geometry *)kmalloc(sizeof(struct hd_geometry), GFP_KERNEL); if ( geo == NULL ) return 0; - if (get_drive_geometry (dev,geo)) + if (ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo); return 0; blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)]; if ( blocksize <= 0 ) { return 0; } + blocksize >>= 9; - set_blocksize(dev, blocksize); /* OUCH !! */ - if ( ( bh = bread( dev, info->label_block, blocksize) ) != NULL ) { - strncpy ( type,bh -> b_data + 0, 4); - if ((!info->FBA_layout) && (!strcmp(info->type,"ECKD"))) { - - strncpy ( name,bh -> b_data + 8, 6); - } else { - strncpy ( name,bh -> b_data + 4, 6); - } - memcpy (&vlabel, bh->b_data, sizeof(volume_label_t)); - } else { + data = read_dev_sector(bdev, inode->label_block*blocksize, §); + if (!data) return 0; + + strncpy (type, data, 4); + if ((!info->FBA_layout) && (!strcmp(info->type,"ECKD"))) { + strncpy ( name, data + 8, 6); + } else { + strncpy ( name, data + 4, 6); } + memcpy (&vlabel, data, sizeof(volume_label_t)); + EBCASC(type,4); EBCASC(name,6); @@ -174,12 +150,12 @@ first_part_minor) printk ( "%4s/%8s:",part_names[partition_type],name); switch ( partition_type ) { case ibm_partition_cms1: - if (* (((long *)bh->b_data) + 13) != 0) { + if (* ((long *)data + 13) != 0) { /* disk is reserved minidisk */ - long *label=(long*)bh->b_data; - blocksize = label[3]; + long *label=(long*)data; + blocksize = label[3]>>9; offset = label[13]; - size = (label[7]-1)*(blocksize>>9); + size = (label[7]-1)*blocksize; printk ("(MDSK)"); } else { offset = (info->label_block + 1); @@ -199,9 +175,10 @@ first_part_minor) /* get block number and read then first format1 label */ blk = cchhb2blk(&vlabel.vtoc, geo) + 1; - if ((buf = bread( dev, blk, blocksize)) != NULL) { - memcpy (&f1, buf->b_data, sizeof(format1_label_t)); - bforget(buf); + data = read_dev_sector(bdev, blk * blocksize, §2); + if (data) { + memcpy (&f1, data, sizeof(format1_label_t)); + put_dev_sector(sect2); } while (f1.DS1FMTID == _ascebc['1']) { @@ -211,14 +188,14 @@ first_part_minor) counter++; add_gd_partition(hd, MINOR(dev) + counter, - offset * (blocksize >> 9), - psize * (blocksize >> 9)); + offset * blocksize, + psize * blocksize); blk++; - if ((buf = bread( dev, blk, blocksize)) != NULL) { - memcpy (&f1, buf->b_data, - sizeof(format1_label_t)); - bforget(buf); + data = read_dev_sector(bdev, blk * blocksize, §2); + if (data) { + memcpy (&f1, data, sizeof(format1_label_t)); + put_dev_sector(sect2); } } break; @@ -228,6 +205,6 @@ first_part_minor) } printk ( "\n" ); - bforget(bh); + put_dev_sector(sect); return 1; } diff --git a/fs/partitions/ibm.h b/fs/partitions/ibm.h index 49ff10bc45b6..08b05ed151fe 100644 --- a/fs/partitions/ibm.h +++ b/fs/partitions/ibm.h @@ -1 +1 @@ -int ibm_partition(struct gendisk *, kdev_t, unsigned long, int); +int ibm_partition(struct gendisk *, struct block_device *, unsigned long, int); diff --git a/fs/partitions/ldm.c b/fs/partitions/ldm.c index 9da28781cf52..9cef2a18fbd0 100644 --- a/fs/partitions/ldm.c +++ b/fs/partitions/ldm.c @@ -178,10 +178,12 @@ static int parse_vblk(const u8 *buffer, const int buf_size, struct vblk *vb) */ static int create_data_partitions(struct gendisk *hd, const unsigned long first_sector, int first_part_minor, - const kdev_t dev, const struct vmdb *vm, - const struct privhead *ph, const struct ldmdisk *dk) + struct block_device *bdev, const struct vmdb *vm, + const struct privhead *ph, const struct ldmdisk *dk, + unsigned long base) { - struct buffer_head *bh; + Sector sect; + unsigned char *data; struct vblk *vb; int vblk; int vsize; /* VBLK size. */ @@ -192,14 +194,14 @@ static int create_data_partitions(struct gendisk *hd, if (!vb) goto no_mem; vsize = vm->vblk_size; - if (vsize < 1 || vsize > LDM_BLOCKSIZE) + if (vsize < 1 || vsize > 512) goto err_out; - perbuf = LDM_BLOCKSIZE / vsize; - if (perbuf < 1 || LDM_BLOCKSIZE % vsize) + perbuf = 512 / vsize; + if (perbuf < 1 || 512 % vsize) goto err_out; /* 512 == VMDB size */ - lastbuf = (vm->last_vblk_seq - (512 / vsize)) / perbuf; - lastofs = (vm->last_vblk_seq - (512 / vsize)) % perbuf; + lastbuf = vm->last_vblk_seq / perbuf - 1; + lastofs = vm->last_vblk_seq % perbuf; if (lastofs) lastbuf++; if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize > @@ -207,17 +209,18 @@ static int create_data_partitions(struct gendisk *hd, goto err_out; printk(" <"); for (buffer = 0; buffer < lastbuf; buffer++) { - if (!(bh = bread(dev, buffer + OFF_VBLK, LDM_BLOCKSIZE))) + data = read_dev_sector(bdev, base + 2*OFF_VBLK + buffer, §); + if (!data) goto read_err; for (vblk = 0; vblk < perbuf; vblk++) { u8 *block; if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs) break; - block = bh->b_data + vsize * vblk; - if (block + vsize > (u8*)bh->b_data + LDM_BLOCKSIZE) + block = data + vsize * vblk; + if (block + vsize > data + 512) goto brelse_out; - if (parse_vblk(block, LDM_BLOCKSIZE, vb) != 1) + if (parse_vblk(block, vsize, vb) != 1) continue; if (vb->vblk_type != VBLK_PART) continue; @@ -229,7 +232,7 @@ static int create_data_partitions(struct gendisk *hd, vb->num_sectors) == 1) first_part_minor++; } - brelse(bh); + put_dev_sector(sect); } printk(" >\n"); err = 1; @@ -237,7 +240,7 @@ out: kfree(vb); return err; brelse_out: - brelse(bh); + put_dev_sector(sect); goto err_out; no_mem: printk(LDM_CRIT "Not enough memory to allocate required buffers.\n"); @@ -326,10 +329,12 @@ static int get_vstr(const u8 *block, u8 *buffer, const int buflen) * * Return 1 on success and -1 on error, in which case @dk is undefined. */ -static int get_disk_objid(const kdev_t dev, const struct vmdb *vm, - const struct privhead *ph, struct ldmdisk *dk) +static int get_disk_objid(struct block_device *bdev, const struct vmdb *vm, + const struct privhead *ph, struct ldmdisk *dk, + unsigned long base) { - struct buffer_head *bh; + Sector sect; + unsigned char *data; u8 *disk_id; int vblk; int vsize; /* VBLK size. */ @@ -340,21 +345,22 @@ static int get_disk_objid(const kdev_t dev, const struct vmdb *vm, if (!disk_id) goto no_mem; vsize = vm->vblk_size; - if (vsize < 1 || vsize > LDM_BLOCKSIZE) + if (vsize < 1 || vsize > 512) goto err_out; - perbuf = LDM_BLOCKSIZE / vsize; - if (perbuf < 1 || LDM_BLOCKSIZE % vsize) + perbuf = 512 / vsize; + if (perbuf < 1 || 512 % vsize) goto err_out; /* 512 == VMDB size */ - lastbuf = (vm->last_vblk_seq - (512 / vsize)) / perbuf; - lastofs = (vm->last_vblk_seq - (512 / vsize)) % perbuf; + lastbuf = vm->last_vblk_seq / perbuf - 1; + lastofs = vm->last_vblk_seq % perbuf; if (lastofs) lastbuf++; if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize > ph->config_size * 512) goto err_out; for (buffer = 0; buffer < lastbuf; buffer++) { - if (!(bh = bread(dev, buffer + OFF_VBLK, LDM_BLOCKSIZE))) + data = read_dev_sector(bdev, base + 2*OFF_VBLK + buffer, §); + if (!data) goto read_err; for (vblk = 0; vblk < perbuf; vblk++) { int rel_objid, rel_name, delta; @@ -362,20 +368,19 @@ static int get_disk_objid(const kdev_t dev, const struct vmdb *vm, if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs) break; - block = bh->b_data + vblk * vsize; + block = data + vblk * vsize; delta = vblk * vsize + 0x18; - if (delta >= LDM_BLOCKSIZE) + if (delta >= 512) goto brelse_out; if (block[0x13] != VBLK_DISK) continue; /* Calculate relative offsets. */ rel_objid = 1 + block[0x18]; - if (delta + rel_objid >= LDM_BLOCKSIZE) + if (delta + rel_objid >= 512) goto brelse_out; rel_name = 1 + block[0x18 + rel_objid] + rel_objid; - if (delta + rel_name >= LDM_BLOCKSIZE || - delta + rel_name + block[0x18 + rel_name] >= - LDM_BLOCKSIZE) + if (delta + rel_name >= 512 || + delta + rel_name + block[0x18 + rel_name] >= 512) goto brelse_out; err = get_vstr(block + 0x18 + rel_name, disk_id, DISK_ID_SIZE); @@ -383,7 +388,7 @@ static int get_disk_objid(const kdev_t dev, const struct vmdb *vm, goto brelse_out; if (!strncmp(disk_id, ph->disk_id, DISK_ID_SIZE)) { dk->obj_id = get_vnum(block + 0x18, &err); - brelse(bh); + put_dev_sector(sect); if (err) goto out; strncpy(dk->disk_id, ph->disk_id, @@ -393,14 +398,14 @@ static int get_disk_objid(const kdev_t dev, const struct vmdb *vm, goto out; } } - brelse(bh); + put_dev_sector(sect); } err = -1; out: kfree(disk_id); return err; brelse_out: - brelse(bh); + put_dev_sector(sect); goto err_out; no_mem: printk(LDM_CRIT "Not enough memory to allocate required buffers.\n"); @@ -457,17 +462,19 @@ static int parse_vmdb(const u8 *buffer, struct vmdb *vm) * * Return 1 on success and -1 on error, in which case @vm is undefined. */ -static int validate_vmdb(const kdev_t dev, struct vmdb *vm) +static int validate_vmdb(struct block_device *bdev, struct vmdb *vm, unsigned long base) { - struct buffer_head *bh; + Sector sect; + unsigned char *data; int ret; - if (!(bh = bread(dev, OFF_VMDB, LDM_BLOCKSIZE))) { + data = read_dev_sector(bdev, base + OFF_VMDB * 2 + 1, §); + if (!data) { printk(LDM_CRIT "Disk read failed in validate_vmdb.\n"); return -1; } - ret = parse_vmdb(bh->b_data + 0x200, vm); - brelse(bh); + ret = parse_vmdb(data, vm); + put_dev_sector(sect); return ret; } @@ -553,9 +560,12 @@ static int parse_tocblock(const u8 *buffer, struct tocblock *toc) * * Return 1 on success and -1 on error, in which case @toc1 is undefined. */ -static int validate_tocblocks(const kdev_t devdb, struct tocblock *toc1) +static int validate_tocblocks(struct block_device *bdev, + struct tocblock *toc1, + unsigned long base) { - struct buffer_head *bh; + Sector sect; + unsigned char *data; struct tocblock *toc2 = NULL, *toc3 = NULL, *toc4 = NULL; int err; @@ -569,39 +579,43 @@ static int validate_tocblocks(const kdev_t devdb, struct tocblock *toc1) if (!toc4) goto no_mem; /* Read and parse first toc. */ - if (!(bh = bread(devdb, OFF_TOCBLOCK1, LDM_BLOCKSIZE))) { + data = read_dev_sector(bdev, base + OFF_TOCBLOCK1 * 2 + 1, §); + if (!data) { printk(LDM_CRIT "Disk read 1 failed in validate_tocblocks.\n"); goto err_out; } - err = parse_tocblock(bh->b_data + 0x0200, toc1); - brelse(bh); + err = parse_tocblock(data, toc1); + put_dev_sector(sect); if (err != 1) goto out; /* Read and parse second toc. */ - if (!(bh = bread(devdb, OFF_TOCBLOCK2, LDM_BLOCKSIZE))) { + data = read_dev_sector(bdev, base + OFF_TOCBLOCK2 * 2, §); + if (!data) { printk(LDM_CRIT "Disk read 2 failed in validate_tocblocks.\n"); goto err_out; } - err = parse_tocblock(bh->b_data, toc2); - brelse(bh); + err = parse_tocblock(data, toc2); + put_dev_sector(sect); if (err != 1) goto out; /* Read and parse third toc. */ - if (!(bh = bread(devdb, OFF_TOCBLOCK3, LDM_BLOCKSIZE))) { + data = read_dev_sector(bdev, base + OFF_TOCBLOCK3 * 2 + 1, §); + if (!data) { printk(LDM_CRIT "Disk read 3 failed in validate_tocblocks.\n"); goto err_out; } - err = parse_tocblock(bh->b_data + 0x0200, toc3); - brelse(bh); + err = parse_tocblock(data, toc3); + put_dev_sector(sect); if (err != 1) goto out; /* Read and parse fourth toc. */ - if (!(bh = bread(devdb, OFF_TOCBLOCK4, LDM_BLOCKSIZE))) { + data = read_dev_sector(bdev, base + OFF_TOCBLOCK4 * 2, §); + if (!data) { printk(LDM_CRIT "Disk read 4 failed in validate_tocblocks.\n"); goto err_out; } - err = parse_tocblock(bh->b_data, toc4); - brelse(bh); + err = parse_tocblock(data, toc4); + put_dev_sector(sect); if (err != 1) goto out; /* Compare all tocs. */ @@ -665,9 +679,12 @@ static int compare_privheads(const struct privhead *ph1, * * Return 1 on succes and -1 on error. */ -static int validate_privheads(const kdev_t dev, const struct privhead *ph1) +static int validate_privheads(struct block_device *bdev, + const struct privhead *ph1, + unsigned long base) { - struct buffer_head *bh; + Sector sect; + unsigned char *data; struct privhead *ph2 = NULL, *ph3 = NULL; int err; @@ -677,20 +694,22 @@ static int validate_privheads(const kdev_t dev, const struct privhead *ph1) ph3 = (struct privhead*)kmalloc(sizeof(*ph3), GFP_KERNEL); if (!ph3) goto no_mem; - if (!(bh = bread(dev, OFF_PRIVHEAD2, LDM_BLOCKSIZE))) { + data = read_dev_sector(bdev, base + OFF_PRIVHEAD2 * 2, §); + if (!data) { printk(LDM_CRIT "Disk read 1 failed in validate_privheads.\n"); goto err_out; } - err = parse_privhead(bh->b_data, ph2); - brelse(bh); + err = parse_privhead(data, ph2); + put_dev_sector(sect); if (err != 1) goto out; - if (!(bh = bread(dev, OFF_PRIVHEAD3, LDM_BLOCKSIZE))) { + data = read_dev_sector(bdev, base + OFF_PRIVHEAD3 * 2 + 1, §); + if (!data) { printk(LDM_CRIT "Disk read 2 failed in validate_privheads.\n"); goto err_out; } - err = parse_privhead(bh->b_data + 0x0200, ph3); - brelse(bh); + err = parse_privhead(data, ph3); + put_dev_sector(sect); if (err != 1) goto out; err = compare_privheads(ph1, ph2); @@ -807,27 +826,29 @@ static int parse_privhead(const u8 *buffer, struct privhead *ph) * * Return 1 on succes, 0 if device is not a dynamic disk and -1 on error. */ -static int create_db_partition(struct gendisk *hd, const kdev_t dev, +static int create_db_partition(struct gendisk *hd, struct block_device *bdev, const unsigned long first_sector, const int first_part_minor, struct privhead *ph) { - struct buffer_head *bh; + Sector sect; + unsigned char *data; int err; - if (!(bh = bread(dev, OFF_PRIVHEAD1, LDM_BLOCKSIZE))) { + data = read_dev_sector(bdev, OFF_PRIVHEAD1*2, §); + if (!data) { printk(LDM_CRIT __FUNCTION__ "(): Device read failed.\n"); return -1; } - if (BE64(bh->b_data) != MAGIC_PRIVHEAD) { + if (BE64(data) != MAGIC_PRIVHEAD) { ldm_debug("Cannot find PRIVHEAD structure. Not a dynamic disk " "or corrupt LDM database.\n"); return 0; } - err = parse_privhead(bh->b_data, ph); + err = parse_privhead(data, ph); if (err == 1) err = create_partition(hd, first_part_minor, first_sector + ph->config_start, ph->config_size); - brelse(bh); + put_dev_sector(sect); return err; } @@ -842,23 +863,23 @@ static int create_db_partition(struct gendisk *hd, const kdev_t dev, * * Return 1 if @dev is a dynamic disk, 0 if not and -1 on error. */ -static int validate_partition_table(const kdev_t dev) +static int validate_partition_table(struct block_device *bdev) { - struct buffer_head *bh; + Sector sect; + unsigned char *data; struct partition *p; int i, nr_sfs; - if (!(bh = bread(dev, 0, LDM_BLOCKSIZE))) { - if (warn_no_part) - printk(LDM_ERR "Unable to read partition table.\n"); + data = read_dev_sector(bdev, 0, §); + if (!data) return -1; - } - if (*(u16*)(bh->b_data + 0x01FE) != cpu_to_le16(MSDOS_LABEL_MAGIC)) { + + if (*(u16*)(data + 0x01FE) != cpu_to_le16(MSDOS_LABEL_MAGIC)) { ldm_debug("No MS-DOS partition found.\n"); goto no_msdos_partition; } nr_sfs = 0; - p = (struct partition*)(bh->b_data + 0x01BE); + p = (struct partition*)(data + 0x01BE); for (i = 0; i < 4; i++) { if (!SYS_IND(p+i) || SYS_IND(p+i) == WIN2K_EXTENDED_PARTITION) continue; @@ -871,12 +892,12 @@ static int validate_partition_table(const kdev_t dev) if (!nr_sfs) goto not_dynamic_disk; ldm_debug("Parsed partition table successfully.\n"); - brelse(bh); + put_dev_sector(sect); return 1; not_dynamic_disk: ldm_debug("Found basic MS-DOS partition, not a dynamic disk.\n"); no_msdos_partition: - brelse(bh); + put_dev_sector(sect); return 0; } @@ -904,67 +925,54 @@ no_msdos_partition: * 0 if @dev is not a dynamic disk, * -1 if an error occured. */ -int ldm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, - int first_part_minor) +int ldm_partition(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sector, int first_part_minor) { - kdev_t devdb; struct privhead *ph = NULL; struct tocblock *toc = NULL; struct vmdb *vm = NULL; struct ldmdisk *dk = NULL; + unsigned long db_first; int err; if (!hd) return 0; - err = (int)get_ptable_blocksize(dev); - if (err != LDM_BLOCKSIZE) { /* 1024 bytes */ - ldm_debug("Expected a blocksize of %d bytes, got %d instead.\n", - LDM_BLOCKSIZE, get_ptable_blocksize(dev)); - return 0; - } - err = get_hardsect_size(dev); - if (err != 512) { - ldm_debug("Expected a sector size of %d bytes, got %d " - "instead.\n", 512, get_hardsect_size(dev)); - return 0; - } /* Check the partition table. */ - err = validate_partition_table(dev); + err = validate_partition_table(bdev); if (err != 1) return err; if (!(ph = (struct privhead*)kmalloc(sizeof(*ph), GFP_KERNEL))) goto no_mem; /* Create the LDM database device. */ - err = create_db_partition(hd, dev, first_sector, first_part_minor, ph); + err = create_db_partition(hd, bdev, first_sector, first_part_minor, ph); if (err != 1) goto out; - /* For convenience, work with the LDM database device from now on. */ - devdb = MKDEV(MAJOR(dev), first_part_minor); + db_first = hd->part[first_part_minor].start_sect; /* Check the backup privheads. */ - err = validate_privheads(devdb, ph); + err = validate_privheads(bdev, ph, db_first); if (err != 1) goto out; /* Check the table of contents and its backups. */ if (!(toc = (struct tocblock*)kmalloc(sizeof(*toc), GFP_KERNEL))) goto no_mem; - err = validate_tocblocks(devdb, toc); + err = validate_tocblocks(bdev, toc, db_first); if (err != 1) goto out; /* Check the vmdb. */ if (!(vm = (struct vmdb*)kmalloc(sizeof(*vm), GFP_KERNEL))) goto no_mem; - err = validate_vmdb(devdb, vm); + err = validate_vmdb(bdev, vm, db_first); if (err != 1) goto out; /* Find the object id for @dev in the LDM database. */ if (!(dk = (struct ldmdisk*)kmalloc(sizeof(*dk), GFP_KERNEL))) goto no_mem; - err = get_disk_objid(devdb, vm, ph, dk); + err = get_disk_objid(bdev, vm, ph, dk, db_first); if (err != 1) goto out; /* Finally, create the data partition devices. */ err = create_data_partitions(hd, first_sector, first_part_minor + - LDM_FIRST_PART_OFFSET, devdb, vm, ph, dk); + LDM_FIRST_PART_OFFSET, bdev, vm, ph, dk, db_first); if (err == 1) ldm_debug("Parsed LDM database successfully.\n"); out: diff --git a/fs/partitions/ldm.h b/fs/partitions/ldm.h index ee7c60becb84..0404543ec1b2 100644 --- a/fs/partitions/ldm.h +++ b/fs/partitions/ldm.h @@ -144,8 +144,8 @@ struct vblk { u64 num_sectors; }; -int ldm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, - int first_part_minor); +int ldm_partition(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sector, int first_part_minor); #endif /* _FS_PT_LDM_H_ */ diff --git a/fs/partitions/mac.c b/fs/partitions/mac.c index 5c46935c7288..84baad30c812 100644 --- a/fs/partitions/mac.c +++ b/fs/partitions/mac.c @@ -20,7 +20,7 @@ #include "check.h" #include "mac.h" -#ifdef CONFIG_PPC +#ifdef CONFIG_ALL_PPC extern void note_bootable_part(kdev_t dev, int part, int goodness); #endif @@ -36,69 +36,54 @@ static inline void mac_fix_string(char *stg, int len) stg[i] = 0; } -int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec, int first_part_minor) +int mac_partition(struct gendisk *hd, struct block_device *bdev, + unsigned long fsec, int first_part_minor) { - struct buffer_head *bh; + Sector sect; + unsigned char *data; int blk, blocks_in_map; - int dev_bsize, dev_pos, pos; unsigned secsize; -#ifdef CONFIG_PPC +#ifdef CONFIG_ALL_PPC int found_root = 0; int found_root_goodness = 0; #endif struct mac_partition *part; struct mac_driver_desc *md; - dev_bsize = get_ptable_blocksize(dev); - dev_pos = 0; /* Get 0th block and look at the first partition map entry. */ - if ((bh = bread(dev, 0, dev_bsize)) == 0) { - printk("%s: error reading partition table\n", - kdevname(dev)); - return -1; - } - md = (struct mac_driver_desc *) bh->b_data; + md = (struct mac_driver_desc *) read_dev_sector(bdev, 0, §); + if (!md) + return -1; if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC) { - brelse(bh); + put_dev_sector(sect); return 0; } secsize = be16_to_cpu(md->block_size); - if (secsize >= dev_bsize) { - brelse(bh); - dev_pos = secsize; - if ((bh = bread(dev, secsize/dev_bsize, dev_bsize)) == 0) { - printk("%s: error reading Mac partition table\n", - kdevname(dev)); - return -1; - } - } - part = (struct mac_partition *) (bh->b_data + secsize - dev_pos); + put_dev_sector(sect); + data = read_dev_sector(bdev, secsize/512, §); + if (!data) + return -1; + part = (struct mac_partition *) (data + secsize%512); if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) { - brelse(bh); + put_dev_sector(sect); return 0; /* not a MacOS disk */ } printk(" [mac]"); blocks_in_map = be32_to_cpu(part->map_count); for (blk = 1; blk <= blocks_in_map; ++blk) { - pos = blk * secsize; - if (pos >= dev_pos + dev_bsize) { - brelse(bh); - dev_pos = pos; - if ((bh = bread(dev, pos/dev_bsize, dev_bsize)) == 0) { - printk("%s: error reading partition table\n", - kdevname(dev)); - return -1; - } - } - part = (struct mac_partition *) (bh->b_data + pos - dev_pos); + int pos = blk * secsize; + put_dev_sector(sect); + data = read_dev_sector(bdev, pos/512, §); + if (!data) + return -1; + part = (struct mac_partition *) (data + pos%512); if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) break; - blocks_in_map = be32_to_cpu(part->map_count); add_gd_partition(hd, first_part_minor, fsec + be32_to_cpu(part->start_block) * (secsize/512), be32_to_cpu(part->block_count) * (secsize/512)); -#ifdef CONFIG_PPC +#ifdef CONFIG_ALL_PPC /* * If this is the first bootable partition, tell the * setup code, in case it wants to make this the root. @@ -139,15 +124,17 @@ int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec, int first_ found_root_goodness = goodness; } } -#endif /* CONFIG_PPC */ +#endif /* CONFIG_ALL_PPC */ ++first_part_minor; } -#ifdef CONFIG_PPC +#ifdef CONFIG_ALL_PPC if (found_root_goodness) - note_bootable_part(dev, found_root, found_root_goodness); + note_bootable_part(to_kdev_t(bdev->bd_dev), + found_root, found_root_goodness); #endif - brelse(bh); + + put_dev_sector(sect); printk("\n"); return 1; } diff --git a/fs/partitions/mac.h b/fs/partitions/mac.h index 1a3fd68de6e5..9d36ec64983e 100644 --- a/fs/partitions/mac.h +++ b/fs/partitions/mac.h @@ -41,4 +41,4 @@ struct mac_driver_desc { /* ... more stuff */ }; -int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec, int first_part_minor); +int mac_partition(struct gendisk *hd, struct block_device *bdev, unsigned long fsec, int first_part_minor); diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index 52e626ab8459..8777f50178a9 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c @@ -40,8 +40,6 @@ extern void md_autodetect_dev(kdev_t dev); #endif -static int current_minor; - /* * Many architectures don't like unaligned accesses, which is * frequently the case with the nr_sects and start_sect partition @@ -88,7 +86,8 @@ static char __attribute__ ((unused)) #define MSDOS_LABEL_MAGIC2 0xAA static inline int -msdos_magic_present(unsigned char *p) { +msdos_magic_present(unsigned char *p) +{ return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2); } @@ -103,35 +102,38 @@ msdos_magic_present(unsigned char *p) { * only for the actual data partitions. */ -static void extended_partition(struct gendisk *hd, kdev_t dev) +static void extended_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor) { - struct buffer_head *bh; struct partition *p; + Sector sect; + unsigned char *data; unsigned long first_sector, first_size, this_sector, this_size; int mask = (1 << hd->minor_shift) - 1; - int sector_size = get_hardsect_size(dev) / 512; + int sector_size = get_hardsect_size(to_kdev_t(bdev->bd_dev)) / 512; int loopct = 0; /* number of links followed without finding a data partition */ int i; - first_sector = hd->part[MINOR(dev)].start_sect; - first_size = hd->part[MINOR(dev)].nr_sects; + first_sector = hd->part[minor].start_sect; + first_size = hd->part[minor].nr_sects; this_sector = first_sector; while (1) { if (++loopct > 100) return; - if ((current_minor & mask) == 0) + if ((*current_minor & mask) == 0) return; - if (!(bh = bread(dev,0,get_ptable_blocksize(dev)))) + data = read_dev_sector(bdev, this_sector, §); + if (!data) return; - if (!msdos_magic_present(bh->b_data + 510)) - goto done; + if (!msdos_magic_present(data + 510)) + goto done; - p = (struct partition *) (bh->b_data + 0x1be); + p = (struct partition *) (data + 0x1be); - this_size = hd->part[MINOR(dev)].nr_sects; + this_size = hd->part[minor].nr_sects; /* * Usually, the first entry is the real data partition, @@ -146,30 +148,34 @@ static void extended_partition(struct gendisk *hd, kdev_t dev) * First process the data partition(s) */ for (i=0; i<4; i++, p++) { + unsigned long offs, size, next; if (!NR_SECTS(p) || is_extended_partition(p)) continue; /* Check the 3rd and 4th entries - these sometimes contain random garbage */ - if (i >= 2 - && START_SECT(p) + NR_SECTS(p) > this_size - && (this_sector + START_SECT(p) < first_sector || - this_sector + START_SECT(p) + NR_SECTS(p) > - first_sector + first_size)) - continue; + offs = START_SECT(p)*sector_size; + size = NR_SECTS(p)*sector_size; + next = this_sector + offs; + if (i >= 2) { + if (offs + size > this_size) + continue; + if (next < first_sector) + continue; + if (next + size > first_sector + first_size) + continue; + } - add_gd_partition(hd, current_minor, - this_sector+START_SECT(p)*sector_size, - NR_SECTS(p)*sector_size); + add_gd_partition(hd, *current_minor, next, size); #if CONFIG_BLK_DEV_MD if (SYS_IND(p) == LINUX_RAID_PARTITION) { - md_autodetect_dev(MKDEV(hd->major,current_minor)); + md_autodetect_dev(MKDEV(hd->major,*current_minor)); } #endif - current_minor++; + (*current_minor)++; loopct = 0; - if ((current_minor & mask) == 0) + if ((*current_minor & mask) == 0) goto done; } /* @@ -184,61 +190,52 @@ static void extended_partition(struct gendisk *hd, kdev_t dev) */ p -= 4; for (i=0; i<4; i++, p++) - if(NR_SECTS(p) && is_extended_partition(p)) + if (NR_SECTS(p) && is_extended_partition(p)) break; if (i == 4) goto done; /* nothing left to do */ - hd->part[current_minor].nr_sects = NR_SECTS(p) * sector_size; /* JSt */ - hd->part[current_minor].start_sect = first_sector + START_SECT(p) * sector_size; this_sector = first_sector + START_SECT(p) * sector_size; - dev = MKDEV(hd->major, current_minor); - - /* Use bforget(), as we have changed the disk geometry */ - bforget(bh); + minor = *current_minor; + put_dev_sector(sect); } done: - bforget(bh); + put_dev_sector(sect); } -static inline struct buffer_head * -get_partition_table_block(struct gendisk *hd, int minor, int blocknr) { - kdev_t dev = MKDEV(hd->major, minor); - return bread(dev, blocknr, get_ptable_blocksize(dev)); -} - -#ifdef CONFIG_SOLARIS_X86_PARTITION - /* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also indicates linux swap. Be careful before believing this is Solaris. */ static void -solaris_x86_partition(struct gendisk *hd, int minor) { - long offset = hd->part[minor].start_sect; +solaris_x86_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor) +{ - struct buffer_head *bh; +#ifdef CONFIG_SOLARIS_X86_PARTITION + long offset = hd->part[minor].start_sect; + Sector sect; struct solaris_x86_vtoc *v; struct solaris_x86_slice *s; int mask = (1 << hd->minor_shift) - 1; int i; char buf[40]; - if(!(bh = get_partition_table_block(hd, minor, 0))) + v = (struct solaris_x86_vtoc *)read_dev_sector(bdev, offset+1, §); + if (!v) return; - v = (struct solaris_x86_vtoc *)(bh->b_data + 512); - if(le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) { - brelse(bh); + if (le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) { + put_dev_sector(sect); return; } printk(" %s: <solaris:", partition_name(hd, minor, buf)); - if(le32_to_cpu(v->v_version) != 1) { + if (le32_to_cpu(v->v_version) != 1) { printk(" cannot handle version %d vtoc>\n", le32_to_cpu(v->v_version)); - brelse(bh); + put_dev_sector(sect); return; } - for(i=0; i<SOLARIS_X86_NUMSLICE; i++) { - if ((current_minor & mask) == 0) + for (i=0; i<SOLARIS_X86_NUMSLICE; i++) { + if ((*current_minor & mask) == 0) break; s = &v->v_slice[i]; @@ -249,23 +246,25 @@ solaris_x86_partition(struct gendisk *hd, int minor) { * one but add_gd_partition starts relative to sector * zero of the disk. Therefore, must add the offset * of the current partition */ - add_gd_partition(hd, current_minor, le32_to_cpu(s->s_start)+offset, + add_gd_partition(hd, *current_minor, + le32_to_cpu(s->s_start)+offset, le32_to_cpu(s->s_size)); - current_minor++; + (*current_minor)++; } - brelse(bh); + put_dev_sector(sect); printk(" >\n"); -} #endif +} #ifdef CONFIG_BSD_DISKLABEL static void -check_and_add_bsd_partition(struct gendisk *hd, - struct bsd_partition *bsd_p, int minor) { +check_and_add_bsd_partition(struct gendisk *hd, struct bsd_partition *bsd_p, + int minor, int *current_minor) +{ struct hd_struct *lin_p; /* check relative position of partitions. */ for (lin_p = hd->part + 1 + minor; - lin_p - hd->part - minor < current_minor; lin_p++) { + lin_p - hd->part - minor < *current_minor; lin_p++) { /* no relationship -> try again */ if (lin_p->start_sect + lin_p->nr_sects <= le32_to_cpu(bsd_p->p_offset) || lin_p->start_sect >= le32_to_cpu(bsd_p->p_offset) + le32_to_cpu(bsd_p->p_size)) @@ -297,232 +296,290 @@ check_and_add_bsd_partition(struct gendisk *hd, } /* if the bsd partition is not currently known to linux, we end * up here */ - add_gd_partition(hd, current_minor, le32_to_cpu(bsd_p->p_offset), + add_gd_partition(hd, *current_minor, le32_to_cpu(bsd_p->p_offset), le32_to_cpu(bsd_p->p_size)); - current_minor++; + (*current_minor)++; } /* * Create devices for BSD partitions listed in a disklabel, under a * dos-like partition. See extended_partition() for more information. */ -static void bsd_disklabel_partition(struct gendisk *hd, int minor, int type) { - struct buffer_head *bh; +static void do_bsd_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor, char *name, int max_partitions) +{ + long offset = hd->part[minor].start_sect; + Sector sect; struct bsd_disklabel *l; struct bsd_partition *p; - int max_partitions; int mask = (1 << hd->minor_shift) - 1; char buf[40]; - if (!(bh = get_partition_table_block(hd, minor, 0))) + l = (struct bsd_disklabel *)read_dev_sector(bdev, offset+1, §); + if (!l) return; - l = (struct bsd_disklabel *) (bh->b_data+512); if (le32_to_cpu(l->d_magic) != BSD_DISKMAGIC) { - brelse(bh); + put_dev_sector(sect); return; } - printk(" %s:", partition_name(hd, minor, buf)); - printk((type == OPENBSD_PARTITION) ? " <openbsd:" : - (type == NETBSD_PARTITION) ? " <netbsd:" : " <bsd:"); + printk(" %s: <%s", partition_name(hd, minor, buf), name); - max_partitions = ((type == OPENBSD_PARTITION) ? OPENBSD_MAXPARTITIONS - : BSD_MAXPARTITIONS); if (le16_to_cpu(l->d_npartitions) < max_partitions) max_partitions = le16_to_cpu(l->d_npartitions); for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) { - if ((current_minor & mask) == 0) + if ((*current_minor & mask) == 0) break; - - if (p->p_fstype != BSD_FS_UNUSED) - check_and_add_bsd_partition(hd, p, minor); + if (p->p_fstype == BSD_FS_UNUSED) + continue; + check_and_add_bsd_partition(hd, p, minor, current_minor); } + put_dev_sector(sect); + printk(" >\n"); +} +#endif - /* Use bforget(), as we have changed the disk setup */ - bforget(bh); +static void bsd_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor) +{ +#ifdef CONFIG_BSD_DISKLABEL + do_bsd_partition(hd, bdev, minor, current_minor, "bsd", + BSD_MAXPARTITIONS); +#endif +} - printk(" >\n"); +static void netbsd_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor) +{ +#ifdef CONFIG_BSD_DISKLABEL + do_bsd_partition(hd, bdev, minor, current_minor, "netbsd", + BSD_MAXPARTITIONS); +#endif } + +static void openbsd_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor) +{ +#ifdef CONFIG_BSD_DISKLABEL + do_bsd_partition(hd, bdev, minor, current_minor, + "openbsd", OPENBSD_MAXPARTITIONS); #endif +} -#ifdef CONFIG_UNIXWARE_DISKLABEL /* * Create devices for Unixware partitions listed in a disklabel, under a * dos-like partition. See extended_partition() for more information. */ -static void unixware_partition(struct gendisk *hd, int minor) { - struct buffer_head *bh; +static void unixware_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor) +{ +#ifdef CONFIG_UNIXWARE_DISKLABEL + long offset = hd->part[minor].start_sect; + Sector sect; struct unixware_disklabel *l; struct unixware_slice *p; int mask = (1 << hd->minor_shift) - 1; char buf[40]; - if (!(bh = get_partition_table_block(hd, minor, 14))) + l = (struct unixware_disklabel *)read_dev_sector(bdev, offset+29, §); + if (!l) return; - l = (struct unixware_disklabel *) (bh->b_data+512); if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC || le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) { - brelse(bh); + put_dev_sector(sect); return; } printk(" %s: <unixware:", partition_name(hd, minor, buf)); p = &l->vtoc.v_slice[1]; /* I omit the 0th slice as it is the same as whole disk. */ while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) { - if ((current_minor & mask) == 0) + if ((*current_minor & mask) == 0) break; if (p->s_label != UNIXWARE_FS_UNUSED) { - add_gd_partition(hd, current_minor, START_SECT(p), + add_gd_partition(hd, *current_minor, START_SECT(p), NR_SECTS(p)); - current_minor++; + (*current_minor)++; } p++; } - /* Use bforget, as we have changed the disk setup */ - bforget(bh); + put_dev_sector(sect); printk(" >\n"); -} #endif +} -#ifdef CONFIG_MINIX_SUBPARTITION /* * Minix 2.0.0/2.0.2 subpartition support. * Anand Krishnamurthy <anandk@wiproge.med.ge.com> * Rajeev V. Pillai <rajeevvp@yahoo.com> */ -static void minix_partition(struct gendisk *hd, int minor) +static void minix_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor) { - struct buffer_head *bh; +#ifdef CONFIG_MINIX_SUBPARTITION + long offset = hd->part[minor].start_sect; + Sector sect; + unsigned char *data; struct partition *p; int mask = (1 << hd->minor_shift) - 1; int i; char buf[40]; - if (!(bh = get_partition_table_block(hd, minor, 0))) + data = read_dev_sector(bdev, offset, §); + if (!data) return; - bh->b_state = 0; - p = (struct partition *)(bh->b_data + 0x1be); + p = (struct partition *)(data + 0x1be); /* The first sector of a Minix partition can have either * a secondary MBR describing its subpartitions, or * the normal boot sector. */ - if (msdos_magic_present (bh->b_data + 510) && + if (msdos_magic_present (data + 510) && SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */ printk(" %s: <minix:", partition_name(hd, minor, buf)); for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) { - if ((current_minor & mask) == 0) + if ((*current_minor & mask) == 0) break; /* add each partition in use */ if (SYS_IND(p) == MINIX_PARTITION) { - add_gd_partition(hd, current_minor, + add_gd_partition(hd, *current_minor, START_SECT(p), NR_SECTS(p)); - current_minor++; + (*current_minor)++; } } printk(" >\n"); } - brelse(bh); -} + put_dev_sector(sect); #endif /* CONFIG_MINIX_SUBPARTITION */ - -int msdos_partition(struct gendisk *hd, kdev_t dev, - unsigned long first_sector, int first_part_minor) { - int i, minor = current_minor = first_part_minor; - struct buffer_head *bh; - struct partition *p; - unsigned char *data; - int mask = (1 << hd->minor_shift) - 1; - int sector_size = get_hardsect_size(dev) / 512; -#ifdef CONFIG_BLK_DEV_IDE - int tested_for_xlate = 0; +} -read_mbr: -#endif /* CONFIG_BLK_DEV_IDE */ - if (!(bh = bread(dev,0,get_ptable_blocksize(dev)))) { - if (warn_no_part) printk(" unable to read partition table\n"); - return -1; - } - data = bh->b_data; +static struct { + unsigned char id; + void (*parse)(struct gendisk *, struct block_device *, int, int *); +} subtypes[] = { + {BSD_PARTITION, bsd_partition}, + {NETBSD_PARTITION, netbsd_partition}, + {OPENBSD_PARTITION, openbsd_partition}, + {MINIX_PARTITION, minix_partition}, + {UNIXWARE_PARTITION, unixware_partition}, + {SOLARIS_X86_PARTITION, solaris_x86_partition}, + {0, NULL}, +}; +/* + * Look for various forms of IDE disk geometry translation + */ +static int handle_ide_mess(struct block_device *bdev) +{ #ifdef CONFIG_BLK_DEV_IDE -check_table: -#endif /* CONFIG_BLK_DEV_IDE */ - /* Use bforget(), because we may have changed the disk geometry */ + Sector sect; + unsigned char *data; + kdev_t dev = to_kdev_t(bdev->bd_dev); + unsigned int sig; + int heads = 0; + struct partition *p; + int i; + /* + * The i386 partition handling programs very often + * make partitions end on cylinder boundaries. + * There is no need to do so, and Linux fdisk doesnt always + * do this, and Windows NT on Alpha doesnt do this either, + * but still, this helps to guess #heads. + */ + data = read_dev_sector(bdev, 0, §); + if (!data) + return -1; if (!msdos_magic_present(data + 510)) { - bforget(bh); + put_dev_sector(sect); return 0; } + sig = le16_to_cpu(*(unsigned short *)(data + 2)); p = (struct partition *) (data + 0x1be); + for (i = 0; i < 4; i++) { + struct partition *q = &p[i]; + if (NR_SECTS(q)) { + if ((q->sector & 63) == 1 && + (q->end_sector & 63) == 63) + heads = q->end_head + 1; + break; + } + } + if (SYS_IND(p) == EZD_PARTITION) { + /* + * Accesses to sector 0 must go to sector 1 instead. + */ + if (ide_xlate_1024(dev, -1, heads, " [EZD]")) + goto reread; + } else if (SYS_IND(p) == DM6_PARTITION) { -#ifdef CONFIG_BLK_DEV_IDE - if (!tested_for_xlate++) { /* Do this only once per disk */ /* - * Look for various forms of IDE disk geometry translation + * Everything on the disk is offset by 63 sectors, + * including a "new" MBR with its own partition table. */ - unsigned int sig = le16_to_cpu(*(unsigned short *)(data + 2)); - int heads = 0; + if (ide_xlate_1024(dev, 1, heads, " [DM6:DDO]")) + goto reread; + } else if (sig <= 0x1ae && + data[sig] == 0xAA && data[sig+1] == 0x55 && + (data[sig+2] & 1)) { + /* DM6 signature in MBR, courtesy of OnTrack */ + (void) ide_xlate_1024 (dev, 0, heads, " [DM6:MBR]"); + } else if (SYS_IND(p) == DM6_AUX1PARTITION || + SYS_IND(p) == DM6_AUX3PARTITION) { /* - * The i386 partition handling programs very often - * make partitions end on cylinder boundaries. - * There is no need to do so, and Linux fdisk doesnt always - * do this, and Windows NT on Alpha doesnt do this either, - * but still, this helps to guess #heads. + * DM6 on other than the first (boot) drive */ - for (i = 0; i < 4; i++) { - struct partition *q = &p[i]; - if (NR_SECTS(q)) { - if ((q->sector & 63) == 1 && - (q->end_sector & 63) == 63) - heads = q->end_head + 1; - break; - } - } - if (SYS_IND(p) == EZD_PARTITION) { - /* - * Accesses to sector 0 must go to sector 1 instead. - */ - if (ide_xlate_1024(dev, -1, heads, " [EZD]")) { - data += 512; - goto check_table; - } - } else if (SYS_IND(p) == DM6_PARTITION) { - - /* - * Everything on the disk is offset by 63 sectors, - * including a "new" MBR with its own partition table. - */ - if (ide_xlate_1024(dev, 1, heads, " [DM6:DDO]")) { - bforget(bh); - goto read_mbr; /* start over with new MBR */ - } - } else if (sig <= 0x1ae && - data[sig] == 0xAA && data[sig+1] == 0x55 && - (data[sig+2] & 1)) { - /* DM6 signature in MBR, courtesy of OnTrack */ - (void) ide_xlate_1024 (dev, 0, heads, " [DM6:MBR]"); - } else if (SYS_IND(p) == DM6_AUX1PARTITION || - SYS_IND(p) == DM6_AUX3PARTITION) { - /* - * DM6 on other than the first (boot) drive - */ - (void) ide_xlate_1024(dev, 0, heads, " [DM6:AUX]"); - } else { - (void) ide_xlate_1024(dev, 2, heads, " [PTBL]"); - } + (void) ide_xlate_1024(dev, 0, heads, " [DM6:AUX]"); + } else { + (void) ide_xlate_1024(dev, 2, heads, " [PTBL]"); } + put_dev_sector(sect); + return 1; + +reread: + put_dev_sector(sect); + /* Flush the cache */ + invalidate_bdev(bdev, 1); + truncate_inode_pages(bdev->bd_inode->i_mapping, 0); #endif /* CONFIG_BLK_DEV_IDE */ + return 1; +} + +int msdos_partition(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sector, int first_part_minor) +{ + int i, minor = first_part_minor; + Sector sect; + struct partition *p; + unsigned char *data; + int mask = (1 << hd->minor_shift) - 1; + int sector_size = get_hardsect_size(to_kdev_t(bdev->bd_dev)) / 512; + int current_minor = first_part_minor; + int err; + + err = handle_ide_mess(bdev); + if (err <= 0) + return err; + data = read_dev_sector(bdev, 0, §); + if (!data) + return -1; + if (!msdos_magic_present(data + 510)) { + put_dev_sector(sect); + return 0; + } + p = (struct partition *) (data + 0x1be); - /* Look for partitions in two passes: - First find the primary partitions, and the DOS-type extended partitions. - On the second pass look inside *BSD and Unixware and Solaris partitions. */ + /* + * Look for partitions in two passes: + * First find the primary and DOS-type extended partitions. + * On the second pass look inside *BSD, Unixware and Solaris partitions. + */ - current_minor += 4; /* first "extra" minor (for extended partitions) */ + current_minor += 4; for (i=1 ; i<=4 ; minor++,i++,p++) { if (!NR_SECTS(p)) continue; - add_gd_partition(hd, minor, first_sector+START_SECT(p)*sector_size, - NR_SECTS(p)*sector_size); + add_gd_partition(hd, minor, + first_sector+START_SECT(p)*sector_size, + NR_SECTS(p)*sector_size); #if CONFIG_BLK_DEV_MD if (SYS_IND(p) == LINUX_RAID_PARTITION) { md_autodetect_dev(MKDEV(hd->major,minor)); @@ -530,20 +587,12 @@ check_table: #endif if (is_extended_partition(p)) { printk(" <"); - /* - * If we are rereading the partition table, we need - * to set the size of the partition so that we will - * be able to bread the block containing the extended - * partition info. - */ - hd->sizes[minor] = hd->part[minor].nr_sects - >> (BLOCK_SIZE_BITS - 9); - extended_partition(hd, MKDEV(hd->major, minor)); - printk(" >"); /* prevent someone doing mkfs or mkswap on an extended partition, but leave room for LILO */ if (hd->part[minor].nr_sects > 2) hd->part[minor].nr_sects = 2; + extended_partition(hd, bdev, minor, ¤t_minor); + printk(" >"); } } @@ -567,29 +616,18 @@ check_table: minor -= 4; p = (struct partition *) (0x1be + data); for (i=1 ; i<=4 ; minor++,i++,p++) { + unsigned char id = SYS_IND(p); + int n; + if (!NR_SECTS(p)) continue; -#ifdef CONFIG_BSD_DISKLABEL - if (SYS_IND(p) == BSD_PARTITION || - SYS_IND(p) == NETBSD_PARTITION || - SYS_IND(p) == OPENBSD_PARTITION) - bsd_disklabel_partition(hd, minor, SYS_IND(p)); -#endif -#ifdef CONFIG_MINIX_SUBPARTITION - if (SYS_IND(p) == MINIX_PARTITION) { - minix_partition(hd, minor); - } -#endif -#ifdef CONFIG_UNIXWARE_DISKLABEL - if (SYS_IND(p) == UNIXWARE_PARTITION) - unixware_partition(hd, minor); -#endif -#ifdef CONFIG_SOLARIS_X86_PARTITION - if(SYS_IND(p) == SOLARIS_X86_PARTITION) - solaris_x86_partition(hd, minor); -#endif - } - bforget(bh); + for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++) + ; + + if (subtypes[n].parse) + subtypes[n].parse(hd, bdev, minor, ¤t_minor); + } + put_dev_sector(sect); return 1; } diff --git a/fs/partitions/msdos.h b/fs/partitions/msdos.h index e24740c5e031..09c8b095ad56 100644 --- a/fs/partitions/msdos.h +++ b/fs/partitions/msdos.h @@ -4,6 +4,6 @@ #define MSDOS_LABEL_MAGIC 0xAA55 -int msdos_partition(struct gendisk *hd, kdev_t dev, +int msdos_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int first_part_minor); diff --git a/fs/partitions/osf.c b/fs/partitions/osf.c index 52aae3bbd6ba..e178ca2b6543 100644 --- a/fs/partitions/osf.c +++ b/fs/partitions/osf.c @@ -17,12 +17,13 @@ #include "check.h" #include "osf.h" -int osf_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, - int current_minor) +int osf_partition(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sector, int current_minor) { int i; + Sector sect; + unsigned char *data; int mask = (1 << hd->minor_shift) - 1; - struct buffer_head *bh; struct disklabel { u32 d_magic; u16 d_type,d_subtype; @@ -56,18 +57,18 @@ int osf_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, } * label; struct d_partition * partition; - if (!(bh = bread(dev,0,get_ptable_blocksize(dev)))) { - if (warn_no_part) printk("unable to read partition table\n"); + data = read_dev_sector(bdev, 0, §); + if (!data) return -1; - } - label = (struct disklabel *) (bh->b_data+64); + + label = (struct disklabel *) (data+64); partition = label->d_partitions; if (le32_to_cpu(label->d_magic) != DISKLABELMAGIC) { - brelse(bh); + put_dev_sector(sect); return 0; } if (le32_to_cpu(label->d_magic2) != DISKLABELMAGIC) { - brelse(bh); + put_dev_sector(sect); return 0; } for (i = 0 ; i < le16_to_cpu(label->d_npartitions); i++, partition++) { @@ -80,7 +81,7 @@ int osf_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, current_minor++; } printk("\n"); - brelse(bh); + put_dev_sector(sect); return 1; } diff --git a/fs/partitions/osf.h b/fs/partitions/osf.h index ce14150565b9..6f02393c490b 100644 --- a/fs/partitions/osf.h +++ b/fs/partitions/osf.h @@ -4,6 +4,6 @@ #define DISKLABELMAGIC (0x82564557UL) -int osf_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, - int current_minor); +int osf_partition(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sector, int current_minor); diff --git a/fs/partitions/sgi.c b/fs/partitions/sgi.c index 3806b5f31afb..ea74ebb4b57b 100644 --- a/fs/partitions/sgi.c +++ b/fs/partitions/sgi.c @@ -17,11 +17,12 @@ #include "check.h" #include "sgi.h" -int sgi_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int current_minor) +int sgi_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int current_minor) { int i, csum, magic; unsigned int *ui, start, blocks, cs; - struct buffer_head *bh; + Sector sect; + kdev_t dev = to_kdev_t(bdev->bd_dev); struct sgi_disklabel { int magic_mushroom; /* Big fat spliff... */ short root_part_num; /* Root partition number */ @@ -43,17 +44,15 @@ int sgi_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, in } *label; struct sgi_partition *p; - if(!(bh = bread(dev, 0, get_ptable_blocksize(dev)))) { - if (warn_no_part) printk(KERN_WARNING "Dev %s: unable to read partition table\n", kdevname(dev)); + label = (struct sgi_disklabel *) read_dev_sector(bdev, 0, §); + if (!label) return -1; - } - label = (struct sgi_disklabel *) bh->b_data; p = &label->partitions[0]; magic = label->magic_mushroom; if(be32_to_cpu(magic) != SGI_LABEL_MAGIC) { /*printk("Dev %s SGI disklabel: bad magic %08x\n", - kdevname(dev), magic);*/ - brelse(bh); + bdevname(dev), magic);*/ + put_dev_sector(sect); return 0; } ui = ((unsigned int *) (label + 1)) - 1; @@ -63,8 +62,8 @@ int sgi_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, in } if(csum) { printk(KERN_WARNING "Dev %s SGI disklabel: csum bad, label corrupted\n", - kdevname(dev)); - brelse(bh); + bdevname(dev)); + put_dev_sector(sect); return 0; } /* All SGI disk labels have 16 partitions, disks under Linux only @@ -81,6 +80,6 @@ int sgi_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, in current_minor++; } printk("\n"); - brelse(bh); + put_dev_sector(sect); return 1; } diff --git a/fs/partitions/sgi.h b/fs/partitions/sgi.h index 6e4ac1ac488f..55840d9285e5 100644 --- a/fs/partitions/sgi.h +++ b/fs/partitions/sgi.h @@ -2,7 +2,7 @@ * fs/partitions/sgi.h */ -extern int sgi_partition(struct gendisk *hd, kdev_t dev, +extern int sgi_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int first_part_minor); #define SGI_LABEL_MAGIC 0x0be5a941 diff --git a/fs/partitions/sun.c b/fs/partitions/sun.c index f48bc5cd8c5c..bee5abb6537b 100644 --- a/fs/partitions/sun.c +++ b/fs/partitions/sun.c @@ -19,11 +19,12 @@ #include "check.h" #include "sun.h" -int sun_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int first_part_minor) +int sun_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int first_part_minor) { int i, csum; unsigned short *ush; - struct buffer_head *bh; + Sector sect; + kdev_t dev = to_kdev_t(bdev->bd_dev); struct sun_disklabel { unsigned char info[128]; /* Informative text string */ unsigned char spare[292]; /* Boot information etc. */ @@ -47,27 +48,25 @@ int sun_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, in struct sun_partition *p; unsigned long spc; - if(!(bh = bread(dev, 0, get_ptable_blocksize(dev)))) { - if (warn_no_part) printk(KERN_WARNING "Dev %s: unable to read partition table\n", - kdevname(dev)); + label = (struct sun_disklabel *)read_dev_sector(bdev, 0, §); + if (!label) return -1; - } - label = (struct sun_disklabel *) bh->b_data; + p = label->partitions; if (be16_to_cpu(label->magic) != SUN_LABEL_MAGIC) { /* printk(KERN_INFO "Dev %s Sun disklabel: bad magic %04x\n", - kdevname(dev), be16_to_cpu(label->magic)); */ - brelse(bh); + bdevname(dev), be16_to_cpu(label->magic)); */ + put_dev_sector(sect); return 0; } /* Look at the checksum */ ush = ((unsigned short *) (label+1)) - 1; - for(csum = 0; ush >= ((unsigned short *) label);) + for (csum = 0; ush >= ((unsigned short *) label);) csum ^= *ush--; if(csum) { printk("Dev %s Sun disklabel: Csum bad, label corrupted\n", - kdevname(dev)); - brelse(bh); + bdevname(dev)); + put_dev_sector(sect); return 0; } /* All Sun disks have 8 partition entries */ @@ -83,7 +82,6 @@ int sun_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, in first_part_minor++; } printk("\n"); - brelse(bh); + put_dev_sector(sect); return 1; } - diff --git a/fs/partitions/sun.h b/fs/partitions/sun.h index 3426d4aa29fc..ae2f9579ef87 100644 --- a/fs/partitions/sun.h +++ b/fs/partitions/sun.h @@ -4,6 +4,6 @@ #define SUN_LABEL_MAGIC 0xDABE -int sun_partition(struct gendisk *hd, kdev_t dev, +int sun_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int first_part_minor); diff --git a/fs/partitions/ultrix.c b/fs/partitions/ultrix.c index aa49ba517fd8..a7e0629dd2da 100644 --- a/fs/partitions/ultrix.c +++ b/fs/partitions/ultrix.c @@ -14,11 +14,12 @@ #include "check.h" -int ultrix_partition(struct gendisk *hd, kdev_t dev, +int ultrix_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int first_part_minor) { int i; - struct buffer_head *bh; + Sector sect; + unsigned char *data; struct ultrix_disklabel { s32 pt_magic; /* magic no. indicating part. info exits */ s32 pt_valid; /* set by driver if pt is current */ @@ -31,18 +32,11 @@ int ultrix_partition(struct gendisk *hd, kdev_t dev, #define PT_MAGIC 0x032957 /* Partition magic number */ #define PT_VALID 1 /* Indicates if struct is valid */ -#define SBLOCK ((unsigned long)((16384 - sizeof(struct ultrix_disklabel)) \ - /get_ptable_blocksize(dev))) - - bh = bread (dev, SBLOCK, get_ptable_blocksize(dev)); - if (!bh) { - if (warn_no_part) printk (" unable to read block 0x%lx\n", SBLOCK); + data = read_dev_sector(bdev, (16384 - sizeof(*label))/512, §); + if (!data) return -1; - } - label = (struct ultrix_disklabel *)(bh->b_data - + get_ptable_blocksize(dev) - - sizeof(struct ultrix_disklabel)); + label = (struct ultrix_disklabel *)(data + 512 - sizeof(*label)); if (label->pt_magic == PT_MAGIC && label->pt_valid == PT_VALID) { for (i=0; i<8; i++, first_part_minor++) @@ -50,11 +44,11 @@ int ultrix_partition(struct gendisk *hd, kdev_t dev, add_gd_partition(hd, first_part_minor, label->pt_part[i].pi_blkoff, label->pt_part[i].pi_nblocks); - brelse(bh); + put_dev_sector(sect); printk ("\n"); return 1; } else { - brelse(bh); + put_dev_sector(sect); return 0; } } diff --git a/fs/partitions/ultrix.h b/fs/partitions/ultrix.h index d2259db3e917..1572c90d90be 100644 --- a/fs/partitions/ultrix.h +++ b/fs/partitions/ultrix.h @@ -2,6 +2,6 @@ * fs/partitions/ultrix.h */ -int ultrix_partition(struct gendisk *hd, kdev_t dev, +int ultrix_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int first_part_minor); diff --git a/fs/smbfs/ChangeLog b/fs/smbfs/ChangeLog index cf9e3ffc5c67..63ecf3d06caf 100644 --- a/fs/smbfs/ChangeLog +++ b/fs/smbfs/ChangeLog @@ -1,5 +1,30 @@ ChangeLog for smbfs. +2001-09-17 Urban Widmark <urban@teststation.com> + + * proc.c: Use 4096 (was 512) as the blocksize for better write + performance (patch originally by Jan Kratochvil) + * proc.c: Skip disconnect smb, allows umount on unreachable servers. + * proc.c: Go back to the interruptible sleep as reconnects seem to + handle it now. + * *.c: use autogenerated and private proto.h + +2000-11-22 Igor Zhbanov <bsg@uniyar.ac.ru> + + * proc.c: fixed date_unix2dos for dates earlier than 01/01/1980 + and date_dos2unix for date==0 (from 2.2) + +2001-07-13 Rob Radez <rob@osinvestor.com> + + * proc.c: make smb_errno return negative error values + +2001-07-09 Jochen Dolze <dolze@epcnet.de> + + * inode.c: smb_statfs always returned success. + * proc.c, ioctl.c: Allow smbmount to signal failure to reconnect with + a NULL argument to SMB_IOC_NEWCONN (speeds up error detection). + * proc.c: Add some of the missing error codes to smb_errno + 2001-06-12 Urban Widmark <urban@teststation.com> * proc.c: replace the win95-flush fix with smb_seek, when needed. diff --git a/fs/smbfs/Makefile b/fs/smbfs/Makefile index 16e8ceb15d5a..93ddc0df84f2 100644 --- a/fs/smbfs/Makefile +++ b/fs/smbfs/Makefile @@ -23,3 +23,19 @@ EXTRA_CFLAGS += -DSMBFS_PARANOIA #EXTRA_CFLAGS += -Werror include $(TOPDIR)/Rules.make + +# +# Maintainer rules +# + +# getopt.c not included. It is intentionally separate +SRC = proc.c dir.c cache.c sock.c inode.c file.c ioctl.c + +proto: + -rm -f proto.h + @echo > proto2.h "/*" + @echo >> proto2.h " * Autogenerated with cproto on: " `date` + @echo >> proto2.h " */" + @echo >> proto2.h "" + cproto -E "gcc -E" -e -v -I $(TOPDIR)/include -DMAKING_PROTO -D__KERNEL__ $(SRC) >> proto2.h + mv proto2.h proto.h diff --git a/fs/smbfs/cache.c b/fs/smbfs/cache.c index 3dc17d2292e3..3e98f83ab19f 100644 --- a/fs/smbfs/cache.c +++ b/fs/smbfs/cache.c @@ -20,6 +20,7 @@ #include <asm/page.h> #include "smb_debug.h" +#include "proto.h" /* * Force the next attempt to use the cache to be a timeout. diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c index 48d716c9e3a8..5696c8e2fbe7 100644 --- a/fs/smbfs/dir.c +++ b/fs/smbfs/dir.c @@ -18,6 +18,7 @@ #include <linux/smbno.h> #include "smb_debug.h" +#include "proto.h" static int smb_readdir(struct file *, void *, filldir_t); static int smb_dir_open(struct inode *, struct file *); @@ -452,8 +453,7 @@ smb_instantiate(struct dentry *dentry, __u16 fileid, int have_id) if (!inode) goto out_no_inode; - if (have_id) - { + if (have_id) { inode->u.smbfs_i.fileid = fileid; inode->u.smbfs_i.access = SMB_O_RDWR; inode->u.smbfs_i.open = server->generation; @@ -465,8 +465,7 @@ out: out_no_inode: error = -EACCES; out_close: - if (have_id) - { + if (have_id) { PARANOIA("%s/%s failed, error=%d, closing %u\n", DENTRY_PATH(dentry), error, fileid); smb_close_fileid(dentry, fileid); @@ -562,12 +561,10 @@ smb_rename(struct inode *old_dir, struct dentry *old_dentry, */ if (old_dentry->d_inode) smb_close(old_dentry->d_inode); - if (new_dentry->d_inode) - { + if (new_dentry->d_inode) { smb_close(new_dentry->d_inode); error = smb_proc_unlink(new_dentry); - if (error) - { + if (error) { VERBOSE("unlink %s/%s, error=%d\n", DENTRY_PATH(new_dentry), error); goto out; @@ -579,8 +576,7 @@ smb_rename(struct inode *old_dir, struct dentry *old_dentry, smb_invalid_dir_cache(old_dir); smb_invalid_dir_cache(new_dir); error = smb_proc_mv(old_dentry, new_dentry); - if (!error) - { + if (!error) { smb_renew_times(old_dentry); smb_renew_times(new_dentry); } diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c index 189828846025..d74e32ad6bf5 100644 --- a/fs/smbfs/file.c +++ b/fs/smbfs/file.c @@ -24,6 +24,7 @@ #include <linux/smb_fs.h> #include "smb_debug.h" +#include "proto.h" static int smb_fsync(struct file *file, struct dentry * dentry, int datasync) diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 348e5acad771..9f5921c18fb5 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -32,6 +32,7 @@ #include "smb_debug.h" #include "getopt.h" +#include "proto.h" /* Always pick a default string */ #ifdef CONFIG_SMB_NLS_REMOTE @@ -259,7 +260,7 @@ smb_delete_inode(struct inode *ino) } /* FIXME: flags and has_arg could probably be merged. */ -struct option opts[] = { +static struct option opts[] = { { "version", 1, 0, 'v' }, { "win95", 0, SMB_MOUNT_WIN95, 1 }, { "oldattr", 0, SMB_MOUNT_OLDATTR, 1 }, @@ -344,7 +345,6 @@ smb_put_super(struct super_block *sb) struct smb_sb_info *server = &(sb->u.smbfs_sb); if (server->sock_file) { - smb_proc_disconnect(server); smb_dont_catch_keepalive(server); fput(server->sock_file); } @@ -353,23 +353,24 @@ smb_put_super(struct super_block *sb) kill_proc(server->conn_pid, SIGTERM, 1); smb_kfree(server->mnt); - smb_kfree(sb->u.smbfs_sb.temp_buf); + smb_kfree(server->temp_buf); if (server->packet) smb_vfree(server->packet); - if(sb->u.smbfs_sb.remote_nls) { - unload_nls(sb->u.smbfs_sb.remote_nls); - sb->u.smbfs_sb.remote_nls = NULL; + if (server->remote_nls) { + unload_nls(server->remote_nls); + server->remote_nls = NULL; } - if(sb->u.smbfs_sb.local_nls) { - unload_nls(sb->u.smbfs_sb.local_nls); - sb->u.smbfs_sb.local_nls = NULL; + if (server->local_nls) { + unload_nls(server->local_nls); + server->local_nls = NULL; } } struct super_block * smb_read_super(struct super_block *sb, void *raw_data, int silent) { + struct smb_sb_info *server = &sb->u.smbfs_sb; struct smb_mount_data_kernel *mnt; struct smb_mount_data *oldmnt; struct inode *root_inode; @@ -389,34 +390,34 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent) sb->s_magic = SMB_SUPER_MAGIC; sb->s_op = &smb_sops; - sb->u.smbfs_sb.mnt = NULL; - sb->u.smbfs_sb.sock_file = NULL; - init_MUTEX(&sb->u.smbfs_sb.sem); - init_waitqueue_head(&sb->u.smbfs_sb.wait); - sb->u.smbfs_sb.conn_pid = 0; - sb->u.smbfs_sb.state = CONN_INVALID; /* no connection yet */ - sb->u.smbfs_sb.generation = 0; - sb->u.smbfs_sb.packet_size = smb_round_length(SMB_INITIAL_PACKET_SIZE); - sb->u.smbfs_sb.packet = smb_vmalloc(sb->u.smbfs_sb.packet_size); - if (!sb->u.smbfs_sb.packet) + server->mnt = NULL; + server->sock_file = NULL; + init_MUTEX(&server->sem); + init_waitqueue_head(&server->wait); + server->conn_pid = 0; + server->state = CONN_INVALID; /* no connection yet */ + server->generation = 0; + server->packet_size = smb_round_length(SMB_INITIAL_PACKET_SIZE); + server->packet = smb_vmalloc(server->packet_size); + if (!server->packet) goto out_no_mem; /* Allocate the global temp buffer */ - sb->u.smbfs_sb.temp_buf = smb_kmalloc(2*SMB_MAXPATHLEN+20, GFP_KERNEL); - if (!sb->u.smbfs_sb.temp_buf) + server->temp_buf = smb_kmalloc(2*SMB_MAXPATHLEN+20, GFP_KERNEL); + if (!server->temp_buf) goto out_no_temp; /* Setup NLS stuff */ - sb->u.smbfs_sb.remote_nls = NULL; - sb->u.smbfs_sb.local_nls = NULL; - sb->u.smbfs_sb.name_buf = sb->u.smbfs_sb.temp_buf + SMB_MAXPATHLEN + 20; + server->remote_nls = NULL; + server->local_nls = NULL; + server->name_buf = server->temp_buf + SMB_MAXPATHLEN + 20; /* Allocate the mount data structure */ /* FIXME: merge this with the other malloc and get a whole page? */ mnt = smb_kmalloc(sizeof(struct smb_mount_data_kernel), GFP_KERNEL); if (!mnt) goto out_no_mount; - sb->u.smbfs_sb.mnt = mnt; + server->mnt = mnt; memset(mnt, 0, sizeof(struct smb_mount_data_kernel)); strncpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT, @@ -447,9 +448,7 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent) mnt->mounted_uid = current->uid; } - smb_setcodepage(&sb->u.smbfs_sb, &mnt->codepage); - if (!sb->u.smbfs_sb.convert) - PARANOIA("convert funcptr was NULL!\n"); + smb_setcodepage(server, &mnt->codepage); /* * Display the enabled options @@ -463,7 +462,7 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent) /* * Keep the super block locked while we get the root inode. */ - smb_init_root_dirent(&(sb->u.smbfs_sb), &root); + smb_init_root_dirent(server, &root); root_inode = smb_iget(sb, &root); if (!root_inode) goto out_no_root; @@ -478,13 +477,13 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent) out_no_root: iput(root_inode); out_bad_option: - smb_kfree(sb->u.smbfs_sb.mnt); + smb_kfree(server->mnt); out_no_mount: - smb_kfree(sb->u.smbfs_sb.temp_buf); + smb_kfree(server->temp_buf); out_no_temp: - smb_vfree(sb->u.smbfs_sb.packet); + smb_vfree(server->packet); out_no_mem: - if (!sb->u.smbfs_sb.mnt) + if (!server->mnt) printk(KERN_ERR "smb_read_super: allocation failure\n"); goto out_fail; out_wrong_data: @@ -499,11 +498,11 @@ out_fail: static int smb_statfs(struct super_block *sb, struct statfs *buf) { - smb_proc_dskattr(sb, buf); + int result = smb_proc_dskattr(sb, buf); buf->f_type = SMB_SUPER_MAGIC; buf->f_namelen = SMB_MAXPATHLEN; - return 0; + return result; } int @@ -532,8 +531,7 @@ smb_notify_change(struct dentry *dentry, struct iattr *attr) if ((attr->ia_valid & ATTR_MODE) && (attr->ia_mode & ~mask)) goto out; - if ((attr->ia_valid & ATTR_SIZE) != 0) - { + if ((attr->ia_valid & ATTR_SIZE) != 0) { VERBOSE("changing %s/%s, old size=%ld, new size=%ld\n", DENTRY_PATH(dentry), (long) inode->i_size, (long) attr->ia_size); @@ -558,20 +556,17 @@ smb_notify_change(struct dentry *dentry, struct iattr *attr) smb_get_inode_attr(inode, &fattr); changed = 0; - if ((attr->ia_valid & ATTR_MTIME) != 0) - { + if ((attr->ia_valid & ATTR_MTIME) != 0) { fattr.f_mtime = attr->ia_mtime; changed = 1; } - if ((attr->ia_valid & ATTR_ATIME) != 0) - { + if ((attr->ia_valid & ATTR_ATIME) != 0) { fattr.f_atime = attr->ia_atime; /* Earlier protocols don't have an access time */ if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) changed = 1; } - if (changed) - { + if (changed) { error = smb_proc_settime(dentry, &fattr); if (error) goto out; @@ -582,27 +577,22 @@ smb_notify_change(struct dentry *dentry, struct iattr *attr) * Check for mode changes ... we're extremely limited in * what can be set for SMB servers: just the read-only bit. */ - if ((attr->ia_valid & ATTR_MODE) != 0) - { + if ((attr->ia_valid & ATTR_MODE) != 0) { VERBOSE("%s/%s mode change, old=%x, new=%x\n", DENTRY_PATH(dentry), fattr.f_mode, attr->ia_mode); changed = 0; - if (attr->ia_mode & S_IWUSR) - { - if (fattr.attr & aRONLY) - { + if (attr->ia_mode & S_IWUSR) { + if (fattr.attr & aRONLY) { fattr.attr &= ~aRONLY; changed = 1; } } else { - if (!(fattr.attr & aRONLY)) - { + if (!(fattr.attr & aRONLY)) { fattr.attr |= aRONLY; changed = 1; } } - if (changed) - { + if (changed) { error = smb_proc_setattr(dentry, &fattr); if (error) goto out; diff --git a/fs/smbfs/ioctl.c b/fs/smbfs/ioctl.c index 285c25b039aa..afc45b4f7fd9 100644 --- a/fs/smbfs/ioctl.c +++ b/fs/smbfs/ioctl.c @@ -19,6 +19,8 @@ #include <asm/uaccess.h> +#include "proto.h" + int smb_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) @@ -37,9 +39,11 @@ smb_ioctl(struct inode *inode, struct file *filp, break; case SMB_IOC_NEWCONN: - /* require an argument == smb_conn_opt, else it is EINVAL */ - if (!arg) + /* arg is smb_conn_opt, or NULL if no connection was made */ + if (!arg) { + result = smb_wakeup(server); break; + } result = -EFAULT; if (!copy_from_user(&opt, (void *)arg, sizeof(opt))) diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index c075b7aa4973..27ec4c40a70b 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -23,16 +23,18 @@ #include <linux/smb_mount.h> #include <asm/string.h> +#include <asm/div64.h> #include "smb_debug.h" +#include "proto.h" /* Features. Undefine if they cause problems, this should perhaps be a config option. */ #define SMBFS_POSIX_UNLINK 1 -/* Allow smb_retry to be interrupted. Not sure of the benefit ... */ -/* #define SMB_RETRY_INTR */ +/* Allow smb_retry to be interrupted. */ +#define SMB_RETRY_INTR #define SMB_VWV(packet) ((packet) + SMB_HEADER_LEN) #define SMB_CMD(packet) (*(packet+8)) @@ -43,6 +45,9 @@ #define SMB_DIRINFO_SIZE 43 #define SMB_STATUS_SIZE 21 +#define SMB_ST_BLKSIZE (PAGE_SIZE) +#define SMB_ST_BLKSHIFT (PAGE_SHIFT) + static int smb_proc_setattr_ext(struct smb_sb_info *, struct inode *, struct smb_fattr *); @@ -137,8 +142,7 @@ out: return len; } -static int setcodepage(struct smb_sb_info *server, - struct nls_table **p, char *name) +static int setcodepage(struct nls_table **p, char *name) { struct nls_table *nls; @@ -160,16 +164,20 @@ static int setcodepage(struct smb_sb_info *server, /* Handles all changes to codepage settings. */ int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp) { - int n; + int n = 0; smb_lock_server(server); - n = setcodepage(server, &server->local_nls, cp->local_name); + /* Don't load any nls_* at all, if no remote is requested */ + if (!*cp->remote_name) + goto out; + + n = setcodepage(&server->local_nls, cp->local_name); if (n != 0) goto out; - n = setcodepage(server, &server->remote_nls, cp->remote_name); + n = setcodepage(&server->remote_nls, cp->remote_name); if (n != 0) - setcodepage(server, &server->local_nls, NULL); + setcodepage(&server->local_nls, NULL); out: if (server->local_nls != NULL && server->remote_nls != NULL) @@ -188,7 +196,7 @@ out: /* */ /*****************************************************************************/ -__u8 * +static __u8 * smb_encode_smb_length(__u8 * p, __u32 len) { *p = 0; @@ -308,7 +316,9 @@ date_dos2unix(struct smb_sb_info *server, __u16 date, __u16 time) int month, year; time_t secs; - month = ((date >> 5) & 15) - 1; + /* first subtract and mask after that... Otherwise, if + date == 0, bad things happen */ + month = ((date >> 5) - 1) & 15; year = date >> 9; secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 + 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) + year * 365 - ((year & 3) == 0 && @@ -327,6 +337,9 @@ date_unix2dos(struct smb_sb_info *server, int day, year, nl_day, month; unix_date = utc2local(server, unix_date); + if (unix_date < 315532800) + unix_date = 315532800; + *time = (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) + (((unix_date / 3600) % 24) << 11); @@ -350,57 +363,20 @@ date_unix2dos(struct smb_sb_info *server, /* The following are taken from fs/ntfs/util.c */ +#define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000) + /* * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units) * into Unix UTC (based 1970-01-01, in seconds). - * - * This is very gross because - * 1: We must do 64-bit division on a 32-bit machine - * 2: We can't use libgcc for long long operations in the kernel - * 3: Floating point math in the kernel would corrupt user data */ static time_t -smb_ntutc2unixutc(struct smb_sb_info *server, u64 ntutc) +smb_ntutc2unixutc(u64 ntutc) { - const unsigned int D = 10000000; - unsigned int H = (unsigned int)(ntutc >> 32); - unsigned int L = (unsigned int)ntutc; - unsigned int numerator2; - unsigned int lowseconds; - unsigned int result; - - /* - * It is best to subtract 0x019db1ded53e8000 first. - * Then the 1601-based date becomes a 1970-based date. - */ - if (L < (unsigned)0xd53e8000) H--; - L -= (unsigned)0xd53e8000; - H -= (unsigned)0x019db1de; - - /* - * Now divide 64-bit numbers on a 32-bit machine :-) - * With the subtraction already done, the result fits in 32 bits. - * The numerator fits in 56 bits and the denominator fits - * in 24 bits, so we can shift by 8 bits to make this work. - */ - - numerator2 = (H<<8) | (L>>24); - result = (numerator2 / D); /* shifted 24 right!! */ - lowseconds = result << 24; - - numerator2 = ((numerator2-result*D)<<8) | ((L>>16)&0xff); - result = (numerator2 / D); /* shifted 16 right!! */ - lowseconds |= result << 16; - - numerator2 = ((numerator2-result*D)<<8) | ((L>>8)&0xff); - result = (numerator2 / D); /* shifted 8 right!! */ - lowseconds |= result << 8; - - numerator2 = ((numerator2-result*D)<<8) | (L&0xff); - result = (numerator2 / D); /* not shifted */ - lowseconds |= result; - - return lowseconds; + /* FIXME: what about the timezone difference? */ + /* Subtract the NTFS time offset, then convert to 1s intervals. */ + u64 t = ntutc - NTFS_TIME_OFFSET; + do_div(t, 10000000); + return (time_t)t; } #if 0 @@ -409,7 +385,7 @@ static u64 smb_unixutc2ntutc(struct smb_sb_info *server, time_t t) { /* Note: timezone conversion is probably wrong. */ - return ((utc2local(server, t) + (u64)(369*365+89)*24*3600) * 10000000); + return ((u64)utc2local(server, t)) * 10000000 + NTFS_TIME_OFFSET; } #endif @@ -519,6 +495,9 @@ smb_get_wsize(struct smb_sb_info *server) return size; } +/* + * Convert SMB error codes to -E... errno values. + */ int smb_errno(struct smb_sb_info *server) { @@ -529,110 +508,115 @@ smb_errno(struct smb_sb_info *server) VERBOSE("errcls %d code %d from command 0x%x\n", errcls, error, SMB_CMD(server->packet)); - if (errcls == ERRDOS) - switch (error) - { + if (errcls == ERRDOS) { + switch (error) { case ERRbadfunc: - return EINVAL; + return -EINVAL; case ERRbadfile: case ERRbadpath: - return ENOENT; + return -ENOENT; case ERRnofids: - return EMFILE; + return -EMFILE; case ERRnoaccess: - return EACCES; + return -EACCES; case ERRbadfid: - return EBADF; + return -EBADF; case ERRbadmcb: - return EREMOTEIO; + return -EREMOTEIO; case ERRnomem: - return ENOMEM; + return -ENOMEM; case ERRbadmem: - return EFAULT; + return -EFAULT; case ERRbadenv: case ERRbadformat: - return EREMOTEIO; + return -EREMOTEIO; case ERRbadaccess: - return EACCES; + return -EACCES; case ERRbaddata: - return E2BIG; + return -E2BIG; case ERRbaddrive: - return ENXIO; + return -ENXIO; case ERRremcd: - return EREMOTEIO; + return -EREMOTEIO; case ERRdiffdevice: - return EXDEV; - case ERRnofiles: /* Why is this mapped to 0?? */ - return 0; + return -EXDEV; + case ERRnofiles: + return -ENOENT; case ERRbadshare: - return ETXTBSY; + return -ETXTBSY; case ERRlock: - return EDEADLK; + return -EDEADLK; case ERRfilexists: - return EEXIST; - case 87: /* should this map to 0?? */ - return 0; /* Unknown error!! */ - case 123: /* Invalid name?? e.g. .tmp* */ - return ENOENT; - case 145: /* Win NT 4.0: non-empty directory? */ - return ENOTEMPTY; - /* This next error seems to occur on an mv when - * the destination exists */ - case 183: - return EEXIST; + return -EEXIST; + case ERRinvalidparam: + return -EINVAL; + case ERRdiskfull: + return -ENOSPC; + case ERRinvalidname: + return -ENOENT; + case ERRdirnotempty: + return -ENOTEMPTY; + case ERRnotlocked: + return -ENOLCK; + case ERRexists: + return -EEXIST; default: class = "ERRDOS"; goto err_unknown; - } else if (errcls == ERRSRV) - switch (error) - { + } + } else if (errcls == ERRSRV) { + switch (error) { /* N.B. This is wrong ... EIO ? */ case ERRerror: - return ENFILE; + return -ENFILE; case ERRbadpw: - return EINVAL; + return -EINVAL; case ERRbadtype: - return EIO; + return -EIO; case ERRaccess: - return EACCES; + return -EACCES; /* * This is a fatal error, as it means the "tree ID" * for this connection is no longer valid. We map * to a special error code and get a new connection. */ case ERRinvnid: - return EBADSLT; + return -EBADSLT; default: class = "ERRSRV"; goto err_unknown; - } else if (errcls == ERRHRD) - switch (error) - { + } + } else if (errcls == ERRHRD) { + switch (error) { case ERRnowrite: - return EROFS; + return -EROFS; case ERRbadunit: - return ENODEV; + return -ENODEV; case ERRnotready: - return EUCLEAN; + return -EUCLEAN; case ERRbadcmd: case ERRdata: - return EIO; + return -EIO; case ERRbadreq: - return ERANGE; + return -ERANGE; case ERRbadshare: - return ETXTBSY; + return -ETXTBSY; case ERRlock: - return EDEADLK; + return -EDEADLK; default: class = "ERRHRD"; goto err_unknown; - } else if (errcls == ERRCMD) + } + } else if (errcls == ERRCMD) { class = "ERRCMD"; + } else if (errcls == SUCCESS) { + return 0; /* This is the only valid 0 return */ + } err_unknown: printk(KERN_ERR "smb_errno: class %s, code %d from command 0x%x\n", class, error, SMB_CMD(server->packet)); - return EIO; + return -EIO; } /* @@ -749,12 +733,10 @@ smb_request_ok(struct smb_sb_info *s, int command, int wct, int bcc) } /* - * Check for server errors. The current smb_errno() routine - * is squashing some error codes, but I don't think this is - * correct: after a server error the packet won't be valid. + * Check for server errors. */ if (s->rcls != 0) { - result = -smb_errno(s); + result = smb_errno(s); if (!result) printk(KERN_DEBUG "smb_request_ok: rcls=%d, err=%d mapped to 0\n", s->rcls, s->err); @@ -850,17 +832,23 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt) out: smb_unlock_server(server); + smb_wakeup(server); + return error; +out_putf: + fput(filp); + goto out; +} + +int +smb_wakeup(struct smb_sb_info *server) +{ #ifdef SMB_RETRY_INTR wake_up_interruptible(&server->wait); #else wake_up(&server->wait); #endif - return error; - -out_putf: - fput(filp); - goto out; + return 0; } /* smb_setup_header: We completely set up the packet. You only have to @@ -1490,7 +1478,7 @@ smb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr) fattr->f_nlink = 1; fattr->f_uid = server->mnt->uid; fattr->f_gid = server->mnt->gid; - fattr->f_blksize = 512; + fattr->f_blksize = SMB_ST_BLKSIZE; } static void @@ -1500,18 +1488,16 @@ smb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr) if (fattr->attr & aDIR) { fattr->f_mode = server->mnt->dir_mode; - fattr->f_size = 512; + fattr->f_size = SMB_ST_BLKSIZE; } /* Check the read-only flag */ if (fattr->attr & aRONLY) fattr->f_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); + /* How many 512 byte blocks do we need for this file? */ fattr->f_blocks = 0; - if ((fattr->f_blksize != 0) && (fattr->f_size != 0)) - { - fattr->f_blocks = - (fattr->f_size - 1) / fattr->f_blksize + 1; - } + if (fattr->f_size != 0) + fattr->f_blocks = 1 + ((fattr->f_size-1) >> 9); return; } @@ -1770,9 +1756,9 @@ smb_decode_long_dirent(struct smb_sb_info *server, char *p, int level, if (len && qname->name[len-1] == '\0') len--; - fattr->f_ctime = smb_ntutc2unixutc(server, LVAL(p, 8)); - fattr->f_atime = smb_ntutc2unixutc(server, LVAL(p, 16)); - fattr->f_mtime = smb_ntutc2unixutc(server, LVAL(p, 24)); + fattr->f_ctime = smb_ntutc2unixutc(LVAL(p, 8)); + fattr->f_atime = smb_ntutc2unixutc(LVAL(p, 16)); + fattr->f_mtime = smb_ntutc2unixutc(LVAL(p, 24)); /* change time (32) */ fattr->f_size = DVAL(p, 40); /* alloc size (48) */ @@ -1940,7 +1926,7 @@ smb_proc_readdir_long(struct file *filp, void *dirent, filldir_t filldir, } if (server->rcls != 0) { - result = -smb_errno(server); + result = smb_errno(server); PARANOIA("name=%s, result=%d, rcls=%d, err=%d\n", mask, result, server->rcls, server->err); break; @@ -2104,7 +2090,7 @@ retry: } if (server->rcls != 0) { - result = -smb_errno(server); + result = smb_errno(server); #ifdef SMBFS_PARANOIA if (result != -ENOENT) PARANOIA("error for %s, rcls=%d, err=%d\n", @@ -2227,7 +2213,7 @@ smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir, { VERBOSE("for %s: result=%d, rcls=%d, err=%d\n", ¶m[6], result, server->rcls, server->err); - result = -smb_errno(server); + result = smb_errno(server); goto out; } result = -ENOENT; @@ -2490,7 +2476,7 @@ smb_proc_setattr_trans2(struct smb_sb_info *server, } result = 0; if (server->rcls != 0) - result = -smb_errno(server); + result = smb_errno(server); out: return result; @@ -2559,6 +2545,7 @@ smb_proc_dskattr(struct super_block *sb, struct statfs *attr) struct smb_sb_info *server = &(sb->u.smbfs_sb); int result; char *p; + long unit; smb_lock_server(server); @@ -2571,23 +2558,13 @@ smb_proc_dskattr(struct super_block *sb, struct statfs *attr) goto out; } p = SMB_VWV(server->packet); - attr->f_blocks = WVAL(p, 0); - attr->f_bsize = WVAL(p, 2) * WVAL(p, 4); - attr->f_bavail = attr->f_bfree = WVAL(p, 6); + unit = (WVAL(p, 2) * WVAL(p, 4)) >> SMB_ST_BLKSHIFT; + attr->f_blocks = WVAL(p, 0) * unit; + attr->f_bsize = SMB_ST_BLKSIZE; + attr->f_bavail = attr->f_bfree = WVAL(p, 6) * unit; result = 0; out: smb_unlock_server(server); return result; } - -int -smb_proc_disconnect(struct smb_sb_info *server) -{ - int result; - smb_lock_server(server); - smb_setup_header(server, SMBtdis, 0, 0); - result = smb_request_ok(server, SMBtdis, 0, 0); - smb_unlock_server(server); - return result; -} diff --git a/fs/smbfs/proto.h b/fs/smbfs/proto.h new file mode 100644 index 000000000000..65b18719da77 --- /dev/null +++ b/fs/smbfs/proto.h @@ -0,0 +1,63 @@ +/* + * Autogenerated with cproto on: Tue Oct 2 20:40:54 CEST 2001 + */ + +/* proc.c */ +extern int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp); +extern __u32 smb_len(__u8 *p); +extern int smb_get_rsize(struct smb_sb_info *server); +extern int smb_get_wsize(struct smb_sb_info *server); +extern int smb_errno(struct smb_sb_info *server); +extern int smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt); +extern int smb_wakeup(struct smb_sb_info *server); +extern __u8 *smb_setup_header(struct smb_sb_info *server, __u8 command, __u16 wct, __u16 bcc); +extern int smb_open(struct dentry *dentry, int wish); +extern int smb_close(struct inode *ino); +extern int smb_close_fileid(struct dentry *dentry, __u16 fileid); +extern int smb_proc_read(struct inode *inode, off_t offset, int count, char *data); +extern int smb_proc_write(struct inode *inode, off_t offset, int count, const char *data); +extern int smb_proc_create(struct dentry *dentry, __u16 attr, time_t ctime, __u16 *fileid); +extern int smb_proc_mv(struct dentry *old_dentry, struct dentry *new_dentry); +extern int smb_proc_mkdir(struct dentry *dentry); +extern int smb_proc_rmdir(struct dentry *dentry); +extern int smb_proc_unlink(struct dentry *dentry); +extern int smb_proc_flush(struct smb_sb_info *server, __u16 fileid); +extern int smb_proc_trunc(struct smb_sb_info *server, __u16 fid, __u32 length); +extern void smb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *fattr); +extern int smb_proc_readdir(struct file *filp, void *dirent, filldir_t filldir, struct smb_cache_control *ctl); +extern int smb_proc_getattr(struct dentry *dir, struct smb_fattr *fattr); +extern int smb_proc_setattr(struct dentry *dir, struct smb_fattr *fattr); +extern int smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr); +extern int smb_proc_dskattr(struct super_block *sb, struct statfs *attr); +/* dir.c */ +extern struct file_operations smb_dir_operations; +extern struct inode_operations smb_dir_inode_operations; +extern void smb_new_dentry(struct dentry *dentry); +extern void smb_renew_times(struct dentry *dentry); +/* cache.c */ +extern void smb_invalid_dir_cache(struct inode *dir); +extern void smb_invalidate_dircache_entries(struct dentry *parent); +extern struct dentry *smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos); +extern int smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir, struct smb_cache_control *ctrl, struct qstr *qname, struct smb_fattr *entry); +/* sock.c */ +extern int smb_valid_socket(struct inode *inode); +extern int smb_catch_keepalive(struct smb_sb_info *server); +extern int smb_dont_catch_keepalive(struct smb_sb_info *server); +extern void smb_close_socket(struct smb_sb_info *server); +extern int smb_round_length(int len); +extern int smb_request(struct smb_sb_info *server); +extern int smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command, int ldata, unsigned char *data, int lparam, unsigned char *param, int *lrdata, unsigned char **rdata, int *lrparam, unsigned char **rparam); +/* inode.c */ +extern struct inode *smb_iget(struct super_block *sb, struct smb_fattr *fattr); +extern void smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr); +extern void smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr); +extern void smb_invalidate_inodes(struct smb_sb_info *server); +extern int smb_revalidate_inode(struct dentry *dentry); +extern struct super_block *smb_read_super(struct super_block *sb, void *raw_data, int silent); +extern int smb_notify_change(struct dentry *dentry, struct iattr *attr); +/* file.c */ +extern struct address_space_operations smb_file_aops; +extern struct file_operations smb_file_operations; +extern struct inode_operations smb_file_inode_operations; +/* ioctl.c */ +extern int smb_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c index 47aad9dc1cb1..46313b623c7b 100644 --- a/fs/smbfs/sock.c +++ b/fs/smbfs/sock.c @@ -27,6 +27,7 @@ #include <asm/uaccess.h> #include "smb_debug.h" +#include "proto.h" static int @@ -674,7 +675,7 @@ smb_request(struct smb_sb_info *server) */ if (server->rcls) { int error = smb_errno(server); - if (error == EBADSLT) { + if (error == -EBADSLT) { printk(KERN_ERR "smb_request: tree ID invalid\n"); result = error; goto bad_conn; @@ -866,7 +867,7 @@ smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command, */ if (server->rcls) { int error = smb_errno(server); - if (error == EBADSLT) { + if (error == -EBADSLT) { printk(KERN_ERR "smb_request: tree ID invalid\n"); result = error; goto bad_conn; diff --git a/fs/super.c b/fs/super.c index 4736ded323c6..c4ad15b24195 100644 --- a/fs/super.c +++ b/fs/super.c @@ -280,6 +280,7 @@ struct file_system_type *get_fs_type(const char *name) } static LIST_HEAD(vfsmntlist); +static struct vfsmount *root_vfsmnt; static struct list_head *mount_hashtable; static int hash_mask, hash_bits; @@ -326,6 +327,15 @@ struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) return p; } +static int check_mnt(struct vfsmount *mnt) +{ + spin_lock(&dcache_lock); + while (mnt->mnt_parent != mnt) + mnt = mnt->mnt_parent; + spin_unlock(&dcache_lock); + return mnt == root_vfsmnt; +} + static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd) { old_nd->dentry = mnt->mnt_mountpoint; @@ -346,50 +356,20 @@ static void attach_mnt(struct vfsmount *mnt, struct nameidata *nd) nd->dentry->d_mounted++; } -/** - * add_vfsmnt - add a new mount node - * @nd: location of mountpoint or %NULL if we want a root node - * @root: root of (sub)tree to be mounted - * @dev_name: device name to show in /proc/mounts or %NULL (for "none"). - * - * This is VFS idea of mount. New node is allocated, bound to a tree - * we are mounting and optionally (OK, usually) registered as mounted - * on a given mountpoint. Returns a pointer to new node or %NULL in - * case of failure. - * - * Potential reason for failure (aside of trivial lack of memory) is a - * deleted mountpoint. Caller must hold ->i_zombie on mountpoint - * dentry (if any). - */ - -static struct vfsmount *add_vfsmnt(struct dentry *root, const char *dev_name) +static struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root) { - struct vfsmount *mnt; - struct super_block *sb = root->d_inode->i_sb; - char *name; - - mnt = alloc_vfsmnt(); - if (!mnt) - goto out; - - /* It may be NULL, but who cares? */ - if (dev_name) { - name = kmalloc(strlen(dev_name)+1, GFP_KERNEL); - if (name) { - strcpy(name, dev_name); - mnt->mnt_devname = name; + struct list_head *next = p->mnt_mounts.next; + if (next == &p->mnt_mounts) { + while (1) { + if (p == root) + return NULL; + next = p->mnt_child.next; + if (next != &p->mnt_parent->mnt_mounts) + break; + p = p->mnt_parent; } } - mnt->mnt_sb = sb; - mnt->mnt_root = dget(root); - mnt->mnt_mountpoint = mnt->mnt_root; - mnt->mnt_parent = mnt; - - spin_lock(&dcache_lock); - list_add(&mnt->mnt_list, vfsmntlist.prev); - spin_unlock(&dcache_lock); -out: - return mnt; + return list_entry(next, struct vfsmount, mnt_child); } static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root) @@ -447,37 +427,6 @@ fail1: return -ENOENT; } -#ifdef CONFIG_BLK_DEV_INITRD -static void move_vfsmnt(struct vfsmount *mnt, - struct nameidata *nd, - const char *dev_name) -{ - struct nameidata parent_nd; - char *new_devname = NULL; - - if (dev_name) { - new_devname = kmalloc(strlen(dev_name)+1, GFP_KERNEL); - if (new_devname) - strcpy(new_devname, dev_name); - } - - spin_lock(&dcache_lock); - detach_mnt(mnt, &parent_nd); - attach_mnt(mnt, nd); - - if (new_devname) { - if (mnt->mnt_devname) - kfree(mnt->mnt_devname); - mnt->mnt_devname = new_devname; - } - spin_unlock(&dcache_lock); - - /* put the old stuff */ - if (parent_nd.mnt != mnt) - path_release(&parent_nd); -} -#endif - static void kill_super(struct super_block *); void __mntput(struct vfsmount *mnt) @@ -1189,10 +1138,52 @@ int may_umount(struct vfsmount *mnt) return 0; } +void umount_tree(struct vfsmount *mnt) +{ + struct vfsmount *p; + LIST_HEAD(kill); + + if (list_empty(&mnt->mnt_list)) + return; + + for (p = mnt; p; p = next_mnt(p, mnt)) { + list_del(&p->mnt_list); + list_add(&p->mnt_list, &kill); + } + + while (!list_empty(&kill)) { + mnt = list_entry(kill.next, struct vfsmount, mnt_list); + list_del_init(&mnt->mnt_list); + if (mnt->mnt_parent == mnt) { + spin_unlock(&dcache_lock); + } else { + struct nameidata old_nd; + detach_mnt(mnt, &old_nd); + spin_unlock(&dcache_lock); + path_release(&old_nd); + } + mntput(mnt); + spin_lock(&dcache_lock); + } +} + static int do_umount(struct vfsmount *mnt, int flags) { struct super_block * sb = mnt->mnt_sb; - struct nameidata parent_nd; + int retval = 0; + + /* + * If we may have to abort operations to get out of this + * mount, and they will themselves hold resources we must + * allow the fs to do things. In the Unix tradition of + * 'Gee thats tricky lets do it in userspace' the umount_begin + * might fail to complete on the first run through as other tasks + * must return, and the like. Thats for the mount program to worry + * about for the moment. + */ + + if( (flags&MNT_FORCE) && sb->s_op->umount_begin) + sb->s_op->umount_begin(sb); /* * No sense to grab the lock for this test, but test itself looks @@ -1204,7 +1195,7 @@ static int do_umount(struct vfsmount *mnt, int flags) * /reboot - static binary that would close all descriptors and * call reboot(9). Then init(8) could umount root and exec /reboot. */ - if (mnt == current->fs->rootmnt) { + if (mnt == current->fs->rootmnt && !(flags & MNT_DETACH)) { int retval = 0; /* * Special case for "unmounting" root ... @@ -1220,59 +1211,20 @@ static int do_umount(struct vfsmount *mnt, int flags) spin_lock(&dcache_lock); - if (atomic_read(&sb->s_active) > 1) { - if (atomic_read(&mnt->mnt_count) > 2) { - spin_unlock(&dcache_lock); - return -EBUSY; - } - detach_mnt(mnt, &parent_nd); - list_del(&mnt->mnt_list); + if (atomic_read(&sb->s_active) == 1) { + /* last instance - try to be smart */ spin_unlock(&dcache_lock); - mntput(mnt); - if (parent_nd.mnt != mnt) - path_release(&parent_nd); - return 0; + DQUOT_OFF(sb); + acct_auto_close(sb->s_dev); + spin_lock(&dcache_lock); } - spin_unlock(&dcache_lock); - - /* - * Before checking whether the filesystem is still busy, - * make sure the kernel doesn't hold any quota files open - * on the device. If the umount fails, too bad -- there - * are no quotas running any more. Just turn them on again. - */ - DQUOT_OFF(sb); - acct_auto_close(sb->s_dev); - - /* - * If we may have to abort operations to get out of this - * mount, and they will themselves hold resources we must - * allow the fs to do things. In the Unix tradition of - * 'Gee thats tricky lets do it in userspace' the umount_begin - * might fail to complete on the first run through as other tasks - * must return, and the like. Thats for the mount program to worry - * about for the moment. - */ - - if( (flags&MNT_FORCE) && sb->s_op->umount_begin) - sb->s_op->umount_begin(sb); - - /* Something might grab it again - redo checks */ - - spin_lock(&dcache_lock); - if (atomic_read(&mnt->mnt_count) > 2) { - spin_unlock(&dcache_lock); - return -EBUSY; + retval = -EBUSY; + if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) { + umount_tree(mnt); + retval = 0; } - - /* OK, that's the point of no return */ - detach_mnt(mnt, &parent_nd); - list_del(&mnt->mnt_list); spin_unlock(&dcache_lock); - mntput(mnt); - if (parent_nd.mnt != mnt) - path_release(&parent_nd); - return 0; + return retval; } /* @@ -1302,6 +1254,8 @@ asmlinkage long sys_umount(char * name, int flags) retval = -EINVAL; if (nd.dentry != nd.mnt->mnt_root) goto dput_and_out; + if (!check_mnt(nd.mnt)) + goto dput_and_out; retval = -EPERM; if (!capable(CAP_SYS_ADMIN) && current->uid!=nd.mnt->mnt_owner) @@ -1353,7 +1307,7 @@ static int mount_is_safe(struct nameidata *nd) static int do_loopback(struct nameidata *nd, char *old_name) { struct nameidata old_nd; - struct vfsmount *mnt; + struct vfsmount *mnt = NULL; int err; err = mount_is_safe(nd); @@ -1369,12 +1323,16 @@ static int do_loopback(struct nameidata *nd, char *old_name) return err; down(&mount_sem); - err = -ENOMEM; - mnt = clone_mnt(old_nd.mnt, old_nd.dentry); + err = -EINVAL; + if (check_mnt(nd->mnt)) { + err = -ENOMEM; + mnt = clone_mnt(old_nd.mnt, old_nd.dentry); + } if (mnt) { err = graft_tree(mnt, nd); mntput(mnt); } + up(&mount_sem); path_release(&old_nd); return err; @@ -1394,6 +1352,9 @@ static int do_remount(struct nameidata *nd,int flags,int mnt_flags,char *data) if (!capable(CAP_SYS_ADMIN)) return -EPERM; + if (!check_mnt(nd->mnt)) + return -EINVAL; + if (nd->dentry != nd->mnt->mnt_root) return -EINVAL; @@ -1472,27 +1433,31 @@ static int do_add_mount(struct nameidata *nd, char *type, int flags, int mnt_flags, char *name, void *data) { struct vfsmount *mnt = do_kern_mount(type, flags, name, data); - int retval = PTR_ERR(mnt); + int err = PTR_ERR(mnt); if (IS_ERR(mnt)) goto out; - mnt->mnt_flags = mnt_flags; - down(&mount_sem); /* Something was mounted here while we slept */ while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry)) ; + err = -EINVAL; + if (!check_mnt(nd->mnt)) + goto unlock; /* Refuse the same filesystem on the same mount point */ + err = -EBUSY; if (nd->mnt->mnt_sb == mnt->mnt_sb && nd->mnt->mnt_root == nd->dentry) - retval = -EBUSY; - else - retval = graft_tree(mnt, nd); + goto unlock; + + mnt->mnt_flags = mnt_flags; + err = graft_tree(mnt, nd); +unlock: up(&mount_sem); mntput(mnt); out: - return retval; + return err; } static int copy_mount_options (const void *data, unsigned long *where) @@ -1630,6 +1595,7 @@ out1: void __init mount_root(void) { + struct nameidata root_nd; struct file_system_type * fs_type; struct super_block * sb; struct vfsmount *vfsmnt; @@ -1639,6 +1605,7 @@ void __init mount_root(void) void *handle; char path[64]; int path_start = -1; + char *name = "/dev/root"; #ifdef CONFIG_ROOT_NFS void *data; @@ -1776,13 +1743,26 @@ mount_it: fs_type->name, (sb->s_flags & MS_RDONLY) ? " readonly" : ""); if (path_start >= 0) { + name = path + path_start; devfs_mk_symlink (NULL, "root", DEVFS_FL_DEFAULT, - path + 5 + path_start, NULL, NULL); - memcpy (path + path_start, "/dev/", 5); - vfsmnt = add_vfsmnt(sb->s_root, path + path_start); + name + 5, NULL, NULL); + memcpy (name, "/dev/", 5); } - else - vfsmnt = add_vfsmnt(sb->s_root, "/dev/root"); + vfsmnt = alloc_vfsmnt(); + if (!vfsmnt) + panic("VFS: alloc_vfsmnt failed for root fs"); + + vfsmnt->mnt_devname = kmalloc(strlen(name)+1, GFP_KERNEL); + if (vfsmnt->mnt_devname) + strcpy(vfsmnt->mnt_devname, name); + vfsmnt->mnt_sb = sb; + vfsmnt->mnt_root = dget(sb->s_root); + + root_nd.mnt = root_vfsmnt; + root_nd.dentry = root_vfsmnt->mnt_sb->s_root; + graft_tree(vfsmnt, &root_nd); + mntput(vfsmnt); + /* FIXME: if something will try to umount us right now... */ if (vfsmnt) { set_fs_root(current->fs, vfsmnt, sb->s_root); @@ -1791,10 +1771,8 @@ mount_it: bdput(bdev); /* sb holds a reference */ return; } - panic("VFS: add_vfsmnt failed for root fs"); } - static void chroot_fs_refs(struct dentry *old_root, struct vfsmount *old_rootmnt, struct dentry *new_root, @@ -1836,10 +1814,8 @@ static void chroot_fs_refs(struct dentry *old_root, asmlinkage long sys_pivot_root(const char *new_root, const char *put_old) { - struct dentry *root; - struct vfsmount *root_mnt; struct vfsmount *tmp; - struct nameidata new_nd, old_nd, parent_nd, root_parent; + struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd; char *name; int error; @@ -1858,11 +1834,14 @@ asmlinkage long sys_pivot_root(const char *new_root, const char *put_old) putname(name); if (error) goto out0; + error = -EINVAL; + if (!check_mnt(new_nd.mnt)) + goto out1; name = getname(put_old); error = PTR_ERR(name); if (IS_ERR(name)) - goto out0; + goto out1; error = 0; if (path_init(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd)) error = path_walk(name, &old_nd); @@ -1871,11 +1850,14 @@ asmlinkage long sys_pivot_root(const char *new_root, const char *put_old) goto out1; read_lock(¤t->fs->lock); - root_mnt = mntget(current->fs->rootmnt); - root = dget(current->fs->root); + user_nd.mnt = mntget(current->fs->rootmnt); + user_nd.dentry = dget(current->fs->root); read_unlock(¤t->fs->lock); down(&mount_sem); down(&old_nd.dentry->d_inode->i_zombie); + error = -EINVAL; + if (!check_mnt(user_nd.mnt)) + goto out2; error = -ENOENT; if (IS_DEADDIR(new_nd.dentry->d_inode)) goto out2; @@ -1884,10 +1866,10 @@ asmlinkage long sys_pivot_root(const char *new_root, const char *put_old) if (d_unhashed(old_nd.dentry) && !IS_ROOT(old_nd.dentry)) goto out2; error = -EBUSY; - if (new_nd.mnt == root_mnt || old_nd.mnt == root_mnt) + if (new_nd.mnt == user_nd.mnt || old_nd.mnt == user_nd.mnt) goto out2; /* loop */ error = -EINVAL; - if (root_mnt->mnt_root != root) + if (user_nd.mnt->mnt_root != user_nd.dentry) goto out2; if (new_nd.mnt->mnt_root != new_nd.dentry) goto out2; /* not a mountpoint */ @@ -1906,22 +1888,18 @@ asmlinkage long sys_pivot_root(const char *new_root, const char *put_old) } else if (!is_subdir(old_nd.dentry, new_nd.dentry)) goto out3; detach_mnt(new_nd.mnt, &parent_nd); - detach_mnt(root_mnt, &root_parent); - attach_mnt(root_mnt, &old_nd); - if (root_parent.mnt != root_mnt) - attach_mnt(new_nd.mnt, &root_parent); + detach_mnt(user_nd.mnt, &root_parent); + attach_mnt(user_nd.mnt, &old_nd); + attach_mnt(new_nd.mnt, &root_parent); spin_unlock(&dcache_lock); - chroot_fs_refs(root,root_mnt,new_nd.dentry,new_nd.mnt); + chroot_fs_refs(user_nd.dentry,user_nd.mnt,new_nd.dentry,new_nd.mnt); error = 0; - if (root_parent.mnt != root_mnt) - path_release(&root_parent); - if (parent_nd.mnt != new_nd.mnt) - path_release(&parent_nd); + path_release(&root_parent); + path_release(&parent_nd); out2: up(&old_nd.dentry->d_inode->i_zombie); up(&mount_sem); - dput(root); - mntput(root_mnt); + path_release(&user_nd); path_release(&old_nd); out1: path_release(&new_nd); @@ -1940,8 +1918,13 @@ int __init change_root(kdev_t new_root_dev,const char *put_old) { struct vfsmount *old_rootmnt; struct nameidata devfs_nd, nd; + struct nameidata parent_nd; + char *new_devname = kmalloc(strlen("/dev/root.old")+1, GFP_KERNEL); int error = 0; + if (new_devname) + strcpy(new_devname, "/dev/root.old"); + read_lock(¤t->fs->lock); old_rootmnt = mntget(current->fs->rootmnt); read_unlock(¤t->fs->lock); @@ -1958,6 +1941,9 @@ int __init change_root(kdev_t new_root_dev,const char *put_old) } else path_release(&devfs_nd); } + spin_lock(&dcache_lock); + detach_mnt(old_rootmnt, &parent_nd); + spin_unlock(&dcache_lock); ROOT_DEV = new_root_dev; mount_root(); #if 1 @@ -1980,25 +1966,36 @@ int __init change_root(kdev_t new_root_dev,const char *put_old) blivet = blkdev_get(ramdisk, FMODE_READ, 0, BDEV_FS); printk(KERN_NOTICE "Trying to unmount old root ... "); if (!blivet) { - blivet = do_umount(old_rootmnt, 0); + spin_lock(&dcache_lock); + list_del(&old_rootmnt->mnt_list); + spin_unlock(&dcache_lock); + mntput(old_rootmnt); mntput(old_rootmnt); - if (!blivet) { - int ioctl_err; - - ioctl_err = ioctl_by_bdev(ramdisk, BLKFLSBUF, 0); - if (ioctl_err) - printk("failed to release ramdisk %d...", ioctl_err); - printk("okay\n"); - error = 0; - } + blivet = ioctl_by_bdev(ramdisk, BLKFLSBUF, 0); + path_release(&parent_nd); blkdev_put(ramdisk, BDEV_FS); } - if (blivet) + if (blivet) { printk(KERN_ERR "error %d\n", blivet); + } else { + printk("okay\n"); + error = 0; + } + kfree(new_devname); return error; } - /* FIXME: we should hold i_zombie on nd.dentry */ - move_vfsmnt(old_rootmnt, &nd, "/dev/root.old"); + + spin_lock(&dcache_lock); + attach_mnt(old_rootmnt, &nd); + if (new_devname) { + if (old_rootmnt->mnt_devname) + kfree(old_rootmnt->mnt_devname); + old_rootmnt->mnt_devname = new_devname; + } + spin_unlock(&dcache_lock); + + /* put the old stuff */ + path_release(&parent_nd); mntput(old_rootmnt); path_release(&nd); return 0; @@ -2006,6 +2003,54 @@ int __init change_root(kdev_t new_root_dev,const char *put_old) #endif +/* + * Absolutely minimal fake fs - only empty root directory and nothing else. + * In 2.5 we'll use ramfs or tmpfs, but for now it's all we need - just + * something to go with root vfsmount. + */ +static struct dentry *rootfs_lookup(struct inode *dir, struct dentry *dentry) +{ + d_add(dentry, NULL); + return NULL; +} +static struct file_operations rootfs_dir_operations = { + read: generic_read_dir, + readdir: dcache_readdir, +}; +static struct inode_operations rootfs_dir_inode_operations = { + lookup: rootfs_lookup, +}; +static struct super_block *rootfs_read_super(struct super_block * sb, void * data, int silent) +{ + struct inode * inode; + struct dentry * root; + static struct super_operations s_ops = {}; + sb->s_op = &s_ops; + inode = new_inode(sb); + if (!inode) + return NULL; + inode->i_mode = S_IFDIR|0555; + inode->i_uid = inode->i_gid = 0; + inode->i_op = &rootfs_dir_inode_operations; + inode->i_fop = &rootfs_dir_operations; + root = d_alloc_root(inode); + if (!root) { + iput(inode); + return NULL; + } + sb->s_root = root; + return sb; +} +static DECLARE_FSTYPE(root_fs_type, "rootfs", rootfs_read_super, FS_NOMOUNT); + +static void __init init_mount_tree(void) +{ + register_filesystem(&root_fs_type); + root_vfsmnt = do_kern_mount("rootfs", 0, "rootfs", NULL); + if (IS_ERR(root_vfsmnt)) + panic("can't allocate root vfsmount"); +} + void __init mnt_init(unsigned long mempages) { struct list_head *d; @@ -2061,4 +2106,5 @@ void __init mnt_init(unsigned long mempages) d++; i--; } while (i); + init_mount_tree(); } diff --git a/include/asm-ppc/mmu_context.h b/include/asm-ppc/mmu_context.h index 7624088c38d5..58b4d6179855 100644 --- a/include/asm-ppc/mmu_context.h +++ b/include/asm-ppc/mmu_context.h @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.mmu_context.h 1.15 08/16/01 23:00:17 paulus + * BK Id: SCCS/s.mmu_context.h 1.18 09/26/01 16:02:49 paulus */ #ifdef __KERNEL__ #ifndef __PPC_MMU_CONTEXT_H @@ -29,7 +29,7 @@ * of the 32-bit virtual address (the "effective segment ID") in order * to spread out the entries in the MMU hash table. Note, if this * function is changed then arch/ppc/mm/hashtable.S will have to be - * changed correspondly. + * changed to correspond. */ #define CTX_TO_VSID(ctx, va) (((ctx) * (897 * 16) + ((va) >> 28) * 0x111) \ & 0xffffff) @@ -89,7 +89,7 @@ extern void set_context(mm_context_t context, pgd_t *pgd); * Bitmap of contexts in use. * The size of this bitmap is LAST_CONTEXT + 1 bits. */ -extern unsigned long context_map[(LAST_CONTEXT+1) / (8*sizeof(unsigned long))]; +extern unsigned long context_map[]; /* * This caches the next context number that we expect to be free. diff --git a/include/linux/fs.h b/include/linux/fs.h index 9d04f9af4908..9d314051fb0b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -650,6 +650,7 @@ struct quota_mount_options */ #define MNT_FORCE 0x00000001 /* Attempt to forcibily umount */ +#define MNT_DETACH 0x00000002 /* Just detach from the tree */ #include <linux/minix_fs_sb.h> #include <linux/ext2_fs_sb.h> diff --git a/include/linux/gameport.h b/include/linux/gameport.h index 4e341f1fdbe9..37b72807182b 100644 --- a/include/linux/gameport.h +++ b/include/linux/gameport.h @@ -74,8 +74,8 @@ void gameport_rescan(struct gameport *gameport); void gameport_register_port(struct gameport *gameport); void gameport_unregister_port(struct gameport *gameport); #else -void __inline__ gameport_register_port(struct gameport *gameport) { return; } -void __inline__ gameport_unregister_port(struct gameport *gameport) { return; } +static void __inline__ gameport_register_port(struct gameport *gameport) { return; } +static void __inline__ gameport_unregister_port(struct gameport *gameport) { return; } #endif void gameport_register_device(struct gameport_dev *dev); diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 7aea8bc88b32..a356cb65a4ac 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -13,23 +13,33 @@ #include <linux/types.h> #include <linux/major.h> +enum { /* These three have identical behaviour; use the second one if DOS fdisk gets confused about extended/logical partitions starting past cylinder 1023. */ -#define DOS_EXTENDED_PARTITION 5 -#define LINUX_EXTENDED_PARTITION 0x85 -#define WIN98_EXTENDED_PARTITION 0x0f + DOS_EXTENDED_PARTITION = 5, + LINUX_EXTENDED_PARTITION = 0x85, + WIN98_EXTENDED_PARTITION = 0x0f, -#define LINUX_SWAP_PARTITION 0x82 -#define LINUX_RAID_PARTITION 0xfd /* autodetect RAID partition */ + LINUX_SWAP_PARTITION = 0x82, + LINUX_RAID_PARTITION = 0xfd, /* autodetect RAID partition */ -#ifdef CONFIG_SOLARIS_X86_PARTITION -#define SOLARIS_X86_PARTITION LINUX_SWAP_PARTITION -#endif + SOLARIS_X86_PARTITION = LINUX_SWAP_PARTITION, -#define DM6_PARTITION 0x54 /* has DDO: use xlated geom & offset */ -#define EZD_PARTITION 0x55 /* EZ-DRIVE */ -#define DM6_AUX1PARTITION 0x51 /* no DDO: use xlated geom */ -#define DM6_AUX3PARTITION 0x53 /* no DDO: use xlated geom */ + DM6_PARTITION = 0x54, /* has DDO: use xlated geom & offset */ + EZD_PARTITION = 0x55, /* EZ-DRIVE */ + DM6_AUX1PARTITION = 0x51, /* no DDO: use xlated geom */ + DM6_AUX3PARTITION = 0x53, /* no DDO: use xlated geom */ + + FREEBSD_PARTITION = 0xa5, /* FreeBSD Partition ID */ + OPENBSD_PARTITION = 0xa6, /* OpenBSD Partition ID */ + NETBSD_PARTITION = 0xa9, /* NetBSD Partition ID */ + BSDI_PARTITION = 0xb7, /* BSDI Partition ID */ +/* Ours is not to wonder why.. */ + BSD_PARTITION = FREEBSD_PARTITION, + MINIX_PARTITION = 0x81, /* Minix Partition ID */ + UNIXWARE_PARTITION = 0x63, /* Partition ID, same as */ + /* GNU_HURD and SCO Unix */ +}; struct partition { unsigned char boot_ind; /* 0x80 - active */ @@ -117,13 +127,6 @@ struct solaris_x86_vtoc { * BSD disklabel support by Yossi Gottlieb <yogo@math.tau.ac.il> * updated by Marc Espie <Marc.Espie@openbsd.org> */ -#define FREEBSD_PARTITION 0xa5 /* FreeBSD Partition ID */ -#define OPENBSD_PARTITION 0xa6 /* OpenBSD Partition ID */ -#define NETBSD_PARTITION 0xa9 /* NetBSD Partition ID */ -#define BSDI_PARTITION 0xb7 /* BSDI Partition ID */ - -/* Ours is not to wonder why.. */ -#define BSD_PARTITION FREEBSD_PARTITION /* check against BSD src/sys/sys/disklabel.h for consistency */ @@ -182,8 +185,6 @@ struct bsd_disklabel { * and Krzysztof G. Baranowski <kgb@knm.org.pl> */ -#define UNIXWARE_PARTITION 0x63 /* Partition ID, same as */ - /* GNU_HURD and SCO Unix */ #define UNIXWARE_DISKMAGIC (0xCA5E600DUL) /* The disk magic number */ #define UNIXWARE_DISKMAGIC2 (0x600DDEEEUL) /* The slice table magic nr */ #define UNIXWARE_NUMSLICE 16 @@ -233,7 +234,6 @@ struct unixware_disklabel { #endif /* CONFIG_UNIXWARE_DISKLABEL */ #ifdef CONFIG_MINIX_SUBPARTITION -# define MINIX_PARTITION 0x81 /* Minix Partition ID */ # define MINIX_NR_SUBPARTITIONS 4 #endif /* CONFIG_MINIX_SUBPARTITION */ diff --git a/include/linux/module.h b/include/linux/module.h index d32bf62b8fb0..becc3a0e48c8 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -366,10 +366,10 @@ __attribute__((section("__ksymtab"))) = \ #define __EXPORT_SYMBOL_GPL(sym, str) \ const char __kstrtab_##sym[] \ -__attribute__((section(".kstrtab"))) = str; \ -const struct module_symbol __ksymtab_GPLONLY_##sym \ +__attribute__((section(".kstrtab"))) = "GPLONLY_" str; \ +const struct module_symbol __ksymtab_##sym \ __attribute__((section("__ksymtab"))) = \ -{ (unsigned long)&sym, __kstrtab_GPLONLY_##sym } +{ (unsigned long)&sym, __kstrtab_##sym } #if defined(MODVERSIONS) || !defined(CONFIG_MODVERSIONS) #define EXPORT_SYMBOL(var) __EXPORT_SYMBOL(var, __MODULE_STRING(var)) diff --git a/include/linux/smb_fs.h b/include/linux/smb_fs.h index 716e50ec65f9..2200209882ec 100644 --- a/include/linux/smb_fs.h +++ b/include/linux/smb_fs.h @@ -161,84 +161,6 @@ smb_is_open(struct inode *i) } -/* FIXME! the prototype list is probably not correct. Automate? */ - -/* linux/fs/smbfs/file.c */ -extern struct inode_operations smb_file_inode_operations; -extern struct file_operations smb_file_operations; -extern struct address_space_operations smb_file_aops; - -/* linux/fs/smbfs/dir.c */ -extern struct inode_operations smb_dir_inode_operations; -extern struct file_operations smb_dir_operations; -void smb_new_dentry(struct dentry *dentry); -void smb_renew_times(struct dentry *); - -/* linux/fs/smbfs/ioctl.c */ -int smb_ioctl (struct inode *, struct file *, unsigned int, unsigned long); - -/* linux/fs/smbfs/inode.c */ -struct super_block *smb_read_super(struct super_block *, void *, int); -void smb_get_inode_attr(struct inode *, struct smb_fattr *); -void smb_set_inode_attr(struct inode *, struct smb_fattr *); -void smb_invalidate_inodes(struct smb_sb_info *); -int smb_revalidate_inode(struct dentry *); -int smb_notify_change(struct dentry *, struct iattr *); -struct inode *smb_iget(struct super_block *, struct smb_fattr *); - -/* linux/fs/smbfs/proc.c */ -int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp); -__u32 smb_len(unsigned char *); -__u8 *smb_setup_header(struct smb_sb_info *, __u8, __u16, __u16); -int smb_get_rsize(struct smb_sb_info *); -int smb_get_wsize(struct smb_sb_info *); -int smb_newconn(struct smb_sb_info *, struct smb_conn_opt *); -int smb_errno(struct smb_sb_info *); -int smb_close(struct inode *); -int smb_close_fileid(struct dentry *, __u16); -int smb_open(struct dentry *, int); -int smb_proc_read(struct inode *, off_t, int, char *); -int smb_proc_write(struct inode *, off_t, int, const char *); -int smb_proc_create(struct dentry *, __u16, time_t, __u16 *); -int smb_proc_mv(struct dentry *, struct dentry *); -int smb_proc_mkdir(struct dentry *); -int smb_proc_rmdir(struct dentry *); -int smb_proc_unlink(struct dentry *); -int smb_proc_readdir(struct file *filp, void *dirent, filldir_t filldir, - struct smb_cache_control *ctl); -int smb_proc_getattr(struct dentry *, struct smb_fattr *); -int smb_proc_setattr(struct dentry *, struct smb_fattr *); -int smb_proc_settime(struct dentry *, struct smb_fattr *); -int smb_proc_dskattr(struct super_block *, struct statfs *); -int smb_proc_disconnect(struct smb_sb_info *); -int smb_proc_trunc(struct smb_sb_info *, __u16, __u32); -int smb_proc_flush(struct smb_sb_info *, __u16); -void smb_init_root_dirent(struct smb_sb_info *, struct smb_fattr *); - -/* linux/fs/smbfs/sock.c */ -int smb_round_length(int); -int smb_valid_socket(struct inode *); -void smb_close_socket(struct smb_sb_info *); -int smb_request(struct smb_sb_info *server); -int smb_catch_keepalive(struct smb_sb_info *server); -int smb_dont_catch_keepalive(struct smb_sb_info *server); -int smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command, - int ldata, unsigned char *data, - int lparam, unsigned char *param, - int *lrdata, unsigned char **rdata, - int *lrparam, unsigned char **rparam); - -/* fs/smbfs/cache.c */ - -void smb_invalid_dir_cache(struct inode * dir); -void smb_invalidate_dircache_entries(struct dentry *parent); -struct dentry * smb_dget_fpos(struct dentry *dentry, struct dentry *parent, - unsigned long fpos); -int smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir, - struct smb_cache_control *ctrl, struct qstr *qname, - struct smb_fattr *entry); - - #endif /* __KERNEL__ */ #endif /* _LINUX_SMB_FS_H */ diff --git a/include/linux/smbno.h b/include/linux/smbno.h index 0f25e0265393..aa5ac336c8cf 100644 --- a/include/linux/smbno.h +++ b/include/linux/smbno.h @@ -39,7 +39,12 @@ #define ERRbadshare 32 /* Share mode on file conflict with open mode */ #define ERRlock 33 /* Lock request conflicts with existing lock */ #define ERRfilexists 80 /* File in operation already exists */ -#define ERRundocumented1 123 /* Invalid name?? e.g. .tmp* */ +#define ERRinvalidparam 87 /* ERROR_INVALID_PARAMETER */ +#define ERRdiskfull 112 /* ERROR_DISK_FULL */ +#define ERRinvalidname 123 /* ERROR_INVALID_NAME */ +#define ERRdirnotempty 145 /* ERROR_DIR_NOT_EMPTY */ +#define ERRnotlocked 158 /* ERROR_NOT_LOCKED */ +#define ERRexists 183 /* ERROR_ALREADY_EXISTS, see also 80 */ #define ERRbadpipe 230 /* Named pipe invalid */ #define ERRpipebusy 231 /* All instances of pipe are busy */ #define ERRpipeclosing 232 /* named pipe close in progress */ diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 1d49bb8e265a..059329c7759e 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -42,6 +42,7 @@ #if (DEBUG_SPINLOCKS < 1) #define atomic_dec_and_lock(atomic,lock) atomic_dec_and_test(atomic) +#define ATOMIC_DEC_AND_LOCK /* * Your basic spinlocks, allowing only a single CPU anywhere @@ -128,7 +129,7 @@ typedef struct { #endif /* !SMP */ /* "lock on reference count zero" */ -#ifndef atomic_dec_and_lock +#ifndef ATOMIC_DEC_AND_LOCK #include <asm/atomic.h> extern int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock); #endif diff --git a/init/main.c b/init/main.c index d4c15678e4f8..5ef5c9d5e13e 100644 --- a/init/main.c +++ b/init/main.c @@ -94,7 +94,6 @@ extern void ppc_init(void); extern void sysctl_init(void); extern void signals_init(void); extern int init_pcmcia_ds(void); -extern void net_notifier_init(void); extern void free_initmem(void); diff --git a/lib/dec_and_lock.c b/lib/dec_and_lock.c index b9d574ce4eb4..f84d1608bef5 100644 --- a/lib/dec_and_lock.c +++ b/lib/dec_and_lock.c @@ -26,7 +26,7 @@ * store-conditional approach, for example. */ -#ifndef atomic_dec_and_lock +#ifndef ATOMIC_DEC_AND_LOCK int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) { spin_lock(lock); |
