VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 11
-EXTRAVERSION =-pre2
+EXTRAVERSION =-pre3
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
/*
- * 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
* 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++;
*/
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);
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
/*
- * 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
#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;
#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];
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 */
}
#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;
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 */
* 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
/* 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);
}
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)
{
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);
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);
}
#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
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 {
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:
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 */
}
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;
}
(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;
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;
}
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
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;
/* 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:
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;
#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);
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
{
int i, ret;
unsigned long base;
+ unsigned long flags;
+ int big_delay;
switch (when) {
case PBOOK_SLEEP_REQUEST:
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;
}
}
-#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)
#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
*/
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) {
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);
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;
}
}
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;
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);
}
-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. */
{
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);
+ }
}
#include <linux/wait.h>
#include <linux/tqueue.h>
+#include <linux/list.h>
#include <asm/semaphore.h>
#include "ieee1394_types.h"
struct hpsb_host {
/* private fields (hosts, do not use them) */
- struct hpsb_host *next;
+ struct list_head list;
atomic_t generation;
};
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 */
#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>
#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;
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;
}
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);
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)];
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;
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;
}
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;
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);
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);
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);
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);
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);
}
/* 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. */
#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 */
#include "hosts.h"
#include "ieee1394_core.h"
#include "ieee1394_transactions.h"
+#include "ieee1394_hotplug.h"
#include "highlevel.h"
#include "nodemgr.h"
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");
packet->header_size = 4;
packet->data_size = length;
- packet->type = iso;
+ packet->type = hpsb_iso;
packet->tcode = TCODE_ISO_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 */
}
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;
#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
#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"
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;
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;
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;
}
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
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;
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;
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:
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)
{
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);
{
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",
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)
* 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);
unsigned long flags;
if (!hi) {
- HPSB_ERR ("Out of memory in Node Manager");
+ HPSB_ERR ("NodeMgr: out of memory in add host");
return;
}
}
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;
}
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;
/* 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)
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;
{
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");
}
}
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;
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 {
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
#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"
#include "highlevel.h"
#include "ohci1394.h"
-
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
#define OHCI1394_DEBUG
#endif
#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
/* 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)
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 *
***********************************/
{
int i;
unsigned long flags;
- u32 r;
+ u32 r = 0;
spin_lock_irqsave (&ohci->phy_reg_lock, flags);
}
/* 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;
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 {
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);
/* Enable interrupts */
reg_write(ohci, OHCI1394_IntMaskSet,
OHCI1394_masterIntEnable |
- OHCI1394_phyRegRcvd |
OHCI1394_busReset |
OHCI1394_selfIDComplete |
OHCI1394_RSPkt |
} 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];
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.
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)
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) =
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"
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;
}
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;
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,
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,
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
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);
/* 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,
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
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 */
* 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
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);
}
}
}
-#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)
{
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)
#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
#include "ieee1394_types.h"
#include "hosts.h"
#include "ieee1394_core.h"
+#include "highlevel.h"
#include "pcilynx.h"
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,
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;
}
}
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:
}
if (lynx->async.queue != NULL) {
- send_next(lynx, async);
+ send_next(lynx, hpsb_async);
}
spin_unlock(&lynx->async.queue_lock);
}
if (lynx->iso_send.queue != NULL) {
- send_next(lynx, iso);
+ send_next(lynx, hpsb_iso);
}
spin_unlock(&lynx->iso_send.queue_lock);
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;
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
}
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");
}
}
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);
}
}
}
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);
}
}
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;
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;
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);
* 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:
*
* <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>
*/
+\f
+
/*
* Includes
*/
#include "../scsi/sd.h"
#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)
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.
#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)
#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)
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
+
+\f
/**************************************
* General utility functions
#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);
}
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)
{
}
/*
- * 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;
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;
}
/*
- * 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;
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);
}
/*
- * 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)
{
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,
}
/*
- * 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)
}
/*
- * 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;
}
/*
- * 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)
{
/*
* 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;
sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
}
+\f
+
/*********************************************
* 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)
{
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;
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)
{
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;
+ ne = ud->ne;
/*
- * 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);
-
- }
- }
- }
-
- /*
- * 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);
SBP2_DMA_FREE("logout ORB DMA");
}
- 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("reconnect ORB DMA");
- }
-
- 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("login FIFO DMA");
- }
-
- kfree(scsi_id);
-alloc_fail_first:
- SBP2_ERR ("sbp2: Could not allocate memory for scsi_id");
- return(-ENOMEM);
- }
- SBP2_DMA_ALLOC("consistent DMA region for login ORB");
-
- /*
- * 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->speed_code = SPEED_100;
- scsi_id->max_payload_size = MAX_PAYLOAD_S100;
-
- init_waitqueue_head(&scsi_id->sbp2_login_wait);
-
- /*
- * Initialize structures needed for the command orb pool.
- */
- INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse);
- INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed);
- scsi_id->sbp2_command_orb_lock = SPIN_LOCK_UNLOCKED;
- 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).
- */
- 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);
- }
-
- scsi_id->sbp2_total_command_orbs = SBP2_MAX_COMMAND_ORBS;
-
- /*
- * Knock the total command orbs down if we are serializing I/O
- */
- if (serialize_io) {
- scsi_id->sbp2_total_command_orbs = 2; /* one extra for good measure */
- }
-
- /*
- * 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++) {
- if (!hi->scsi_id[i]) {
- hi->scsi_id[i] = scsi_id;
- SBP2_DEBUG("sbp2: New SBP-2 device inserted, SCSI ID = %x", (unsigned int) i);
- break;
- }
- }
-
- /*
- * Make sure we are not out of space
- */
- if (i >= SBP2SCSI_MAX_SCSI_IDS) {
- SBP2_ERR("sbp2: No slots left for SBP-2 device");
- hi->scsi_id[i]->validated = 0;
- return(-EBUSY);
- }
-
- /*
- * Login to the sbp-2 device
- */
- if (sbp2_login_device(hi, hi->scsi_id[i])) {
-
- /*
- * 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;
- }
-
- 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...
- */
-
- 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;
-
- /*
- * Now, step through the unit directory and look for the unit_spec_ID and the unit_sw_version
- */
- 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));
- }
- }
-
- /*
- * Validate unit spec id and unit sw ver to see if this is an SBP-2 device
- */
- if ((be32_to_cpu(unit_spec_id_data) != SBP2_UNIT_SPEC_ID_ENTRY) ||
- (be32_to_cpu(unit_sw_ver_data) != SBP2_SW_VERSION_ENTRY)) {
-
- /*
- * 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);
-}
-
-/*
- * This function removes (cleans-up after) any unvalidated sbp2 devices
- */
-static void sbp2_remove_unvalidated_devices(struct sbp2scsi_host_info *hi)
-{
- 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);
-
- /*
- * 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);
- }
- }
- }
-
- 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;
+ 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("reconnect ORB DMA");
+ }
+
+ 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("login FIFO DMA");
}
+
+ kfree(scsi_id);
+alloc_fail_first:
+ SBP2_ERR ("sbp2: Could not allocate memory for scsi_id");
+ return(-ENOMEM);
}
+ SBP2_DMA_ALLOC("consistent DMA region for login ORB");
/*
- * Give the sbp2 devices a little time to recover after the bus reset
+ * Initialize some of the fields in this structure
*/
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(HZ/2); /* 1/2 second delay */
+ 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;
- /*
- * Spit out what we know from the host
+ init_waitqueue_head(&scsi_id->sbp2_login_wait);
+
+ /*
+ * Initialize structures needed for the command orb pool.
*/
- 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);
+ INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse);
+ INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed);
+ scsi_id->sbp2_command_orb_lock = SPIN_LOCK_UNLOCKED;
+ scsi_id->sbp2_total_command_orbs = 0;
/*
- * Let's try and figure out which devices out there are SBP-2 devices! Loop through all
- * nodes out there.
+ * Make sure that we've gotten ahold of the sbp2 management agent
+ * address. Also figure out the command set being used (SCSI or
+ * RBC).
*/
- 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)) {
+ sbp2_parse_unit_directory(scsi_id);
- 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)) {
+ scsi_id->sbp2_total_command_orbs = SBP2_MAX_COMMAND_ORBS;
- /*
- * Found an SBP-2 device. Now, actually start the device.
- */
- sbp2_start_device(hi, i);
- }
- }
- }
- }
+ /*
+ * Knock the total command orbs down if we are serializing I/O
+ */
+ if (serialize_io) {
+ scsi_id->sbp2_total_command_orbs = 2; /* one extra for good measure */
}
/*
- * This code needs protection
+ * Allocate some extra command orb structures for devices with
+ * 128KB limit.
*/
- sbp2_spin_lock(&hi->sbp2_command_lock, flags);
+ if (scsi_id->sbp2_firmware_revision == SBP2_128KB_BROKEN_FIRMWARE) {
+ scsi_id->sbp2_total_command_orbs *= 4;
+ }
/*
- * 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).
+ * Find an empty spot to stick our scsi id instance data.
*/
- sbp2_remove_unvalidated_devices(hi);
+ 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;
+ }
+ }
/*
- * Complete any pending commands with busy (so they get retried) and remove them from our queue
+ * Create our command orb pool
*/
- 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 (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;
}
/*
- * Now, note that the bus reset is complete (finally!)
+ * Make sure we are not out of space
*/
- hi->bus_reset_in_progress = 0;
+ if (i == SBP2SCSI_MAX_SCSI_IDS) {
+ SBP2_ERR("sbp2: No slots left for SBP-2 device");
+ sbp2_remove_device(hi, scsi_id);
+ return -EBUSY;
+ }
/*
- * Deal with the initial scsi bus scan if needed (since we only now know if there are
- * any sbp2 devices attached)
+ * Login to the sbp-2 device
*/
- if (!no_bus_scan && !hi->initial_scsi_bus_scan_complete && hi->bus_scan_SCpnt) {
+ if (sbp2_login_device(hi, scsi_id)) {
- 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.
+ /*
+ * Login failed... so, just mark him as unvalidated, so
+ * that he gets cleaned up later.
*/
- 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);
- }
+ SBP2_ERR("sbp2: sbp2_login_device failed");
+ sbp2_remove_device(hi, scsi_id);
+ return -EBUSY;
}
- sbp2_spin_unlock(&hi->sbp2_command_lock, flags);
+ /*
+ * Set max retries to something large on the device
+ */
+ sbp2_set_busy_timeout(hi, scsi_id);
+
+ /*
+ * 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);
- return;
+ return 0;
}
-
/*
- * 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
+ * This function removes (cleans-up after) any unvalidated sbp2 devices
*/
-static void sbp2_host_reset(struct hpsb_host *host)
+static void sbp2_remove_device(struct sbp2scsi_host_info *hi,
+ struct scsi_id_instance_data *scsi_id)
{
- 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;
- }
- }
+ /* Complete any pending commands with selection timeout */
+ sbp2scsi_complete_all_commands(hi, scsi_id, DID_NO_CONNECT);
+
+ /* Clean up any other structures */
+ if (scsi_id->sbp2_total_command_orbs) {
+ sbp2util_remove_command_orb_pool(scsi_id, hi);
+ }
- hi->bus_reset_in_progress = 1;
+ 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");
+ }
- wake_up(&hi->sbp2_detection_wait);
- }
+ 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");
}
- sbp2_spin_unlock(&sbp2_host_info_lock, flags);
- return;
-}
-/* XXX: How best to handle these with DMA interface? */
+ 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");
+ }
-#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)
-{
+ 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");
+ }
- /*
- * 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
+\f
/**************************************
* 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)
{
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");
/*
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");
}
/*
- * 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;
}
/*
- * 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)
{
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
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");
}
/*
- * 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)
{
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
*/
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");
}
/*
- * 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)
{
*/
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");
}
}
/*
- * 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:
-
- /*
- * 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;
-
- 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;
+ ud = scsi_id->ud;
- case SBP2_DEVICE_TYPE_AND_LUN_KEY:
+ /* 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);
- /*
- * 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) {
/* 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;
/*
* 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");
}
/*
- * 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,
/*
* 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;
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) {
}
}
- 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);
}
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) {
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;
} 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;
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
/*
* 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");
* 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));
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) &&
(*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);
/*
* 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) ||
}
/*
- * 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 *))
}
/*
- * 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)
{
*/
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;
}
}
return(RCODE_COMPLETE);
}
+\f
/**************************************
* SCSI interface related section
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;
}
/*
- * 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;
}
/*
- * 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");
}
/*
- * 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);
}
/*
- * 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;
}
/*
- * 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 *))
}
/*
- * 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;
}
}
/*
- * 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");
}
/*
- * 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");
}
/*
- * 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)
{
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 {
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)");
}
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)
{
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;
#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
* 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
#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
* 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
/*
* 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;
*/
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
*/
struct list_head sbp2_command_orb_completed;
u32 sbp2_total_command_orbs;
+ /* Node entry, as retrieved from NodeMgr entries */
+ struct node_entry *ne;
};
/*
spinlock_t sbp2_command_lock;
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
struct list_head sbp2_req_inuse;
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.
/*
* 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,
/*
* 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
*/
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);
int ctxMatch;
wait_queue_head_t waitq;
spinlock_t lock;
- unsigned int syt_offset;
+ unsigned int syt_offset;
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 =
}
/* 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);
}
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);
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);
}
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;
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;
& 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;
static void remove_card(struct video_card *video)
{
int i;
- unsigned long flags;
ohci1394_unregister_video(video->ohci, &video_tmpl);
}
kfree(video->it_context);
}
- spin_lock_irqsave(&video1394_cards_lock, flags);
list_del(&video->list);
- spin_unlock_irqrestore(&video1394_cards_lock, flags);
kfree(video);
}
p = list_entry(lh, struct video_card, list);
if (p ->ohci == ohci) {
remove_card(p);
- return;
+ break;
}
}
}
*/
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);
MD_BUG();
return;
}
- if (mddev_map[minor].mddev != NULL) {
+ if (mddev_map[minor].mddev) {
MD_BUG();
return;
}
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);
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);
}
}
-static mddev_t * alloc_mddev (kdev_t dev)
+static mddev_t * alloc_mddev(kdev_t dev)
{
mddev_t *mddev;
mddev = (mddev_t *) kmalloc(sizeof(*mddev), GFP_KERNEL);
if (!mddev)
return NULL;
-
+
memset(mddev, 0, sizeof(*mddev));
mddev->__minor = MINOR(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>";
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;
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;
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;
* 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;
*/
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;
}
}
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;
}
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;
}
}
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--;
#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();
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);
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);
}
}
-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;
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);
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)
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;
* 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;
}
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;
}
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;
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();
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;
}
* 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)
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;
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);
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);
}
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;
MD_BUG();
}
-static void free_mddev (mddev_t *mddev)
+static void free_mddev(mddev_t *mddev)
{
if (!mddev) {
MD_BUG();
{
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;
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;
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;
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;
}
/*
*/
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);
skip:
return 0;
}
-#undef GETBLK_FAILED
+#undef GETBLK_FAILED
static void set_this_disk(mddev_t *mddev, mdk_rdev_t *rdev)
{
err = 0;
ITERATE_RDEV(mddev,rdev,tmp) {
- printk("md: ");
+ printk(KERN_INFO "md: ");
if (rdev->faulty)
printk("(skipping faulty ");
if (rdev->alias_device)
}
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;
}
*
* 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;
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;
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;
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;
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;
}
#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;
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;
}
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;
}
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));
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;
((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;
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;
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);
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);
}
first = 0;
}
}
-
+
/*
* Kick all rdevs that are not in the
* descriptor array:
if (rdev->desc_nr == -1)
kick_rdev_from_array(rdev);
}
-
+
/*
* Do a final reality check.
*/
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:
#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;
}
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);
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)])
#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;
}
} 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();
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);
}
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;
}
#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;
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
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;
}
#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) {
/*
* 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);
* 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;
}
/*
* 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;
}
-static void autorun_array (mddev_t *mddev)
+static void autorun_array(mddev_t *mddev)
{
mdk_rdev_t *rdev;
struct md_list_head *tmp;
return;
}
- printk("md: running: ");
+ printk(KERN_INFO "md: running: ");
ITERATE_RDEV(mddev,rdev,tmp) {
printk("<%s>", partition_name(rdev->dev));
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
*/
*
* 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;
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);
}
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);
}
autorun_array(mddev);
}
- printk("md: ... autorun DONE.\n");
+ printk(KERN_INFO "md: ... autorun DONE.\n");
}
/*
#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;
}
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;
}
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;
}
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);
#undef AUTORUNNING
-static int get_version (void * arg)
+static int get_version(void * arg)
{
mdu_version_t ver;
}
#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;
#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;
#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;
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);
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;
}
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);
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);
}
#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;
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;
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;
}
MD_BUG();
return -EINVAL;
}
-
+
err = mddev->pers->diskop(mddev, &disk, DISKOP_HOT_REMOVE_DISK);
if (err == -EBUSY) {
MD_BUG();
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;
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;
}
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;
}
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);
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;
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;
}
}
#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))
}
#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;
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;
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;
*/
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;
}
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;
}
}
*/
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;
}
}
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 */
}
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;
}
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
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)
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;
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;
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;
kfree(thread);
}
-void md_recover_arrays (void)
+void md_recover_arrays(void)
{
if (!md_recovery_thread) {
MD_BUG();
}
-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;
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;
return 0;
}
-static int status_unused (char * page)
+static int status_unused(char * page)
{
int sz = 0, i = 0;
mdk_rdev_t *rdev;
}
-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;
/*
* Should not happen.
- */
+ */
if (!max_blocks) {
MD_BUG();
return 0;
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);
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);
}
}
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();
return 0;
}
-int unregister_md_personality (int pnum)
+int unregister_md_personality(int pnum)
{
if (pnum >= MAX_PERSONALITY) {
MD_BUG();
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;
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;
}
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;
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;
}
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.
* 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);
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;
* 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;
* 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;
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))
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);
goto restart;
}
printk(KERN_INFO "md: recovery thread finished ...\n");
-
+
}
int md_notify_reboot(struct notifier_block *this,
priority: INT_MAX, /* before any real devices */
};
-static void md_geninit (void)
+static void md_geninit(void)
{
int i;
#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);
/* 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;
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;
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;
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;
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;
}
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);
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]) {
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);
}
}
}
#else /* It is a MODULE */
-int init_module (void)
+int init_module(void)
{
return md_init();
}
}
-void cleanup_module (void)
+void cleanup_module(void)
{
md_unregister_thread(md_recovery_thread);
devfs_unregister(devfs_handle);
blk_size[MAJOR_NR] = NULL;
max_readahead[MAJOR_NR] = NULL;
hardsect_size[MAJOR_NR] = NULL;
-
+
free_device_names();
}
*/
#define DRV_NAME "8139too"
-#define DRV_VERSION "0.9.18a"
+#define DRV_VERSION "0.9.19"
#include <linux/config.h>
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
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;
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);
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) {
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)
}
-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;
}
}
- 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
* 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
*/
#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. */
IntrNormalSummary=0x025f, IntrAbnormalSummary=0xCD20,
};
+#define DEFAULT_INTR 0x00f1cd65
+
/* Bits in the RxMode register. */
enum rx_mode_bits {
AcceptErr=0x20, AcceptRunt=0x10,
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);
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);
\f
}
}
-\f
+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;
return i;
}
init_ring(dev);
+ spin_lock_irq(&np->lock);
init_registers(dev);
+ spin_unlock_irq(&np->lock);
netif_start_queue(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);
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++;
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++) {
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)
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) {
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);
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. */
/* 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,
{
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);
}
}
}
+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;
}
#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;
}
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;
}
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];
long ioaddr = dev->base_addr;
int csr5;
int entry;
- int missed;
+ int csr8;
int rx = 0;
int tx = 0;
int oi = 0;
}
}
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++;
}
}
- 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",
*/
#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>
/* The RIDs */
#define RID_CAPABILITIES 0xFF00
+#define RID_RSSI 0xFF04
#define RID_CONFIG 0xFF10
#define RID_SSID 0xFF11
#define RID_APLIST 0xFF12
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 */
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
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 );
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;
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 */
/* 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;
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;
/* 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;
* 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>
#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 */
#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
*/
* 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;
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);
*
* 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;
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;
*
* 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;
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;
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;
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);
#define HERMES_FRAME_LEN_MAX (2304)
#define HERMES_MAX_MULTICAST (16)
#define HERMES_MAGIC (0x7d1f)
+#define HERMES_SYMBOL_MAX_VER (14)
/*
* Hermes register offsets
#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)
#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);
#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) \
-/* 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/
* 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>
#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");
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,
/* 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
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 */
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);
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 :
/* 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);
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;
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';
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;
}
* 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;
}
}
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;
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);
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;
}
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:
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;
#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
#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)
#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 */
-/* 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/
* Copyright notice & release notes in file orinoco.c
*/
+#include <linux/config.h>
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
/*====================================================================*/
-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");
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
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
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
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
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
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
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
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
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
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
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
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
4802 Falcon
4803 Hawk
4806 CPX8216
+ 4d68 20268
5600 SM56 PCI Modem
1057 0300 SM56 PCI Speakerphone Modem
1057 0301 SM56 PCI Voice Modem
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
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
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
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]
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]
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
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
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
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
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
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
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
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
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
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
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!)
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
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
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)
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
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)
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
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
11f5 Computing Devices International
11f6 Compex
0112 ENet100VG4
+ 0113 FreedomLine 100
1401 ReadyLink 2000
2011 RL100-ATX 10/100
2201 ReadyLink 100TX (Winbond W89C840)
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
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
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
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
1384 Reality Simulation Systems Inc
1385 Netgear
620a GA620
+ f311 FA311
1386 Video Domain Technologies
1387 Systran Corp
1388 Hitachi Information Technology Co Ltd
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
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
# 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]
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
3d3d 0125 Oxygen VX1
3d3d 0127 Permedia3 Create!
000a GLINT R3
+ 3d3d 0121 Oxygen VX1
0100 Permedia II 2D+3D
1004 Permedia
3d04 Permedia
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
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
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
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
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
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)
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]
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
00c0 7899A
00c1 7899B
00c3 7899D
+ 00c5 RAID subsystem HBA
00cf 7899P
907f Atronics
2015 IDE-2015PL
10 OHCI
80 Unspecified
Fe USB Device
- 04 Fiber Channel
+ 04 Fibre Channel
05 SMBus
06 InfiniBand
C 0d Wireless controller
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
error handling will be discarded.
*/
-static char *verstr = "20010812";
+static char *verstr = "20011003";
#include <linux/module.h>
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;
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);
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;
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);
*
*/
-#define CLGEN_VERSION "1.9.8"
+#define CLGEN_VERSION "1.9.9"
#include <linux/config.h>
#include <linux/module.h>
{ 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 },
#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>
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 */
}
#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>
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,
{
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;
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])))
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;
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);
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);
}
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;
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);
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;
}
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;
/*
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)
#define __KERNEL_SYSCALLS__
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/sched.h>
#include <linux/errno.h>
*/
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)
{
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)
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)
/* 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
/*
{ 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, {"", ""}}
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;
{
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) &&
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;
#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
#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
}
#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)) {
}
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)) {
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'.
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;
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
* 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;
* ..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;
* 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;
}
}
}
- 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.
* 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;
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
};
*
* 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;
}
};
-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
-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;
}
*/
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);
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;
}
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);
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
#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;
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);
}
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;
+}
*/
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;
[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 )
{
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);
}
}
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,};
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);
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);
/* 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']) {
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;
}
printk ( "\n" );
- bforget(bh);
+ put_dev_sector(sect);
return 1;
}
-int ibm_partition(struct gendisk *, kdev_t, unsigned long, int);
+int ibm_partition(struct gendisk *, struct block_device *, unsigned long, int);
*/
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. */
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 >
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;
vb->num_sectors) == 1)
first_part_minor++;
}
- brelse(bh);
+ put_dev_sector(sect);
}
printk(" >\n");
err = 1;
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");
*
* 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. */
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;
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);
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,
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");
*
* 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;
}
*
* 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;
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. */
*
* 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;
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);
*
* 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;
}
*
* 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;
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;
}
* 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:
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_ */
#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
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.
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;
}
/* ... 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);
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
#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);
}
* 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,
* 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;
}
/*
*/
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];
* 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))
} /* 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));
#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(" >");
}
}
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;
}
#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);
#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;
} * 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++) {
current_minor++;
}
printk("\n");
- brelse(bh);
+ put_dev_sector(sect);
return 1;
}
#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);
#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 */
} *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;
}
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
current_minor++;
}
printk("\n");
- brelse(bh);
+ put_dev_sector(sect);
return 1;
}
* 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
#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. */
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 */
first_part_minor++;
}
printk("\n");
- brelse(bh);
+ put_dev_sector(sect);
return 1;
}
-
#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);
#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 */
#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++)
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;
}
}
* 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);
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.
#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
#include <asm/page.h>
#include "smb_debug.h"
+#include "proto.h"
/*
* Force the next attempt to use the cache to be a timeout.
#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 *);
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;
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);
*/
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;
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);
}
#include <linux/smb_fs.h>
#include "smb_debug.h"
+#include "proto.h"
static int
smb_fsync(struct file *file, struct dentry * dentry, int datasync)
#include "smb_debug.h"
#include "getopt.h"
+#include "proto.h"
/* Always pick a default string */
#ifdef CONFIG_SMB_NLS_REMOTE
}
/* 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 },
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);
}
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;
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,
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
/*
* 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;
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:
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
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);
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;
* 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;
#include <asm/uaccess.h>
+#include "proto.h"
+
int
smb_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
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)))
#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))
#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 *);
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;
/* 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)
/* */
/*****************************************************************************/
-__u8 *
+static __u8 *
smb_encode_smb_length(__u8 * p, __u32 len)
{
*p = 0;
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 &&
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);
/* 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
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
return size;
}
+/*
+ * Convert SMB error codes to -E... errno values.
+ */
int
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;
}
/*
}
/*
- * 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);
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
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
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;
}
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) */
}
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;
}
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",
{
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;
}
result = 0;
if (server->rcls != 0)
- result = -smb_errno(server);
+ result = smb_errno(server);
out:
return result;
struct smb_sb_info *server = &(sb->u.smbfs_sb);
int result;
char *p;
+ long unit;
smb_lock_server(server);
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;
-}
--- /dev/null
+/*
+ * 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);
#include <asm/uaccess.h>
#include "smb_debug.h"
+#include "proto.h"
static int
*/
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;
*/
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;
}
static LIST_HEAD(vfsmntlist);
+static struct vfsmount *root_vfsmnt;
static struct list_head *mount_hashtable;
static int hash_mask, hash_bits;
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;
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)
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)
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
* /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 ...
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;
}
/*
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)
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);
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;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
+ if (!check_mnt(nd->mnt))
+ return -EINVAL;
+
if (nd->dentry != nd->mnt->mnt_root)
return -EINVAL;
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)
void __init mount_root(void)
{
+ struct nameidata root_nd;
struct file_system_type * fs_type;
struct super_block * sb;
struct vfsmount *vfsmnt;
void *handle;
char path[64];
int path_start = -1;
+ char *name = "/dev/root";
#ifdef CONFIG_ROOT_NFS
void *data;
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);
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,
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;
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);
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;
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 */
} 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);
{
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);
} 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
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;
#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;
d++;
i--;
} while (i);
+ init_mount_tree();
}
/*
- * 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
* 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)
* 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.
*/
#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>
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);
#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 */
* 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 */
* 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
#endif /* CONFIG_UNIXWARE_DISKLABEL */
#ifdef CONFIG_MINIX_SUBPARTITION
-# define MINIX_PARTITION 0x81 /* Minix Partition ID */
# define MINIX_NR_SUBPARTITIONS 4
#endif /* CONFIG_MINIX_SUBPARTITION */
#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))
}
-/* 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 */
#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 */
#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
#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
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);
* 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);