!C99Shell v. 1.0 pre-release build #13!

Software: Apache/2.0.54 (Unix) mod_perl/1.99_09 Perl/v5.8.0 mod_ssl/2.0.54 OpenSSL/0.9.7l DAV/2 FrontPage/5.0.2.2635 PHP/4.4.0 mod_gzip/2.0.26.1a 

uname -a: Linux snow.he.net 4.4.276-v2-mono-1 #1 SMP Wed Jul 21 11:21:17 PDT 2021 i686 

uid=99(nobody) gid=98(nobody) groups=98(nobody) 

Safe-mode: OFF (not secure)

/usr/src/linux-2.4.18-xfs-1.1/drivers/ieee1394/   drwxr-xr-x
Free 318.31 GB of 458.09 GB (69.49%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     nodemgr.c (24.79 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
 * Node information (ConfigROM) collection and management.
 *
 * Copyright (C) 2000 Andreas E. Bombe
 *               2001 Ben Collins <bcollins@debian.net>
 *
 * This code is licensed under the GPL.  See the file COPYING in the root
 * directory of the kernel sources for details.
 */

#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <asm/byteorder.h>
#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"


/* 
 * Basically what we do here is start off retrieving the bus_info block.
 * From there will fill in some info about the node, verify it is of IEEE
 * 1394 type, and that the crc checks out ok. After that we start off with
 * the root directory, and subdirectories. To do this, we retrieve the
 * quadlet header for a directory, find out the length, and retrieve the
 * complete directory entry (be it a leaf or a directory). We then process
 * it and add the info to our structure for that particular node.
 *
 * We verify CRC's along the way for each directory/block/leaf. The
 * entire node structure is generic, and simply stores the information in
 * a way that's easy to parse by the protocol interface.
 */

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 host_info {
    struct hpsb_host *host;
    struct tq_struct task;
    struct list_head list;
};

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;

        ne = kmalloc(sizeof(struct node_entry), SLAB_ATOMIC);
        if (!ne) return NULL;

        INIT_LIST_HEAD(&ne->list);
    INIT_LIST_HEAD(&ne->unit_directories);
        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;
}

static struct node_entry *find_entry_by_guid(u64 guid)
{
        struct list_head *lh;
        struct node_entry *ne;
        
        list_for_each(lh, &node_list) {
                ne = list_entry(lh, struct node_entry, list);
                if (ne->guid == guid) return ne;
        }

        return NULL;
}

static struct node_entry *find_entry_by_nodeid(nodeid_t nodeid)
{
    struct list_head *lh;
    struct node_entry *ne;

    list_for_each(lh, &node_list) {
        ne = list_entry(lh, struct node_entry, list);
        if (ne->nodeid == nodeid) return ne;
    }

    return NULL;
}

int nodemgr_read_quadlet(struct node_entry *ne,
             octlet_t address, quadlet_t *quad)
{
    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 ret;
}

#define CONFIG_ROM_VENDOR_ID        0x03
#define CONFIG_ROM_MODEL_ID        0x17
#define CONFIG_ROM_NODE_CAPABILITES    0x0C
#define CONFIG_ROM_UNIT_DIRECTORY    0xd1
#define CONFIG_ROM_SPECIFIER_ID        0x12 
#define CONFIG_ROM_VERSION        0x13
#define CONFIG_ROM_DESCRIPTOR_LEAF    0x81
#define CONFIG_ROM_DESCRIPTOR_DIRECTORY    0xc1

/* This implementation currently only scans the config rom and its
 * immediate unit directories looking for software_id and
 * software_version entries, in order to get driver autoloading working.
 */

static void nodemgr_process_unit_directory(struct node_entry *ne, 
                       octlet_t address)
{
    struct unit_directory *ud;
    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;
    length = quad >> 16;
    a = address + 4;

    for (i = 0; i < length; i++, a += 4) {
        int code;
        quadlet_t value;

        if (nodemgr_read_quadlet(ne, a, &quad))
            goto unit_directory_error;
        code = quad >> 24;
        value = quad & 0xffffff;

        switch (code) {
        case CONFIG_ROM_VENDOR_ID:
            ud->vendor_id = value;
            ud->flags |= UNIT_DIRECTORY_VENDOR_ID;
            break;

        case CONFIG_ROM_MODEL_ID:
            ud->model_id = value;
            ud->flags |= UNIT_DIRECTORY_MODEL_ID;
            break;

        case CONFIG_ROM_SPECIFIER_ID:
            ud->specifier_id = value;
            ud->flags |= UNIT_DIRECTORY_SPECIFIER_ID;
            break;

        case CONFIG_ROM_VERSION:
            ud->version = value;
            ud->flags |= UNIT_DIRECTORY_VERSION;
            break;

        case CONFIG_ROM_DESCRIPTOR_LEAF:
        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->node_list, &ne->unit_directories);
    list_add_tail(&ud->driver_list, &unit_directory_list);

    return;

unit_directory_error:    
    if (ud != NULL)
        kfree(ud);
}

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, 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("  sw_specifier_id=0x%06x ", ud->specifier_id);
        if (ud->flags & UNIT_DIRECTORY_VERSION)
            HPSB_DEBUG("  sw_version=0x%06x ", ud->version);
    }
#else
    return;
#endif
}

static void nodemgr_process_root_directory(struct node_entry *ne)
{
    octlet_t address;
    quadlet_t quad;
    int length, i;

    address = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
    
    if (nodemgr_read_quadlet(ne, address, &quad))
        return;
    address += 4 + (quad >> 24) * 4;

    if (nodemgr_read_quadlet(ne, address, &quad))
        return;
    length = quad >> 16;
    address += 4;

    for (i = 0; i < length; i++, address += 4) {
        int code, value;

        if (nodemgr_read_quadlet(ne, address, &quad))
            return;
        code = quad >> 24;
        value = quad & 0xffffff;

        switch (code) {
        case CONFIG_ROM_VENDOR_ID:
            ne->vendor_id = value;
            break;

        case CONFIG_ROM_NODE_CAPABILITES:
            ne->capabilities = value;
            break;

        case CONFIG_ROM_UNIT_DIRECTORY:
            nodemgr_process_unit_directory(ne, address + value * 4);
            break;            

        case CONFIG_ROM_DESCRIPTOR_LEAF:
        case CONFIG_ROM_DESCRIPTOR_DIRECTORY:
            /* TODO: read strings... icons? */
            break;
        }
    }

    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 %d", value);
}

#else

static inline void
nodemgr_call_policy(char *verb, struct unit_directory *ud)
{
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
    HPSB_DEBUG("NodeMgr: nodemgr_call_policy(): hotplug not enabled");
#endif
    return;


#endif /* CONFIG_HOTPLUG */

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);
    }
}

int hpsb_register_protocol(struct hpsb_protocol_driver *driver)
{
    struct unit_directory *ud;
    struct list_head *lh;
    unsigned long flags;

        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

    /*
     * 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;
    struct unit_directory *ud;

    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->nodeid = nodeid;
    }

    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(ne->host));

    list_for_each (lh, &ne->unit_directories) {
        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_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);
        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)
{
    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);

    return;
}

/* Used to schedule each nodes config rom probe */
struct node_probe_task {
    nodeid_t nodeid;
    struct hpsb_host *host;
    atomic_t *count;
    struct tq_struct task;
};

/* This is where we probe the nodes for their information and provided
 * features.  */
static void nodemgr_node_probe_one(void *__npt)
{
    struct node_probe_task *npt = (struct node_probe_task *)__npt;
    struct node_entry *ne;
    quadlet_t buffer[5];
    octlet_t guid;

    /* We need to detect when the ConfigROM's generation has changed,
     * so we only update the node's info when it needs to be.  */

    if (read_businfo_block (npt->host, npt->nodeid, buffer, sizeof(buffer) >> 2))
        goto probe_complete;

    if (buffer[1] != IEEE1394_BUSID_MAGIC) {
        /* This isn't a 1394 device */
        HPSB_ERR("Node " NODE_BUS_FMT " isn't an IEEE 1394 device",
             NODE_BUS_ARGS(npt->nodeid));
        goto probe_complete;
    }

    guid = ((u64)buffer[3] << 32) | buffer[4];
    ne = hpsb_guid_get_entry(guid);

    if (!ne)
        nodemgr_create_node(guid, buffer[2], npt->host, npt->nodeid);
    else
        nodemgr_update_node(ne, buffer[2], npt->host, npt->nodeid);

probe_complete:
    atomic_dec(npt->count);

    kfree(npt);

    return;
}

static void nodemgr_node_probe_cleanup(void *__npt)
{
    struct node_probe_task *npt = (struct node_probe_task *)__npt;
    unsigned long flags;
    struct list_head *lh, *next;
    struct node_entry *ne;

    /* If things aren't done yet, reschedule ourselves. */
        if (atomic_read(npt->count)) {
                schedule_task(&npt->task);
        return;
    }

    kfree(npt->count);

    /* Now check to see if we have any nodes that aren't referenced
     * any longer.  */
    write_lock_irqsave(&node_lock, flags);
    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 != npt->host)
            continue;

        /* If the generation didn't get updated, then either the
         * node was removed, or it failed the above probe. Either
         * way, we remove references to it, since they are
         * invalid.  */
        if (!hpsb_node_entry_valid(ne))
            nodemgr_remove_node(ne);
    }
    write_unlock_irqrestore(&node_lock, flags);

    kfree(npt);

    return;
}

static void nodemgr_node_probe(void *__host)
{
    struct hpsb_host *host = (struct hpsb_host *)__host;
    int nodecount = host->node_count;
    struct selfid *sid = (struct selfid *)host->topology_map;
    nodeid_t nodeid = LOCAL_BUS;
    struct node_probe_task *npt;
    atomic_t *count;

    count = kmalloc(sizeof (*count), GFP_KERNEL);

    if (count == NULL) {
        HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe");
        return;
    }

    atomic_set(count, 0);

    for (; nodecount; nodecount--, nodeid++, sid++) {
        while (sid->extended)
            sid++;
        if (!sid->link_active || nodeid == host->node_id)
            continue;

        npt = kmalloc(sizeof (*npt), GFP_KERNEL);

        if (npt == NULL) {
            HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe");
            break;
        }

        INIT_TQUEUE(&npt->task, nodemgr_node_probe_one, npt);
        npt->host = host;
        npt->nodeid = nodeid;
        npt->count = count;

        atomic_inc(count);

        schedule_task(&npt->task);
    }

    /* Now schedule a task to clean things up after the node probes
     * are done.  */
    npt = kmalloc (sizeof (*npt), GFP_KERNEL);

    if (npt == NULL) {
        HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe");
        return;
    }

    INIT_TQUEUE(&npt->task, nodemgr_node_probe_cleanup, npt);
    npt->host = host;
    npt->nodeid = 0;
    npt->count = count;

    schedule_task(&npt->task);

    return;
}

struct node_entry *hpsb_guid_get_entry(u64 guid)
{
        unsigned long flags;
        struct node_entry *ne;

        read_lock_irqsave(&node_lock, flags);
        ne = find_entry_by_guid(guid);
        read_unlock_irqrestore(&node_lock, flags);

        return ne;
}

struct node_entry *hpsb_nodeid_get_entry(nodeid_t nodeid)
{
    unsigned long flags;
    struct node_entry *ne;

    read_lock_irqsave(&node_lock, flags);
    ne = find_entry_by_nodeid(nodeid);
    read_unlock_irqrestore(&node_lock, flags);

    return ne;
}

struct hpsb_host *hpsb_get_host_by_ne(struct node_entry *ne)
{
        if (atomic_read(&ne->generation) != get_hpsb_generation(ne->host))
        return NULL;
        if (ne->nodeid == ne->host->node_id) return ne->host;
        return NULL;
}

int hpsb_guid_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt)
{
        if (atomic_read(&ne->generation) != get_hpsb_generation(ne->host))
        return 0;

        pkt->host = ne->host;
        pkt->node_id = ne->nodeid;
        pkt->generation = atomic_read(&ne->generation);
        return 1;
}

static void nodemgr_add_host(struct hpsb_host *host)
{
    struct host_info *hi = kmalloc (sizeof (struct host_info), GFP_KERNEL);
    unsigned long flags;

    if (!hi) {
        HPSB_ERR ("NodeMgr: out of memory in add host");
        return;
    }

    /* We simply initialize the struct here. We don't start the thread
     * until the first bus reset.  */
    hi->host = host;
    INIT_LIST_HEAD(&hi->list);
    INIT_TQUEUE(&hi->task, nodemgr_node_probe, host);

    spin_lock_irqsave (&host_info_lock, flags);
    list_add_tail (&hi->list, &host_info_list);
    spin_unlock_irqrestore (&host_info_lock, flags);

    return;
}

static void nodemgr_host_reset(struct hpsb_host *host)
{
    struct list_head *lh;
    struct host_info *hi = NULL;
    unsigned long flags;

    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;
            break;
        }
    }

    if (hi == NULL) {
        HPSB_ERR ("NodeMgr: could not process reset of non-existent host");
        goto done_reset_host;
    }

    schedule_task(&hi->task);

done_reset_host:
    spin_unlock_irqrestore (&host_info_lock, flags);

    return;
}

static void nodemgr_remove_host(struct hpsb_host *host)
{
    struct list_head *lh, *next;
    struct node_entry *ne;
    unsigned long flags;

    /* Make sure we have no active scans */
    flush_scheduled_tasks();

    /* First remove all node entries for this host */
    write_lock_irqsave(&node_lock, flags);

    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)
            continue;

        nodemgr_remove_node(ne);
    }
    write_unlock_irqrestore(&node_lock, flags);

    spin_lock_irqsave (&host_info_lock, flags);
    list_for_each_safe(lh, next, &host_info_list) {
        struct host_info *hi = list_entry(lh, struct host_info, list);
        if (hi->host == host) {
            list_del(&hi->list);
            kfree (hi);
            break;
        }
    }

    if (lh == host_info_list.next)
        HPSB_ERR ("NodeMgr: could not remove non-existent host");

    spin_unlock_irqrestore (&host_info_lock, flags);

    return;
}

static struct hpsb_highlevel_ops nodemgr_ops = {
    add_host:    nodemgr_add_host,
    host_reset:    nodemgr_host_reset,
    remove_host:    nodemgr_remove_host,
};

static struct hpsb_highlevel *hl;

void init_ieee1394_nodemgr(void)
{
        hl = hpsb_register_highlevel("Node manager", &nodemgr_ops);
        if (!hl) {
        HPSB_ERR("NodeMgr: out of memory during ieee1394 initialization");
        }
}

void cleanup_ieee1394_nodemgr(void)
{
        hpsb_unregister_highlevel(hl);
}

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0054 ]--