From e169cfbef46d62e042614ffafa8880eed1d894bb Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 23 Nov 2009 14:53:09 -0700 Subject: of/flattree: merge find_flat_dt_string and initial_boot_params Merge common code between Microblaze and PowerPC. Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Tested-by: Michal Simek --- drivers/of/Kconfig | 4 ++++ drivers/of/Makefile | 1 + drivers/of/fdt.c | 21 +++++++++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 drivers/of/fdt.c (limited to 'drivers') diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index d2fa27c5c1b2..462825e03123 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -1,3 +1,7 @@ +config OF_FLATTREE + bool + depends on OF + config OF_DEVICE def_bool y depends on OF && (SPARC || PPC_OF || MICROBLAZE) diff --git a/drivers/of/Makefile b/drivers/of/Makefile index bdfb5f5d4b06..f232cc98ce00 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -1,4 +1,5 @@ obj-y = base.o +obj-$(CONFIG_OF_FLATTREE) += fdt.o obj-$(CONFIG_OF_DEVICE) += device.o platform.o obj-$(CONFIG_OF_GPIO) += gpio.o obj-$(CONFIG_OF_I2C) += of_i2c.o diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c new file mode 100644 index 000000000000..9faa9a5cbdf0 --- /dev/null +++ b/drivers/of/fdt.c @@ -0,0 +1,21 @@ +/* + * Functions for working with the Flattened Device Tree data format + * + * Copyright 2009 Benjamin Herrenschmidt, IBM Corp + * benh@kernel.crashing.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include +#include + +struct boot_param_header *initial_boot_params; + +char *find_flat_dt_string(u32 offset) +{ + return ((char *)initial_boot_params) + + initial_boot_params->off_dt_strings + offset; +} -- cgit v1.2.2 From c8cb7a59842c0b512b44f6f818cdb0b5a3ddc89e Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 23 Nov 2009 18:54:23 -0700 Subject: of/flattree: merge of_scan_flat_dt Merge common code between PowerPC and Microblaze Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Tested-by: Michal Simek --- drivers/of/fdt.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 9faa9a5cbdf0..dd9057cb7aa7 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -19,3 +19,67 @@ char *find_flat_dt_string(u32 offset) return ((char *)initial_boot_params) + initial_boot_params->off_dt_strings + offset; } + +/** + * of_scan_flat_dt - scan flattened tree blob and call callback on each. + * @it: callback function + * @data: context data pointer + * + * This function is used to scan the flattened device-tree, it is + * used to extract the memory information at boot before we can + * unflatten the tree + */ +int __init of_scan_flat_dt(int (*it)(unsigned long node, + const char *uname, int depth, + void *data), + void *data) +{ + unsigned long p = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + int rc = 0; + int depth = -1; + + do { + u32 tag = *((u32 *)p); + char *pathp; + + p += 4; + if (tag == OF_DT_END_NODE) { + depth--; + continue; + } + if (tag == OF_DT_NOP) + continue; + if (tag == OF_DT_END) + break; + if (tag == OF_DT_PROP) { + u32 sz = *((u32 *)p); + p += 8; + if (initial_boot_params->version < 0x10) + p = _ALIGN(p, sz >= 8 ? 8 : 4); + p += sz; + p = _ALIGN(p, 4); + continue; + } + if (tag != OF_DT_BEGIN_NODE) { + pr_err("Invalid tag %x in flat device tree!\n", tag); + return -EINVAL; + } + depth++; + pathp = (char *)p; + p = _ALIGN(p + strlen(pathp) + 1, 4); + if ((*pathp) == '/') { + char *lp, *np; + for (lp = NULL, np = pathp; *np; np++) + if ((*np) == '/') + lp = np+1; + if (lp != NULL) + pathp = lp; + } + rc = it(p, pathp, depth, data); + if (rc != 0) + break; + } while (1); + + return rc; +} -- cgit v1.2.2 From 819d2819303654c6829d572e698e2d0021c08599 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 23 Nov 2009 19:44:23 -0700 Subject: of/flattree: merge of_get_flat_dt_root Merge common code between PowerPC and MicroBlaze Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Tested-by: Michal Simek --- drivers/of/fdt.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index dd9057cb7aa7..f41d739aa2f7 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -83,3 +83,19 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, return rc; } + +/** + * of_get_flat_dt_root - find the root node in the flat blob + */ +unsigned long __init of_get_flat_dt_root(void) +{ + unsigned long p = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + + while (*((u32 *)p) == OF_DT_NOP) + p += 4; + BUG_ON(*((u32 *)p) != OF_DT_BEGIN_NODE); + p += 4; + return _ALIGN(p + strlen((char *)p) + 1, 4); +} + -- cgit v1.2.2 From ca900cfa2944448bdb76e1246f282e59bc65f472 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 23 Nov 2009 20:06:59 -0700 Subject: of/flattree: merge of_get_flat_dt_prop Merge common code between PowerPC and Microblaze Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Tested-by: Michal Simek --- drivers/of/fdt.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index f41d739aa2f7..b17a9086cbfc 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -99,3 +99,46 @@ unsigned long __init of_get_flat_dt_root(void) return _ALIGN(p + strlen((char *)p) + 1, 4); } +/** + * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr + * + * This function can be used within scan_flattened_dt callback to get + * access to properties + */ +void *__init of_get_flat_dt_prop(unsigned long node, const char *name, + unsigned long *size) +{ + unsigned long p = node; + + do { + u32 tag = *((u32 *)p); + u32 sz, noff; + const char *nstr; + + p += 4; + if (tag == OF_DT_NOP) + continue; + if (tag != OF_DT_PROP) + return NULL; + + sz = *((u32 *)p); + noff = *((u32 *)(p + 4)); + p += 8; + if (initial_boot_params->version < 0x10) + p = _ALIGN(p, sz >= 8 ? 8 : 4); + + nstr = find_flat_dt_string(noff); + if (nstr == NULL) { + pr_warning("Can't find property index name !\n"); + return NULL; + } + if (strcmp(name, nstr) == 0) { + if (size) + *size = sz; + return (void *)p; + } + p += sz; + p = _ALIGN(p, 4); + } while (1); +} + -- cgit v1.2.2 From 00e38efd90f27518ec96b37b1c7773e3ac529966 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 23 Nov 2009 20:07:00 -0700 Subject: of/flattree: Merge of_flat_dt_is_compatible Merge common code between PowerPC and Microblaze Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Tested-by: Michal Simek --- drivers/of/fdt.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index b17a9086cbfc..5cdd958db9af 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -142,3 +142,27 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name, } while (1); } +/** + * of_flat_dt_is_compatible - Return true if given node has compat in compatible list + * @node: node to test + * @compat: compatible string to compare with compatible list. + */ +int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) +{ + const char *cp; + unsigned long cplen, l; + + cp = of_get_flat_dt_prop(node, "compatible", &cplen); + if (cp == NULL) + return 0; + while (cplen > 0) { + if (strncasecmp(cp, compat, strlen(compat)) == 0) + return 1; + l = strlen(cp) + 1; + cp += l; + cplen -= l; + } + + return 0; +} + -- cgit v1.2.2 From bbd33931a08362f78266a4016211a35947b91041 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 23 Nov 2009 20:07:00 -0700 Subject: of/flattree: Merge unflatten_dt_node Merge common code between PowerPC and MicroBlaze Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Tested-by: Michal Simek --- drivers/of/fdt.c | 200 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 5cdd958db9af..6852ecf6d1e1 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -166,3 +166,203 @@ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) return 0; } +static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, + unsigned long align) +{ + void *res; + + *mem = _ALIGN(*mem, align); + res = (void *)*mem; + *mem += size; + + return res; +} + +/** + * unflatten_dt_node - Alloc and populate a device_node from the flat tree + * @p: pointer to node in flat tree + * @dad: Parent struct device_node + * @allnextpp: pointer to ->allnext from last allocated device_node + * @fpsize: Size of the node path up at the current depth. + */ +unsigned long __init unflatten_dt_node(unsigned long mem, + unsigned long *p, + struct device_node *dad, + struct device_node ***allnextpp, + unsigned long fpsize) +{ + struct device_node *np; + struct property *pp, **prev_pp = NULL; + char *pathp; + u32 tag; + unsigned int l, allocl; + int has_name = 0; + int new_format = 0; + + tag = *((u32 *)(*p)); + if (tag != OF_DT_BEGIN_NODE) { + pr_err("Weird tag at start of node: %x\n", tag); + return mem; + } + *p += 4; + pathp = (char *)*p; + l = allocl = strlen(pathp) + 1; + *p = _ALIGN(*p + l, 4); + + /* version 0x10 has a more compact unit name here instead of the full + * path. we accumulate the full path size using "fpsize", we'll rebuild + * it later. We detect this because the first character of the name is + * not '/'. + */ + if ((*pathp) != '/') { + new_format = 1; + if (fpsize == 0) { + /* root node: special case. fpsize accounts for path + * plus terminating zero. root node only has '/', so + * fpsize should be 2, but we want to avoid the first + * level nodes to have two '/' so we use fpsize 1 here + */ + fpsize = 1; + allocl = 2; + } else { + /* account for '/' and path size minus terminal 0 + * already in 'l' + */ + fpsize += l; + allocl = fpsize; + } + } + + np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, + __alignof__(struct device_node)); + if (allnextpp) { + memset(np, 0, sizeof(*np)); + np->full_name = ((char *)np) + sizeof(struct device_node); + if (new_format) { + char *fn = np->full_name; + /* rebuild full path for new format */ + if (dad && dad->parent) { + strcpy(fn, dad->full_name); +#ifdef DEBUG + if ((strlen(fn) + l + 1) != allocl) { + pr_debug("%s: p: %d, l: %d, a: %d\n", + pathp, (int)strlen(fn), + l, allocl); + } +#endif + fn += strlen(fn); + } + *(fn++) = '/'; + memcpy(fn, pathp, l); + } else + memcpy(np->full_name, pathp, l); + prev_pp = &np->properties; + **allnextpp = np; + *allnextpp = &np->allnext; + if (dad != NULL) { + np->parent = dad; + /* we temporarily use the next field as `last_child'*/ + if (dad->next == NULL) + dad->child = np; + else + dad->next->sibling = np; + dad->next = np; + } + kref_init(&np->kref); + } + while (1) { + u32 sz, noff; + char *pname; + + tag = *((u32 *)(*p)); + if (tag == OF_DT_NOP) { + *p += 4; + continue; + } + if (tag != OF_DT_PROP) + break; + *p += 4; + sz = *((u32 *)(*p)); + noff = *((u32 *)((*p) + 4)); + *p += 8; + if (initial_boot_params->version < 0x10) + *p = _ALIGN(*p, sz >= 8 ? 8 : 4); + + pname = find_flat_dt_string(noff); + if (pname == NULL) { + pr_info("Can't find property name in list !\n"); + break; + } + if (strcmp(pname, "name") == 0) + has_name = 1; + l = strlen(pname) + 1; + pp = unflatten_dt_alloc(&mem, sizeof(struct property), + __alignof__(struct property)); + if (allnextpp) { + if (strcmp(pname, "linux,phandle") == 0) { + np->node = *((u32 *)*p); + if (np->linux_phandle == 0) + np->linux_phandle = np->node; + } + if (strcmp(pname, "ibm,phandle") == 0) + np->linux_phandle = *((u32 *)*p); + pp->name = pname; + pp->length = sz; + pp->value = (void *)*p; + *prev_pp = pp; + prev_pp = &pp->next; + } + *p = _ALIGN((*p) + sz, 4); + } + /* with version 0x10 we may not have the name property, recreate + * it here from the unit name if absent + */ + if (!has_name) { + char *p1 = pathp, *ps = pathp, *pa = NULL; + int sz; + + while (*p1) { + if ((*p1) == '@') + pa = p1; + if ((*p1) == '/') + ps = p1 + 1; + p1++; + } + if (pa < ps) + pa = p1; + sz = (pa - ps) + 1; + pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, + __alignof__(struct property)); + if (allnextpp) { + pp->name = "name"; + pp->length = sz; + pp->value = pp + 1; + *prev_pp = pp; + prev_pp = &pp->next; + memcpy(pp->value, ps, sz - 1); + ((char *)pp->value)[sz - 1] = 0; + pr_debug("fixed up name for %s -> %s\n", pathp, + (char *)pp->value); + } + } + if (allnextpp) { + *prev_pp = NULL; + np->name = of_get_property(np, "name", NULL); + np->type = of_get_property(np, "device_type", NULL); + + if (!np->name) + np->name = ""; + if (!np->type) + np->type = ""; + } + while (tag == OF_DT_BEGIN_NODE) { + mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); + tag = *((u32 *)(*p)); + } + if (tag != OF_DT_END_NODE) { + pr_err("Weird tag at end of node: %x\n", tag); + return mem; + } + *p += 4; + return mem; +} -- cgit v1.2.2 From 41f880091c15b039ffcc8b3d831656b81517a6d3 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 23 Nov 2009 20:07:01 -0700 Subject: of/flattree: Merge unflatten_device_tree Merge common code between PowerPC and MicroBlaze Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Tested-by: Michal Simek --- drivers/of/fdt.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 6852ecf6d1e1..43d236cbc17b 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -9,6 +9,8 @@ * version 2 as published by the Free Software Foundation. */ +#include +#include #include #include @@ -366,3 +368,53 @@ unsigned long __init unflatten_dt_node(unsigned long mem, *p += 4; return mem; } + +/** + * unflatten_device_tree - create tree of device_nodes from flat blob + * + * unflattens the device-tree passed by the firmware, creating the + * tree of struct device_node. It also fills the "name" and "type" + * pointers of the nodes so the normal device-tree walking functions + * can be used. + */ +void __init unflatten_device_tree(void) +{ + unsigned long start, mem, size; + struct device_node **allnextp = &allnodes; + + pr_debug(" -> unflatten_device_tree()\n"); + + /* First pass, scan for size */ + start = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + size = unflatten_dt_node(0, &start, NULL, NULL, 0); + size = (size | 3) + 1; + + pr_debug(" size is %lx, allocating...\n", size); + + /* Allocate memory for the expanded device tree */ + mem = lmb_alloc(size + 4, __alignof__(struct device_node)); + mem = (unsigned long) __va(mem); + + ((u32 *)mem)[size / 4] = 0xdeadbeef; + + pr_debug(" unflattening %lx...\n", mem); + + /* Second pass, do actual unflattening */ + start = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + unflatten_dt_node(mem, &start, NULL, &allnextp, 0); + if (*((u32 *)start) != OF_DT_END) + pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start)); + if (((u32 *)mem)[size / 4] != 0xdeadbeef) + pr_warning("End of tree marker overwritten: %08x\n", + ((u32 *)mem)[size / 4]); + *allnextp = NULL; + + /* Get pointer to OF "/chosen" node for use everywhere */ + of_chosen = of_find_node_by_path("/chosen"); + if (of_chosen == NULL) + of_chosen = of_find_node_by_path("/chosen@0"); + + pr_debug(" <- unflatten_device_tree()\n"); +} -- cgit v1.2.2 From 02af11b03fce3ddb264d7873d7a2e295e697938c Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 23 Nov 2009 20:16:45 -0700 Subject: of: merge prom_{add,remove,modify}_property Merge common code between PowerPC and MicroBlaze Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Tested-by: Michal Simek --- drivers/of/base.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index e6627b2320f1..ec56739eb247 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -658,3 +658,119 @@ err0: return ret; } EXPORT_SYMBOL(of_parse_phandles_with_args); + +/** + * prom_add_property - Add a property to a node + */ +int prom_add_property(struct device_node *np, struct property *prop) +{ + struct property **next; + unsigned long flags; + + prop->next = NULL; + write_lock_irqsave(&devtree_lock, flags); + next = &np->properties; + while (*next) { + if (strcmp(prop->name, (*next)->name) == 0) { + /* duplicate ! don't insert it */ + write_unlock_irqrestore(&devtree_lock, flags); + return -1; + } + next = &(*next)->next; + } + *next = prop; + write_unlock_irqrestore(&devtree_lock, flags); + +#ifdef CONFIG_PROC_DEVICETREE + /* try to add to proc as well if it was initialized */ + if (np->pde) + proc_device_tree_add_prop(np->pde, prop); +#endif /* CONFIG_PROC_DEVICETREE */ + + return 0; +} + +/** + * prom_remove_property - Remove a property from a node. + * + * Note that we don't actually remove it, since we have given out + * who-knows-how-many pointers to the data using get-property. + * Instead we just move the property to the "dead properties" + * list, so it won't be found any more. + */ +int prom_remove_property(struct device_node *np, struct property *prop) +{ + struct property **next; + unsigned long flags; + int found = 0; + + write_lock_irqsave(&devtree_lock, flags); + next = &np->properties; + while (*next) { + if (*next == prop) { + /* found the node */ + *next = prop->next; + prop->next = np->deadprops; + np->deadprops = prop; + found = 1; + break; + } + next = &(*next)->next; + } + write_unlock_irqrestore(&devtree_lock, flags); + + if (!found) + return -ENODEV; + +#ifdef CONFIG_PROC_DEVICETREE + /* try to remove the proc node as well */ + if (np->pde) + proc_device_tree_remove_prop(np->pde, prop); +#endif /* CONFIG_PROC_DEVICETREE */ + + return 0; +} + +/* + * prom_update_property - Update a property in a node. + * + * Note that we don't actually remove it, since we have given out + * who-knows-how-many pointers to the data using get-property. + * Instead we just move the property to the "dead properties" list, + * and add the new property to the property list + */ +int prom_update_property(struct device_node *np, + struct property *newprop, + struct property *oldprop) +{ + struct property **next; + unsigned long flags; + int found = 0; + + write_lock_irqsave(&devtree_lock, flags); + next = &np->properties; + while (*next) { + if (*next == oldprop) { + /* found the node */ + newprop->next = oldprop->next; + *next = newprop; + oldprop->next = np->deadprops; + np->deadprops = oldprop; + found = 1; + break; + } + next = &(*next)->next; + } + write_unlock_irqrestore(&devtree_lock, flags); + + if (!found) + return -ENODEV; + +#ifdef CONFIG_PROC_DEVICETREE + /* try to add to proc as well if it was initialized */ + if (np->pde) + proc_device_tree_update_prop(np->pde, newprop, oldprop); +#endif /* CONFIG_PROC_DEVICETREE */ + + return 0; +} -- cgit v1.2.2 From f7b3a8355ba6cad251297844a0bdd08898ea36e0 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 24 Nov 2009 03:26:58 -0700 Subject: of/flattree: Merge early_init_dt_check_for_initrd() Merge common code between PowerPC and Microblaze Signed-off-by: Grant Likely Tested-by: Wolfram Sang Acked-by: Benjamin Herrenschmidt --- drivers/of/fdt.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 43d236cbc17b..6ad98e85dc93 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -369,6 +370,42 @@ unsigned long __init unflatten_dt_node(unsigned long mem, return mem; } +#ifdef CONFIG_BLK_DEV_INITRD +/** + * early_init_dt_check_for_initrd - Decode initrd location from flat tree + * @node: reference to node containing initrd location ('chosen') + */ +void __init early_init_dt_check_for_initrd(unsigned long node) +{ + unsigned long len; + u32 *prop; + + pr_debug("Looking for initrd properties... "); + + prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len); + if (prop) { + initrd_start = (unsigned long) + __va(of_read_ulong(prop, len/4)); + + prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len); + if (prop) { + initrd_end = (unsigned long) + __va(of_read_ulong(prop, len/4)); + initrd_below_start_ok = 1; + } else { + initrd_start = 0; + } + } + + pr_debug("initrd_start=0x%lx initrd_end=0x%lx\n", + initrd_start, initrd_end); +} +#else +inline void early_init_dt_check_for_initrd(unsigned long node) +{ +} +#endif /* CONFIG_BLK_DEV_INITRD */ + /** * unflatten_device_tree - create tree of device_nodes from flat blob * -- cgit v1.2.2 From f00abd94918c9780f9d2d961fc0e419c11457922 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 24 Nov 2009 03:27:10 -0700 Subject: of/flattree: Merge earlyinit_dt_scan_root() Merge common code between PowerPC and Microblaze Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt Tested-by: Wolfram Sang --- drivers/of/fdt.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 6ad98e85dc93..be200be47269 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -15,6 +15,9 @@ #include #include +int __initdata dt_root_addr_cells; +int __initdata dt_root_size_cells; + struct boot_param_header *initial_boot_params; char *find_flat_dt_string(u32 offset) @@ -406,6 +409,29 @@ inline void early_init_dt_check_for_initrd(unsigned long node) } #endif /* CONFIG_BLK_DEV_INITRD */ +/** + * early_init_dt_scan_root - fetch the top level address and size cells + */ +int __init early_init_dt_scan_root(unsigned long node, const char *uname, + int depth, void *data) +{ + u32 *prop; + + if (depth != 0) + return 0; + + prop = of_get_flat_dt_prop(node, "#size-cells", NULL); + dt_root_size_cells = (prop == NULL) ? 1 : *prop; + pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells); + + prop = of_get_flat_dt_prop(node, "#address-cells", NULL); + dt_root_addr_cells = (prop == NULL) ? 2 : *prop; + pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells); + + /* break now */ + return 1; +} + /** * unflatten_device_tree - create tree of device_nodes from flat blob * -- cgit v1.2.2 From 83f7a06eb479e2aeb83536e77a2cb14cc2285e32 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 24 Nov 2009 03:37:56 -0700 Subject: of/flattree: merge dt_mem_next_cell Merge common code between PowerPC and Microblaze Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt Tested-by: Wolfram Sang --- drivers/of/fdt.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index be200be47269..ebce509b0886 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -432,6 +432,14 @@ int __init early_init_dt_scan_root(unsigned long node, const char *uname, return 1; } +u64 __init dt_mem_next_cell(int s, u32 **cellp) +{ + u32 *p = *cellp; + + *cellp = p + s; + return of_read_number(p, s); +} + /** * unflatten_device_tree - create tree of device_nodes from flat blob * -- cgit v1.2.2 From 86e032213424958b45564d0cc96b3316641a49d3 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 10 Dec 2009 23:42:21 -0700 Subject: of/flattree: merge early_init_dt_scan_chosen() Merge common code between PowerPC and Microblaze. This patch splits the arch-specific stuff out into a new function, early_init_dt_scan_chosen_arch(). Signed-off-by: Grant Likely Tested-by: Wolfram Sang Acked-by: Benjamin Herrenschmidt --- drivers/of/fdt.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index ebce509b0886..616a4767a950 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -15,6 +15,10 @@ #include #include +#ifdef CONFIG_PPC +#include +#endif /* CONFIG_PPC */ + int __initdata dt_root_addr_cells; int __initdata dt_root_size_cells; @@ -440,6 +444,40 @@ u64 __init dt_mem_next_cell(int s, u32 **cellp) return of_read_number(p, s); } +int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, + int depth, void *data) +{ + unsigned long l; + char *p; + + pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); + + if (depth != 1 || + (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) + return 0; + + early_init_dt_check_for_initrd(node); + + /* Retreive command line */ + p = of_get_flat_dt_prop(node, "bootargs", &l); + if (p != NULL && l > 0) + strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE)); + +#ifdef CONFIG_CMDLINE +#ifndef CONFIG_CMDLINE_FORCE + if (p == NULL || l == 0 || (l == 1 && (*p) == 0)) +#endif + strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); +#endif /* CONFIG_CMDLINE */ + + early_init_dt_scan_chosen_arch(node); + + pr_debug("Command line is: %s\n", cmd_line); + + /* break now */ + return 1; +} + /** * unflatten_device_tree - create tree of device_nodes from flat blob * -- cgit v1.2.2 From bc85b25e5de17d714e8001cb3dc0feb66eac2750 Mon Sep 17 00:00:00 2001 From: Alessandro Rubini Date: Sat, 19 Dec 2009 19:45:43 +0800 Subject: hwrng: nomadik - Add hardware RNG driver The hardware random number generator by ST is used in both the Nomadik 8815 SoC and the U8500. It returns 16 bits every 400ns with automatic delay if a read is issued too early. It depends on PLAT_NOMADIK. Signed-off-by: Alessandro Rubini Acked-by: Andrea Gallo Acked-by: Matt Mackall Signed-off-by: Herbert Xu --- drivers/char/hw_random/Kconfig | 12 ++++ drivers/char/hw_random/Makefile | 1 + drivers/char/hw_random/nomadik-rng.c | 103 +++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 drivers/char/hw_random/nomadik-rng.c (limited to 'drivers') diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 87060266ef91..6ea1014697d1 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -186,3 +186,15 @@ config HW_RANDOM_MXC_RNGA module will be called mxc-rnga. If unsure, say Y. + +config HW_RANDOM_NOMADIK + tristate "ST-Ericsson Nomadik Random Number Generator support" + depends on HW_RANDOM && PLAT_NOMADIK + ---help--- + This driver provides kernel-side support for the Random Number + Generator hardware found on ST-Ericsson SoCs (8815 and 8500). + + To compile this driver as a module, choose M here: the + module will be called nomadik-rng. + + If unsure, say Y. diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index 5eeb1303f0d0..4273308aa1e3 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o +obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o diff --git a/drivers/char/hw_random/nomadik-rng.c b/drivers/char/hw_random/nomadik-rng.c new file mode 100644 index 000000000000..a8b4c4010144 --- /dev/null +++ b/drivers/char/hw_random/nomadik-rng.c @@ -0,0 +1,103 @@ +/* + * Nomadik RNG support + * Copyright 2009 Alessandro Rubini + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +static int nmk_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) +{ + void __iomem *base = (void __iomem *)rng->priv; + + /* + * The register is 32 bits and gives 16 random bits (low half). + * A subsequent read will delay the core for 400ns, so we just read + * once and accept the very unlikely very small delay, even if wait==0. + */ + *(u16 *)data = __raw_readl(base + 8) & 0xffff; + return 2; +} + +/* we have at most one RNG per machine, granted */ +static struct hwrng nmk_rng = { + .name = "nomadik", + .read = nmk_rng_read, +}; + +static int nmk_rng_probe(struct amba_device *dev, struct amba_id *id) +{ + void __iomem *base; + int ret; + + ret = amba_request_regions(dev, dev->dev.init_name); + if (ret) + return ret; + ret = -ENOMEM; + base = ioremap(dev->res.start, resource_size(&dev->res)); + if (!base) + goto out_release; + nmk_rng.priv = (unsigned long)base; + ret = hwrng_register(&nmk_rng); + if (ret) + goto out_unmap; + return 0; + +out_unmap: + iounmap(base); +out_release: + amba_release_regions(dev); + return ret; +} + +static int nmk_rng_remove(struct amba_device *dev) +{ + void __iomem *base = (void __iomem *)nmk_rng.priv; + hwrng_unregister(&nmk_rng); + iounmap(base); + amba_release_regions(dev); + return 0; +} + +static struct amba_id nmk_rng_ids[] = { + { + .id = 0x000805e1, + .mask = 0x000fffff, /* top bits are rev and cfg: accept all */ + }, + {0, 0}, +}; + +static struct amba_driver nmk_rng_driver = { + .drv = { + .owner = THIS_MODULE, + .name = "rng", + }, + .probe = nmk_rng_probe, + .remove = nmk_rng_remove, + .id_table = nmk_rng_ids, +}; + +static int __init nmk_rng_init(void) +{ + return amba_driver_register(&nmk_rng_driver); +} + +static void __devexit nmk_rng_exit(void) +{ + amba_driver_unregister(&nmk_rng_driver); +} + +module_init(nmk_rng_init); +module_exit(nmk_rng_exit); + +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From b6353f4f36f03a12edaf3fa5365b475a28106035 Mon Sep 17 00:00:00 2001 From: Stephane Chatty Date: Tue, 22 Dec 2009 23:04:17 +0100 Subject: HID: Support for 3M multitouch panel Add support for 3M multitouch panels. Signed-off-by: Stephane Chatty [jkosina@suse.cz: fix build failure because of inconsistent 3M/MMM defines] Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 ++ drivers/hid/Makefile | 1 + drivers/hid/hid-3m-pct.c | 291 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 + 5 files changed, 303 insertions(+) create mode 100644 drivers/hid/hid-3m-pct.c (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 24d90ea246ce..a05133f645bc 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -55,6 +55,13 @@ source "drivers/hid/usbhid/Kconfig" menu "Special HID drivers" depends on HID +config HID_3M_PCT + tristate "3M PCT" if EMBEDDED + depends on USB_HID + default !EMBEDDED + ---help--- + Support for 3M PCT touch screens. + config HID_A4TECH tristate "A4 tech" if EMBEDDED depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 0de2dff5542c..1bdfb97910f1 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -19,6 +19,7 @@ ifdef CONFIG_LOGIRUMBLEPAD2_FF hid-logitech-objs += hid-lg2ff.o endif +obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_BELKIN) += hid-belkin.o diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c new file mode 100644 index 000000000000..6d11e3dbbbff --- /dev/null +++ b/drivers/hid/hid-3m-pct.c @@ -0,0 +1,291 @@ +/* + * HID driver for 3M PCT multitouch panels + * + * Copyright (c) 2009 Stephane Chatty + * + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include + +MODULE_VERSION("0.6"); +MODULE_AUTHOR("Stephane Chatty "); +MODULE_DESCRIPTION("3M PCT multitouch panels"); +MODULE_LICENSE("GPL"); + +#include "hid-ids.h" + +struct mmm_finger { + __s32 x, y; + __u8 rank; + bool touch, valid; +}; + +struct mmm_data { + struct mmm_finger f[10]; + __u8 curid, num; + bool touch, valid; +}; + +static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + switch (usage->hid & HID_USAGE_PAGE) { + + case HID_UP_BUTTON: + return -1; + + case HID_UP_GENDESK: + switch (usage->hid) { + case HID_GD_X: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_X); + /* touchscreen emulation */ + input_set_abs_params(hi->input, ABS_X, + field->logical_minimum, + field->logical_maximum, 0, 0); + return 1; + case HID_GD_Y: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_Y); + /* touchscreen emulation */ + input_set_abs_params(hi->input, ABS_Y, + field->logical_minimum, + field->logical_maximum, 0, 0); + return 1; + } + return 0; + + case HID_UP_DIGITIZER: + switch (usage->hid) { + /* we do not want to map these: no input-oriented meaning */ + case 0x14: + case 0x23: + case HID_DG_INPUTMODE: + case HID_DG_DEVICEINDEX: + case HID_DG_CONTACTCOUNT: + case HID_DG_CONTACTMAX: + case HID_DG_INRANGE: + case HID_DG_CONFIDENCE: + return -1; + case HID_DG_TIPSWITCH: + /* touchscreen emulation */ + hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); + return 1; + case HID_DG_CONTACTID: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_TRACKING_ID); + return 1; + } + /* let hid-input decide for the others */ + return 0; + + case 0xff000000: + /* we do not want to map these: no input-oriented meaning */ + return -1; + } + + return 0; +} + +static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if (usage->type == EV_KEY || usage->type == EV_ABS) + clear_bit(usage->code, *bit); + + return 0; +} + +/* + * this function is called when a whole packet has been received and processed, + * so that it can decide what to send to the input layer. + */ +static void mmm_filter_event(struct mmm_data *md, struct input_dev *input) +{ + struct mmm_finger *oldest = 0; + bool pressed = false, released = false; + int i; + + /* + * we need to iterate on all fingers to decide if we have a press + * or a release event in our touchscreen emulation. + */ + for (i = 0; i < 10; ++i) { + struct mmm_finger *f = &md->f[i]; + if (!f->valid) { + /* this finger is just placeholder data, ignore */ + } else if (f->touch) { + /* this finger is on the screen */ + input_event(input, EV_ABS, ABS_MT_TRACKING_ID, i); + input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y); + input_mt_sync(input); + /* + * touchscreen emulation: maintain the age rank + * of this finger, decide if we have a press + */ + if (f->rank == 0) { + f->rank = ++(md->num); + if (f->rank == 1) + pressed = true; + } + if (f->rank == 1) + oldest = f; + } else { + /* this finger took off the screen */ + /* touchscreen emulation: maintain age rank of others */ + int j; + + for (j = 0; j < 10; ++j) { + struct mmm_finger *g = &md->f[j]; + if (g->rank > f->rank) { + g->rank--; + if (g->rank == 1) + oldest = g; + } + } + f->rank = 0; + --(md->num); + if (md->num == 0) + released = true; + } + f->valid = 0; + } + + /* touchscreen emulation */ + if (oldest) { + if (pressed) + input_event(input, EV_KEY, BTN_TOUCH, 1); + input_event(input, EV_ABS, ABS_X, oldest->x); + input_event(input, EV_ABS, ABS_Y, oldest->y); + } else if (released) { + input_event(input, EV_KEY, BTN_TOUCH, 0); + } +} + +/* + * this function is called upon all reports + * so that we can accumulate contact point information, + * and call input_mt_sync after each point. + */ +static int mmm_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct mmm_data *md = hid_get_drvdata(hid); + /* + * strangely, this function can be called before + * field->hidinput is initialized! + */ + if (hid->claimed & HID_CLAIMED_INPUT) { + struct input_dev *input = field->hidinput->input; + switch (usage->hid) { + case HID_DG_TIPSWITCH: + md->touch = value; + break; + case HID_DG_CONFIDENCE: + md->valid = value; + break; + case HID_DG_CONTACTID: + if (md->valid) { + md->curid = value; + md->f[value].touch = md->touch; + md->f[value].valid = 1; + } + break; + case HID_GD_X: + if (md->valid) + md->f[md->curid].x = value; + break; + case HID_GD_Y: + if (md->valid) + md->f[md->curid].y = value; + break; + case HID_DG_CONTACTCOUNT: + mmm_filter_event(md, input); + break; + } + } + + /* we have handled the hidinput part, now remains hiddev */ + if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) + hid->hiddev_hid_event(hid, field, usage, value); + + return 1; +} + +static int mmm_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + struct mmm_data *md; + + md = kzalloc(sizeof(struct mmm_data), GFP_KERNEL); + if (!md) { + dev_err(&hdev->dev, "cannot allocate 3M data\n"); + return -ENOMEM; + } + hid_set_drvdata(hdev, md); + + ret = hid_parse(hdev); + if (!ret) + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + + if (ret) + kfree(md); + return ret; +} + +static void mmm_remove(struct hid_device *hdev) +{ + hid_hw_stop(hdev); + kfree(hid_get_drvdata(hdev)); + hid_set_drvdata(hdev, NULL); +} + +static const struct hid_device_id mmm_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) }, + { } +}; +MODULE_DEVICE_TABLE(hid, mmm_devices); + +static const struct hid_usage_id mmm_grabbed_usages[] = { + { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, + { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} +}; + +static struct hid_driver mmm_driver = { + .name = "3m-pct", + .id_table = mmm_devices, + .probe = mmm_probe, + .remove = mmm_remove, + .input_mapping = mmm_input_mapping, + .input_mapped = mmm_input_mapped, + .usage_table = mmm_grabbed_usages, + .event = mmm_event, +}; + +static int __init mmm_init(void) +{ + return hid_register_driver(&mmm_driver); +} + +static void __exit mmm_exit(void) +{ + hid_unregister_driver(&mmm_driver); +} + +module_init(mmm_init); +module_exit(mmm_exit); +MODULE_LICENSE("GPL"); + diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 80792d38d25c..70c25a056205 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1248,6 +1248,7 @@ EXPORT_SYMBOL_GPL(hid_disconnect); /* a list of devices for which there is a specialized driver on HID bus */ static const struct hid_device_id hid_blacklist[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 3839340e293a..3d55f983dbaf 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -18,6 +18,9 @@ #ifndef HID_IDS_H_FILE #define HID_IDS_H_FILE +#define USB_VENDOR_ID_3M 0x0596 +#define USB_DEVICE_ID_3M1968 0x0500 + #define USB_VENDOR_ID_A4TECH 0x09da #define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 #define USB_DEVICE_ID_A4TECH_X5_005D 0x000a -- cgit v1.2.2 From 4b186f72033611c2b526c7341534e71ee4afd222 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 23 Dec 2009 13:12:32 +0100 Subject: HID: make 3M PCT touchscreen driver standalone config option The point behind 'default !EMBEDDED' for certain HID drivers that simple and straightforward quirks for HID devices (which are implemented as drivers on HID bus) wouldn't have to be enabled separately, if the device is otherwise more-or-less HID standard compliant. But this driver is rather standalone driver, so we'd want to have it normally selectable. Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index a05133f645bc..0c8ce3a68d27 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -56,9 +56,8 @@ menu "Special HID drivers" depends on HID config HID_3M_PCT - tristate "3M PCT" if EMBEDDED + tristate "3M PCT" depends on USB_HID - default !EMBEDDED ---help--- Support for 3M PCT touch screens. -- cgit v1.2.2 From d3fb5454a8474d5d22c8f8fe4d043b05732d91d5 Mon Sep 17 00:00:00 2001 From: Stephane Chatty Date: Mon, 4 Jan 2010 12:04:08 +0100 Subject: HID: add support for Stantum multitouch panel Added support for the Stantum multitouch panel. Signed-off-by: Stephane Chatty Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 6 + drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 + drivers/hid/hid-stantum.c | 283 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 294 insertions(+) create mode 100644 drivers/hid/hid-stantum.c (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 0c8ce3a68d27..84272c690310 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -247,6 +247,12 @@ config HID_SONY ---help--- Support for Sony PS3 controller. +config HID_STANTUM + tristate "Stantum" if EMBEDDED + depends on USB_HID + ---help--- + Support for Stantum multitouch panel. + config HID_SUNPLUS tristate "Sunplus" if EMBEDDED depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 1bdfb97910f1..f8dc5bac79bd 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o obj-$(CONFIG_HID_SONY) += hid-sony.o +obj-$(CONFIG_HID_STANTUM) += hid-stantum.o obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 70c25a056205..6462c923805f 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1339,6 +1339,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) }, { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 3d55f983dbaf..07e056b0e188 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -393,6 +393,9 @@ #define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034 #define USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST 0x0046 +#define USB_VENDOR_ID_STANTUM 0x1f87 +#define USB_DEVICE_ID_MTP 0x0002 + #define USB_VENDOR_ID_SUN 0x0430 #define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c new file mode 100644 index 000000000000..add965dab932 --- /dev/null +++ b/drivers/hid/hid-stantum.c @@ -0,0 +1,283 @@ +/* + * HID driver for Stantum multitouch panels + * + * Copyright (c) 2009 Stephane Chatty + * + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include + +MODULE_VERSION("0.6"); +MODULE_AUTHOR("Stephane Chatty "); +MODULE_DESCRIPTION("Stantum HID multitouch panels"); +MODULE_LICENSE("GPL"); + +#include "hid-ids.h" + +struct stantum_data { + __s32 x, y, z, w, h; /* x, y, pressure, width, height */ + __u16 id; /* touch id */ + bool valid; /* valid finger data, or just placeholder? */ + bool first; /* first finger in the HID packet? */ + bool activity; /* at least one active finger so far? */ +}; + +static int stantum_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + switch (usage->hid & HID_USAGE_PAGE) { + + case HID_UP_GENDESK: + switch (usage->hid) { + case HID_GD_X: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_X); + /* touchscreen emulation */ + input_set_abs_params(hi->input, ABS_X, + field->logical_minimum, + field->logical_maximum, 0, 0); + return 1; + case HID_GD_Y: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_Y); + /* touchscreen emulation */ + input_set_abs_params(hi->input, ABS_Y, + field->logical_minimum, + field->logical_maximum, 0, 0); + return 1; + } + return 0; + + case HID_UP_DIGITIZER: + switch (usage->hid) { + case HID_DG_INRANGE: + case HID_DG_CONFIDENCE: + case HID_DG_INPUTMODE: + case HID_DG_DEVICEINDEX: + case HID_DG_CONTACTCOUNT: + case HID_DG_CONTACTMAX: + case HID_DG_TIPPRESSURE: + return -1; + + case HID_DG_TIPSWITCH: + /* touchscreen emulation */ + hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); + return 1; + + case HID_DG_WIDTH: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_TOUCH_MAJOR); + return 1; + case HID_DG_HEIGHT: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_TOUCH_MINOR); + input_set_abs_params(hi->input, ABS_MT_ORIENTATION, + 1, 1, 0, 0); + return 1; + case HID_DG_CONTACTID: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_TRACKING_ID); + return 1; + + } + return 0; + + case 0xff000000: + /* no input-oriented meaning */ + return -1; + } + + return 0; +} + +static int stantum_input_mapped(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if (usage->type == EV_KEY || usage->type == EV_ABS) + clear_bit(usage->code, *bit); + + return 0; +} + +/* + * this function is called when a whole finger has been parsed, + * so that it can decide what to send to the input layer. + */ +static void stantum_filter_event(struct stantum_data *sd, + struct input_dev *input) +{ + bool wide; + + if (!sd->valid) { + /* + * touchscreen emulation: if the first finger is not valid and + * there previously was finger activity, this is a release + */ + if (sd->first && sd->activity) { + input_event(input, EV_KEY, BTN_TOUCH, 0); + sd->activity = false; + } + return; + } + + input_event(input, EV_ABS, ABS_MT_TRACKING_ID, sd->id); + input_event(input, EV_ABS, ABS_MT_POSITION_X, sd->x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, sd->y); + + wide = (sd->w > sd->h); + input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); + input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, wide ? sd->w : sd->h); + input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, wide ? sd->h : sd->w); + +#if 0 + /* MT_PRESSURE does not exist yet */ + input_event(input, EV_ABS, ABS_MT_PRESSURE, sd->z); +#endif + + input_mt_sync(input); + sd->valid = false; + sd->first = false; + + /* touchscreen emulation */ + if (sd->first) { + if (!sd->activity) { + input_event(input, EV_KEY, BTN_TOUCH, 1); + sd->activity = true; + } + input_event(input, EV_ABS, ABS_X, sd->x); + input_event(input, EV_ABS, ABS_Y, sd->y); + } +} + + +static int stantum_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct stantum_data *sd = hid_get_drvdata(hid); + + if (hid->claimed & HID_CLAIMED_INPUT) { + struct input_dev *input = field->hidinput->input; + + switch (usage->hid) { + case HID_DG_INRANGE: + /* this is the last field in a finger */ + stantum_filter_event(sd, input); + break; + case HID_DG_WIDTH: + sd->w = value; + break; + case HID_DG_HEIGHT: + sd->h = value; + break; + case HID_GD_X: + sd->x = value; + break; + case HID_GD_Y: + sd->y = value; + break; + case HID_DG_TIPPRESSURE: + sd->z = value; + break; + case HID_DG_CONTACTID: + sd->id = value; + break; + case HID_DG_CONFIDENCE: + sd->valid = !!value; + break; + case 0xff000002: + /* this comes only before the first finger */ + sd->first = true; + break; + + default: + /* ignore the others */ + return 1; + } + } + + /* we have handled the hidinput part, now remains hiddev */ + if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) + hid->hiddev_hid_event(hid, field, usage, value); + + return 1; +} + +static int stantum_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int ret; + struct stantum_data *sd; + + sd = kmalloc(sizeof(struct stantum_data), GFP_KERNEL); + if (!sd) { + dev_err(&hdev->dev, "cannot allocate Stantum data\n"); + return -ENOMEM; + } + sd->valid = false; + sd->first = false; + sd->activity = false; + hid_set_drvdata(hdev, sd); + + ret = hid_parse(hdev); + if (!ret) + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + + if (ret) + kfree(sd); + + return ret; +} + +static void stantum_remove(struct hid_device *hdev) +{ + hid_hw_stop(hdev); + kfree(hid_get_drvdata(hdev)); + hid_set_drvdata(hdev, NULL); +} + +static const struct hid_device_id stantum_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) }, + { } +}; +MODULE_DEVICE_TABLE(hid, stantum_devices); + +static const struct hid_usage_id stantum_grabbed_usages[] = { + { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, + { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} +}; + +static struct hid_driver stantum_driver = { + .name = "stantum", + .id_table = stantum_devices, + .probe = stantum_probe, + .remove = stantum_remove, + .input_mapping = stantum_input_mapping, + .input_mapped = stantum_input_mapped, + .usage_table = stantum_grabbed_usages, + .event = stantum_event, +}; + +static int __init stantum_init(void) +{ + return hid_register_driver(&stantum_driver); +} + +static void __exit stantum_exit(void) +{ + hid_unregister_driver(&stantum_driver); +} + +module_init(stantum_init); +module_exit(stantum_exit); + -- cgit v1.2.2 From 92688c0c3c1c9e2daf705d307e8fda1b5a180d26 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Mon, 4 Jan 2010 12:04:59 +0100 Subject: HID: make Stantum driver standalone config option Analogically to commit "HID: make 3M PCT touchscreen driver standalone config option", remove the dependency of Stantum driver on CONFIG_EMBEDDED, as it is a standalone driver rather than device quirk. Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 84272c690310..5f73774164d8 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -248,7 +248,7 @@ config HID_SONY Support for Sony PS3 controller. config HID_STANTUM - tristate "Stantum" if EMBEDDED + tristate "Stantum" depends on USB_HID ---help--- Support for Stantum multitouch panel. -- cgit v1.2.2 From cf2f765f1896064e34c6f0f2ef896ff058dd5c06 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Mon, 4 Jan 2010 12:20:56 +0100 Subject: HID: handle joysticks with large number of buttons Current HID code doesn't properly handle HID joysticks which have larger number of buttons than what fits into current range reserved for BTN_JOYSTICK. One such joystick reported to not work properly is Saitek X52 Pro Flight System. We can't extend the range to fit more buttons in, because of backwards compatibility reasons. Therefore this patch introduces a new BTN_TRIGGER_HAPPY range, and uses these to map the buttons which are over BTN_JOYSTICK limit. Acked-by: Dmitry Torokhov [for the input.h part] Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 5862b0f3b55d..dad7aae9c975 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -198,7 +198,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel switch (field->application) { case HID_GD_MOUSE: case HID_GD_POINTER: code += 0x110; break; - case HID_GD_JOYSTICK: code += 0x120; break; + case HID_GD_JOYSTICK: + if (code <= 0xf) + code += BTN_JOYSTICK; + else + code += BTN_TRIGGER_HAPPY; + break; case HID_GD_GAMEPAD: code += 0x130; break; default: switch (field->physical) { -- cgit v1.2.2 From 722612cd51cf1b574c89dff57cc5dbedf1f645bb Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Tue, 5 Jan 2010 11:45:52 +0100 Subject: HID: fix parsing of local delimiter with size 0 Acording to HID standard 1.11, value 0 allows for size being 0. Local delimiter tag has has 0 one of the possible values. Therefore we need to handle this case properly, to be fully compliant with the specification. Reported-by: Marcin Tolysz Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 6462c923805f..a4b496c68259 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -387,7 +387,8 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) __u32 data; unsigned n; - if (item->size == 0) { + /* Local delimiter could have value 0, which allows size to be 0 */ + if (item->size == 0 && item->tag != HID_LOCAL_ITEM_TAG_DELIMITER) { dbg_hid("item data expected for local item\n"); return -1; } -- cgit v1.2.2 From 54a6593d65e638ad7e1e8cc986159d76054dab4b Mon Sep 17 00:00:00 2001 From: Stefan Glasenhardt Date: Tue, 5 Jan 2010 23:30:30 +0100 Subject: HID: allow disabling hard-coded ISO-layout for Apple keyboards This patch adds a new option named "iso_layout" to the driver "hid-apple.ko", to allow disabling of the hard-coded ISO-layout. Disabling the hard-coded layout solves the problem that the kernel-module only works perfectly for the english/american version of the Apple aluminum keyboard. Other versions have swapped keys, e.g. the "<"-key is swapped with "^"-key on the german keyboard. There is a very long bug-entry on Launchpad to this problem: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/214786 Signed-off-by: Stefan Glasenhardt Signed-off-by: Jiri Kosina --- drivers/hid/hid-apple.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 4b96e7a898cf..1433cbbaa99f 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -40,6 +40,11 @@ module_param(fnmode, uint, 0644); MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, " "[1] = fkeyslast, 2 = fkeysfirst)"); +static unsigned int iso_layout = 1; +module_param(iso_layout, uint, 0644); +MODULE_PARM_DESC(iso_layout, "Enable/Disable hardcoded ISO-layout of the keyboard. " + "(0 = disabled, [1] = enabled)"); + struct apple_sc { unsigned long quirks; unsigned int fn_on; @@ -199,11 +204,13 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, } } - if (asc->quirks & APPLE_ISO_KEYBOARD) { - trans = apple_find_translation(apple_iso_keyboard, usage->code); - if (trans) { - input_event(input, usage->type, trans->to, value); - return 1; + if (iso_layout) { + if (asc->quirks & APPLE_ISO_KEYBOARD) { + trans = apple_find_translation(apple_iso_keyboard, usage->code); + if (trans) { + input_event(input, usage->type, trans->to, value); + return 1; + } } } -- cgit v1.2.2 From faad98f29606d9d3c6bddae7c88693be37d2fb43 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Fri, 8 Jan 2010 14:19:21 +1100 Subject: crypto: geode-aes - access .cip instead of .blk in cipher mode The fallback code in cipher mode touch the union fallback.blk instead of fallback.cip. This is wrong because we use the cipher and not the blockcipher. This did not show any side effects yet because both types / structs contain the same element right now. Signed-off-by: Roel Kluin Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Herbert Xu --- drivers/crypto/geode-aes.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c index 4801162919d9..03e71b1a5128 100644 --- a/drivers/crypto/geode-aes.c +++ b/drivers/crypto/geode-aes.c @@ -135,8 +135,8 @@ static int geode_setkey_cip(struct crypto_tfm *tfm, const u8 *key, /* * The requested key size is not supported by HW, do a fallback */ - op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; - op->fallback.blk->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK); + op->fallback.cip->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; + op->fallback.cip->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK); ret = crypto_cipher_setkey(op->fallback.cip, key, len); if (ret) { @@ -263,7 +263,7 @@ static int fallback_init_cip(struct crypto_tfm *tfm) if (IS_ERR(op->fallback.cip)) { printk(KERN_ERR "Error allocating fallback algo %s\n", name); - return PTR_ERR(op->fallback.blk); + return PTR_ERR(op->fallback.cip); } return 0; -- cgit v1.2.2 From d67dec5b2cc208215de21dc7806945bf6a6e85d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Sun, 10 Jan 2010 17:59:22 +0100 Subject: HID: make USB device id constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The id_table field of the struct usb_device_id is constant in so it is worth to make the initialization data also constant. The semantic match that finds this kind of pattern is as follows: (http://coccinelle.lip6.fr/) // @r@ disable decl_init,const_decl_init; identifier I1, I2, x; @@ struct I1 { ... const struct I2 *x; ... }; @s@ identifier r.I1, y; identifier r.x, E; @@ struct I1 y = { .x = E, }; @c@ identifier r.I2; identifier s.E; @@ const struct I2 E[] = ... ; @depends on !c@ identifier r.I2; identifier s.E; @@ + const struct I2 E[] = ...; // Signed-off-by: Márton Németh Cc: Julia Lawall Cc: cocci@diku.dk Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 0258289f3b3e..e72751d6e3e7 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -1342,7 +1342,7 @@ static int hid_reset_resume(struct usb_interface *intf) #endif /* CONFIG_PM */ -static struct usb_device_id hid_usb_ids [] = { +static const struct usb_device_id hid_usb_ids[] = { { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, .bInterfaceClass = USB_INTERFACE_CLASS_HID }, { } /* Terminating entry */ -- cgit v1.2.2 From 74f292ca8c7a2b9370f80d97a49e48174f4c7635 Mon Sep 17 00:00:00 2001 From: Gary Stein Date: Wed, 13 Jan 2010 00:25:58 +0100 Subject: HID: add driver for the Logitech Flight System G940 Implements a new USB-HID for Force Feedback based on the normal Logitech Force Feedback code and FF-Memless. Currently only supports the FF_CONSTANT effect although the joystick appears to support additional non-standard ones. Signed-off-by: Gary Stein Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 8 +++ drivers/hid/Makefile | 3 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-lg.c | 7 +- drivers/hid/hid-lg.h | 6 ++ drivers/hid/hid-lg3ff.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-lgff.c | 1 + 8 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 drivers/hid/hid-lg3ff.c (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 5f73774164d8..317049b80c35 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -189,6 +189,14 @@ config LOGIRUMBLEPAD2_FF Say Y here if you want to enable force feedback support for Logitech Rumblepad 2 devices. +config LOGIG940_FF + bool "Logitech Flight System G940 force feedback support" + depends on HID_LOGITECH + select INPUT_FF_MEMLESS + help + Say Y here if you want to enable force feedback support for Logitech + Flight System G940 devices. + config HID_MICROSOFT tristate "Microsoft" if EMBEDDED depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index f8dc5bac79bd..ce6c8da28486 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -18,6 +18,9 @@ endif ifdef CONFIG_LOGIRUMBLEPAD2_FF hid-logitech-objs += hid-lg2ff.o endif +ifdef CONFIG_LOGIG940_FF + hid-logitech-objs += hid-lg3ff.o +endif obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index a4b496c68259..a0c0c49dec09 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1323,6 +1323,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 07e056b0e188..c7c9cbf8132c 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -300,6 +300,7 @@ #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2 0xc219 #define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283 #define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286 +#define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940 0xc287 #define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294 #define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG 0xc293 #define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295 diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index 9fcd3d017ab3..3677c9037a11 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -34,6 +34,7 @@ #define LG_FF 0x200 #define LG_FF2 0x400 #define LG_RDESC_REL_ABS 0x800 +#define LG_FF3 0x1000 /* * Certain Logitech keyboards send in report #3 keys which are far @@ -266,7 +267,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err_free; } - if (quirks & (LG_FF | LG_FF2)) + if (quirks & (LG_FF | LG_FF2 | LG_FF3)) connect_mask &= ~HID_CONNECT_FF; ret = hid_hw_start(hdev, connect_mask); @@ -279,6 +280,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) lgff_init(hdev); if (quirks & LG_FF2) lg2ff_init(hdev); + if (quirks & LG_FF3) + lg3ff_init(hdev); return 0; err_free: @@ -331,6 +334,8 @@ static const struct hid_device_id lg_devices[] = { .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2), .driver_data = LG_FF2 }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940), + .driver_data = LG_FF3 }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR), .driver_data = LG_RDESC_REL_ABS }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER), diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h index 27ae750ca878..8069c3e8b64a 100644 --- a/drivers/hid/hid-lg.h +++ b/drivers/hid/hid-lg.h @@ -15,4 +15,10 @@ int lg2ff_init(struct hid_device *hdev); static inline int lg2ff_init(struct hid_device *hdev) { return -1; } #endif +#ifdef CONFIG_LOGIG940_FF +int lg3ff_init(struct hid_device *hdev); +#else +static inline int lg3ff_init(struct hid_device *hdev) { return -1; } +#endif + #endif diff --git a/drivers/hid/hid-lg3ff.c b/drivers/hid/hid-lg3ff.c new file mode 100644 index 000000000000..4002832ee4af --- /dev/null +++ b/drivers/hid/hid-lg3ff.c @@ -0,0 +1,176 @@ +/* + * Force feedback support for Logitech Flight System G940 + * + * Copyright (c) 2009 Gary Stein + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include + +#include "usbhid/usbhid.h" +#include "hid-lg.h" + +/* + * G940 Theory of Operation (from experimentation) + * + * There are 63 fields (only 3 of them currently used) + * 0 - seems to be command field + * 1 - 30 deal with the x axis + * 31 -60 deal with the y axis + * + * Field 1 is x axis constant force + * Field 31 is y axis constant force + * + * other interesting fields 1,2,3,4 on x axis + * (same for 31,32,33,34 on y axis) + * + * 0 0 127 127 makes the joystick autocenter hard + * + * 127 0 127 127 makes the joystick loose on the right, + * but stops all movemnt left + * + * -127 0 -127 -127 makes the joystick loose on the left, + * but stops all movement right + * + * 0 0 -127 -127 makes the joystick rattle very hard + * + * I'm sure these are effects that I don't know enough about them + */ + +struct lg3ff_device { + struct hid_report *report; +}; + +static int hid_lg3ff_play(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + int x, y; + +/* + * Maxusage should always be 63 (maximum fields) + * likely a better way to ensure this data is clean + */ + memset(report->field[0]->value, 0, sizeof(__s32)*report->field[0]->maxusage); + + switch (effect->type) { + case FF_CONSTANT: +/* + * Already clamped in ff_memless + * 0 is center (different then other logitech) + */ + x = effect->u.ramp.start_level; + y = effect->u.ramp.end_level; + + /* send command byte */ + report->field[0]->value[0] = 0x51; + +/* + * Sign backwards from other Force3d pro + * which get recast here in two's complement 8 bits + */ + report->field[0]->value[1] = (unsigned char)(-x); + report->field[0]->value[31] = (unsigned char)(-y); + + usbhid_submit_report(hid, report, USB_DIR_OUT); + break; + } + return 0; +} +static void hid_lg3ff_set_autocenter(struct input_dev *dev, u16 magnitude) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + +/* + * Auto Centering probed from device + * NOTE: deadman's switch on G940 must be covered + * for effects to work + */ + report->field[0]->value[0] = 0x51; + report->field[0]->value[1] = 0x00; + report->field[0]->value[2] = 0x00; + report->field[0]->value[3] = 0x7F; + report->field[0]->value[4] = 0x7F; + report->field[0]->value[31] = 0x00; + report->field[0]->value[32] = 0x00; + report->field[0]->value[33] = 0x7F; + report->field[0]->value[34] = 0x7F; + + usbhid_submit_report(hid, report, USB_DIR_OUT); +} + + +static const signed short ff3_joystick_ac[] = { + FF_CONSTANT, + FF_AUTOCENTER, + -1 +}; + +int lg3ff_init(struct hid_device *hid) +{ + struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); + struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct input_dev *dev = hidinput->input; + struct hid_report *report; + struct hid_field *field; + const signed short *ff_bits = ff3_joystick_ac; + int error; + int i; + + /* Find the report to use */ + if (list_empty(report_list)) { + err_hid("No output report found"); + return -1; + } + + /* Check that the report looks ok */ + report = list_entry(report_list->next, struct hid_report, list); + if (!report) { + err_hid("NULL output report"); + return -1; + } + + field = report->field[0]; + if (!field) { + err_hid("NULL field"); + return -1; + } + + /* Assume single fixed device G940 */ + for (i = 0; ff_bits[i] >= 0; i++) + set_bit(ff_bits[i], dev->ffbit); + + error = input_ff_create_memless(dev, NULL, hid_lg3ff_play); + if (error) + return error; + + if (test_bit(FF_AUTOCENTER, dev->ffbit)) + dev->ff->set_autocenter = hid_lg3ff_set_autocenter; + + dev_info(&hid->dev, "Force feedback for Logitech Flight System G940 by " + "Gary Stein \n"); + return 0; +} + diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c index 987abebe0829..61142b76a9b1 100644 --- a/drivers/hid/hid-lgff.c +++ b/drivers/hid/hid-lgff.c @@ -67,6 +67,7 @@ static const struct dev_type devices[] = { { 0x046d, 0xc219, ff_rumble }, { 0x046d, 0xc283, ff_joystick }, { 0x046d, 0xc286, ff_joystick_ac }, + { 0x046d, 0xc287, ff_joystick_ac }, { 0x046d, 0xc293, ff_joystick }, { 0x046d, 0xc294, ff_wheel }, { 0x046d, 0xc295, ff_joystick }, -- cgit v1.2.2 From 49e4739a0cf681cbfe08c72232c1dcc130b66dde Mon Sep 17 00:00:00 2001 From: Stephane Chatty Date: Wed, 13 Jan 2010 00:29:16 +0100 Subject: HID: add support for Acer T230H multitouch Add support for the Quanta Optical Touch dual-touch panel, present in the Acer T230H monitor, HP L2105tm, and Packard-Bell Video 200t. Signed-off-by: Stephane Chatty Tested-by: Jerome Vidal Tested-by: Cedric Berthier Acked-by: Dmitry Torokhov Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 6 ++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 + drivers/hid/hid-quanta.c | 259 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 270 insertions(+) create mode 100644 drivers/hid/hid-quanta.c (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 317049b80c35..38e969207636 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -241,6 +241,12 @@ config HID_PETALYNX ---help--- Support for Petalynx Maxter remote control. +config HID_QUANTA + tristate "Quanta Optical Touch" + depends on USB_HID + ---help--- + Support for Quanta Optical Touch dual-touch panels. + config HID_SAMSUNG tristate "Samsung" if EMBEDDED depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index ce6c8da28486..15541c47b172 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o +obj-$(CONFIG_HID_QUANTA) += hid-quanta.o obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index a0c0c49dec09..056384cf05e4 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1338,6 +1338,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index c7c9cbf8132c..b009fd68deae 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -383,6 +383,9 @@ #define USB_VENDOR_ID_SAITEK 0x06a3 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 +#define USB_VENDOR_ID_QUANTA 0x0408 +#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH 0x3000 + #define USB_VENDOR_ID_SAMSUNG 0x0419 #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001 diff --git a/drivers/hid/hid-quanta.c b/drivers/hid/hid-quanta.c new file mode 100644 index 000000000000..244d61c18a47 --- /dev/null +++ b/drivers/hid/hid-quanta.c @@ -0,0 +1,259 @@ +/* + * HID driver for Quanta Optical Touch dual-touch panels + * + * Copyright (c) 2009-2010 Stephane Chatty + * + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include + +MODULE_VERSION("1.00"); +MODULE_AUTHOR("Stephane Chatty "); +MODULE_DESCRIPTION("Quanta dual-touch panel"); +MODULE_LICENSE("GPL"); + +#include "hid-ids.h" + +struct quanta_data { + __u16 x, y; + __u8 id; + bool valid; /* valid finger data, or just placeholder? */ + bool first; /* is this the first finger in this frame? */ + bool activity_now; /* at least one active finger in this frame? */ + bool activity; /* at least one active finger previously? */ +}; + +static int quanta_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + switch (usage->hid & HID_USAGE_PAGE) { + + case HID_UP_GENDESK: + switch (usage->hid) { + case HID_GD_X: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_X); + /* touchscreen emulation */ + input_set_abs_params(hi->input, ABS_X, + field->logical_minimum, + field->logical_maximum, 0, 0); + return 1; + case HID_GD_Y: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_Y); + /* touchscreen emulation */ + input_set_abs_params(hi->input, ABS_Y, + field->logical_minimum, + field->logical_maximum, 0, 0); + return 1; + } + return 0; + + case HID_UP_DIGITIZER: + switch (usage->hid) { + case HID_DG_CONFIDENCE: + case HID_DG_TIPSWITCH: + case HID_DG_INPUTMODE: + case HID_DG_DEVICEINDEX: + case HID_DG_CONTACTCOUNT: + case HID_DG_CONTACTMAX: + case HID_DG_TIPPRESSURE: + case HID_DG_WIDTH: + case HID_DG_HEIGHT: + return -1; + case HID_DG_INRANGE: + /* touchscreen emulation */ + hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); + return 1; + case HID_DG_CONTACTID: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_TRACKING_ID); + return 1; + } + return 0; + + case 0xff000000: + /* ignore vendor-specific features */ + return -1; + } + + return 0; +} + +static int quanta_input_mapped(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if (usage->type == EV_KEY || usage->type == EV_ABS) + clear_bit(usage->code, *bit); + + return 0; +} + +/* + * this function is called when a whole finger has been parsed, + * so that it can decide what to send to the input layer. + */ +static void quanta_filter_event(struct quanta_data *td, struct input_dev *input) +{ + + td->first = !td->first; /* touchscreen emulation */ + + if (!td->valid) { + /* + * touchscreen emulation: if no finger in this frame is valid + * and there previously was finger activity, this is a release + */ + if (!td->first && !td->activity_now && td->activity) { + input_event(input, EV_KEY, BTN_TOUCH, 0); + td->activity = false; + } + return; + } + + input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id); + input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y); + + input_mt_sync(input); + td->valid = false; + + /* touchscreen emulation: if first active finger in this frame... */ + if (!td->activity_now) { + /* if there was no previous activity, emit touch event */ + if (!td->activity) { + input_event(input, EV_KEY, BTN_TOUCH, 1); + td->activity = true; + } + td->activity_now = true; + /* and in any case this is our preferred finger */ + input_event(input, EV_ABS, ABS_X, td->x); + input_event(input, EV_ABS, ABS_Y, td->y); + } +} + + +static int quanta_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct quanta_data *td = hid_get_drvdata(hid); + + if (hid->claimed & HID_CLAIMED_INPUT) { + struct input_dev *input = field->hidinput->input; + + switch (usage->hid) { + case HID_DG_INRANGE: + td->valid = !!value; + break; + case HID_GD_X: + td->x = value; + break; + case HID_GD_Y: + td->y = value; + quanta_filter_event(td, input); + break; + case HID_DG_CONTACTID: + td->id = value; + break; + case HID_DG_CONTACTCOUNT: + /* touch emulation: this is the last field in a frame */ + td->first = false; + td->activity_now = false; + break; + case HID_DG_CONFIDENCE: + case HID_DG_TIPSWITCH: + /* avoid interference from generic hidinput handling */ + break; + + default: + /* fallback to the generic hidinput handling */ + return 0; + } + } + + /* we have handled the hidinput part, now remains hiddev */ + if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) + hid->hiddev_hid_event(hid, field, usage, value); + + return 1; +} + +static int quanta_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + struct quanta_data *td; + + td = kmalloc(sizeof(struct quanta_data), GFP_KERNEL); + if (!td) { + dev_err(&hdev->dev, "cannot allocate Quanta Touch data\n"); + return -ENOMEM; + } + td->valid = false; + td->activity = false; + td->activity_now = false; + td->first = false; + hid_set_drvdata(hdev, td); + + ret = hid_parse(hdev); + if (!ret) + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + + if (ret) + kfree(td); + + return ret; +} + +static void quanta_remove(struct hid_device *hdev) +{ + hid_hw_stop(hdev); + kfree(hid_get_drvdata(hdev)); + hid_set_drvdata(hdev, NULL); +} + +static const struct hid_device_id quanta_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, + USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, + { } +}; +MODULE_DEVICE_TABLE(hid, quanta_devices); + +static const struct hid_usage_id quanta_grabbed_usages[] = { + { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, + { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} +}; + +static struct hid_driver quanta_driver = { + .name = "quanta-touch", + .id_table = quanta_devices, + .probe = quanta_probe, + .remove = quanta_remove, + .input_mapping = quanta_input_mapping, + .input_mapped = quanta_input_mapped, + .usage_table = quanta_grabbed_usages, + .event = quanta_event, +}; + +static int __init quanta_init(void) +{ + return hid_register_driver(&quanta_driver); +} + +static void __exit quanta_exit(void) +{ + hid_unregister_driver(&quanta_driver); +} + +module_init(quanta_init); +module_exit(quanta_exit); + -- cgit v1.2.2 From 4bb9508bbbb06f10bc3e249dd34375b4a4d6bfc0 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 23 Dec 2009 14:13:46 +0100 Subject: HID: remove TENX iBuddy from blacklist There were multiple reports which indicate that vendor messed up horribly and the same VID/PID combination is used for completely different devices, some of them requiring the blacklist entry and other not. Remove the blacklist entry for this combination of VID/PID completely, and let the user decide and unbind the driver via sysfs eventually, if needed. Proper fix would be fixing the vendor. References: http://lkml.org/lkml/2009/2/10/434 http://bugzilla.kernel.org/show_bug.cgi?id=13411 Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 2 -- drivers/hid/hid-ids.h | 4 ---- 2 files changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 056384cf05e4..116a3460e75a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1662,8 +1662,6 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) }, { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) }, { HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY1) }, - { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY2) }, { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) }, { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) }, { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b009fd68deae..064c09a221ef 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -406,10 +406,6 @@ #define USB_VENDOR_ID_SUNPLUS 0x04fc #define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8 -#define USB_VENDOR_ID_TENX 0x1130 -#define USB_DEVICE_ID_TENX_IBUDDY1 0x0001 -#define USB_DEVICE_ID_TENX_IBUDDY2 0x0002 - #define USB_VENDOR_ID_THRUSTMASTER 0x044f #define USB_VENDOR_ID_TOPMAX 0x0663 -- cgit v1.2.2 From 62e62da856dba2edb897b672cbd05a69edd4485c Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Thu, 14 Jan 2010 19:10:07 -0700 Subject: HID: hid-debug.c: make local symbols static hid-debug.c: make local symbols static The symbols hid_resolv_event and hid_dump_input_mapping are only used locally in this file. Make them static to prevent the following sparse warnings: warning: symbol 'hid_resolv_event' was not declared. Should it be static? warning: symbol 'hid_dump_input_mapping' was not declared. Should it be static? Signed-off-by: H Hartley Sweeten Signed-off-by: Jiri Kosina --- drivers/hid/hid-debug.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 6abd0369aedb..cd4ece6fdfb9 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -864,13 +864,13 @@ static const char **names[EV_MAX + 1] = { [EV_SND] = sounds, [EV_REP] = repeats, }; -void hid_resolv_event(__u8 type, __u16 code, struct seq_file *f) { - +static void hid_resolv_event(__u8 type, __u16 code, struct seq_file *f) +{ seq_printf(f, "%s.%s", events[type] ? events[type] : "?", names[type] ? (names[type][code] ? names[type][code] : "?") : "?"); } -void hid_dump_input_mapping(struct hid_device *hid, struct seq_file *f) +static void hid_dump_input_mapping(struct hid_device *hid, struct seq_file *f) { int i, j, k; struct hid_report *report; -- cgit v1.2.2 From 6c3f975a4cafaf4dcc9795385da6d42caa37ddeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Sun, 17 Jan 2010 21:54:01 +1100 Subject: crypto: Make Open Firmware device id constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Márton Németh The match_table field of the struct of_device_id is constant in so it is worth to make the initialization data also constant. The semantic match that finds this kind of pattern is as follows: (http://coccinelle.lip6.fr/) // @r@ disable decl_init,const_decl_init; identifier I1, I2, x; @@ struct I1 { ... const struct I2 *x; ... }; @s@ identifier r.I1, y; identifier r.x, E; @@ struct I1 y = { .x = E, }; @c@ identifier r.I2; identifier s.E; @@ const struct I2 E[] = ... ; @depends on !c@ identifier r.I2; identifier s.E; @@ + const struct I2 E[] = ...; // Signed-off-by: Márton Németh Cc: Julia Lawall Cc: cocci@diku.dk Signed-off-by: Herbert Xu --- drivers/crypto/amcc/crypto4xx_core.c | 2 +- drivers/crypto/talitos.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 46e899ac924e..1c3849f6b7a2 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -1274,7 +1274,7 @@ static int __exit crypto4xx_remove(struct of_device *ofdev) return 0; } -static struct of_device_id crypto4xx_match[] = { +static const struct of_device_id crypto4xx_match[] = { { .compatible = "amcc,ppc4xx-crypto",}, { }, }; diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index c47ffe8a73ef..fd529d68c5ba 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -1958,7 +1958,7 @@ err_out: return err; } -static struct of_device_id talitos_match[] = { +static const struct of_device_id talitos_match[] = { { .compatible = "fsl,sec2.0", }, -- cgit v1.2.2 From 933a838aa1aae8388438bb002fbdaf6fca519a5c Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 29 Dec 2009 18:21:39 +0100 Subject: pcmcia: make use of pcmcia_dev_resume() return value In runtime_resume(), do not throw away the return value of pcmcia_dev_resume(), for we can use it (at least) in pcmcia_store_pm_state(). This also fixes the pointless assignment previosly seen there, as noted by Dan Carpenter. CC: Dan Carpenter Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/ds.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 1a4a3c49cc15..defa44c27b97 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -970,13 +970,14 @@ static int runtime_suspend(struct device *dev) return rc; } -static void runtime_resume(struct device *dev) +static int runtime_resume(struct device *dev) { int rc; down(&dev->sem); rc = pcmcia_dev_resume(dev); up(&dev->sem); + return rc; } /************************ per-device sysfs output ***************************/ @@ -1027,7 +1028,7 @@ static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute if ((!p_dev->suspended) && !strncmp(buf, "off", 3)) ret = runtime_suspend(dev); else if (p_dev->suspended && !strncmp(buf, "on", 2)) - runtime_resume(dev); + ret = runtime_resume(dev); return ret ? ret : count; } -- cgit v1.2.2 From cd2e18fe785082b132d960063df83a02acc9a4f2 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Fri, 1 Jan 2010 17:43:08 +0100 Subject: pcmcia: remove remaining unused IRQ_FIRST_SHARED parameter Komuro pointed out correctly that I missed one IRQ_FIRST_SHARED parameter in smc91c92_cs.c, and that another line could be writter more beautifully. CC: netdev@vger.kernel.org CC: Komuro Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/net/pcmcia/smc91c92_cs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 6dd486d2977b..aa57cfd1e3fb 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -453,8 +453,7 @@ static int mhz_mfc_config(struct pcmcia_device *link) link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; - link->irq.Attributes = - IRQ_TYPE_DYNAMIC_SHARING; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->io.IOAddrLines = 16; link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts2 = 8; @@ -652,8 +651,7 @@ static int osi_config(struct pcmcia_device *link) link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; - link->irq.Attributes = - IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->io.NumPorts1 = 64; link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts2 = 8; -- cgit v1.2.2 From fa0b3bc504ff813cc05988bb30bbb6c6a0263eb4 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Jan 2010 12:08:22 +0100 Subject: pcmcia: do not meddle with already assigned resources Do not release any iomem resources already in use. Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/rsrc_nonstatic.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 9b0dc433a8c3..4f93889301b6 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -727,13 +727,6 @@ static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned break; case REMOVE_MANAGED_RESOURCE: ret = sub_interval(&data->mem_db, start, size); - if (!ret) { - struct pcmcia_socket *socket; - down_read(&pcmcia_socket_list_rwsem); - list_for_each_entry(socket, &pcmcia_socket_list, socket_list) - release_cis_mem(socket); - up_read(&pcmcia_socket_list_rwsem); - } break; default: ret = -EINVAL; -- cgit v1.2.2 From 904e377744bfdcea276c27167fa6a609929f39dc Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Jan 2010 12:28:04 +0100 Subject: pcmcia: validate CIS, not CIS cache. In pccard_validate_cis(), validate the card CIS, not the CIS cache. Also, destroy the CIS cache if pccard_validate_cis fails. Furthermore, do not remove the fake CIS in destroy_cis_cache() but do so explicitely in the code paths where it makes sense. Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cistpl.c | 24 ++++++++++++++++-------- drivers/pcmcia/cs.c | 4 ++++ drivers/pcmcia/rsrc_nonstatic.c | 3 +-- 3 files changed, 21 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 25b1cd219e37..41ec7729eddc 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -319,22 +319,23 @@ remove_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, u_int len) } } +/** + * destroy_cis_cache() - destroy the CIS cache + * @s: pcmcia_socket for which CIS cache shall be destroyed + * + * This destroys the CIS cache but keeps any fake CIS alive. + */ + void destroy_cis_cache(struct pcmcia_socket *s) { struct list_head *l, *n; + struct cis_cache_entry *cis; list_for_each_safe(l, n, &s->cis_cache) { - struct cis_cache_entry *cis = list_entry(l, struct cis_cache_entry, node); - + cis = list_entry(l, struct cis_cache_entry, node); list_del(&cis->node); kfree(cis); } - - /* - * If there was a fake CIS, destroy that as well. - */ - kfree(s->fake_cis); - s->fake_cis = NULL; } EXPORT_SYMBOL(destroy_cis_cache); @@ -1596,6 +1597,9 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info) if (!s) return -EINVAL; + /* We do not want to validate the CIS cache... */ + destroy_cis_cache(s); + tuple = kmalloc(sizeof(*tuple), GFP_KERNEL); if (tuple == NULL) { dev_printk(KERN_WARNING, &s->dev, "no memory to validate CIS\n"); @@ -1647,6 +1651,10 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info) count = 0; done: + /* invalidate CIS cache on failure */ + if (!dev_ok || !ident_ok || !count) + destroy_cis_cache(s); + if (info) *info = count; kfree(tuple); diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 6d6f82b38a68..96d8d25c209d 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -407,6 +407,8 @@ static void socket_shutdown(struct pcmcia_socket *s) s->irq.AssignedIRQ = s->irq.Config = 0; s->lock_count = 0; destroy_cis_cache(s); + kfree(s->fake_cis); + s->fake_cis = NULL; #ifdef CONFIG_CARDBUS cb_free(s); #endif @@ -577,6 +579,8 @@ static int socket_late_resume(struct pcmcia_socket *skt) dev_dbg(&skt->dev, "cis mismatch - different card\n"); socket_remove_drivers(skt); destroy_cis_cache(skt); + kfree(skt->fake_cis); + skt->fake_cis = NULL; /* * Workaround: give DS time to schedule removal. * Remove me once the 100ms delay is eliminated diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 4f93889301b6..b886385f12e2 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -281,10 +281,9 @@ static int readable(struct pcmcia_socket *s, struct resource *res, s->cis_virt = ioremap(res->start, s->map_size); if (s->cis_virt) { ret = pccard_validate_cis(s, count); - /* invalidate mapping and CIS cache */ + /* invalidate mapping */ iounmap(s->cis_virt); s->cis_virt = NULL; - destroy_cis_cache(s); } s->cis_mem.res = NULL; if ((ret != 0) || (*count == 0)) -- cgit v1.2.2 From f131ddc4bd1713385c70606555d4d63bed5ec3fd Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Jan 2010 12:58:10 +0100 Subject: pcmcia: cleanup pccard_validate_cis() Cleanup pccard_validate_cis() and make it return an error code on all failures, not merely on some failures. Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cistpl.c | 155 +++++++++++++++++++++++++----------------------- 1 file changed, 81 insertions(+), 74 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 41ec7729eddc..04bf1ba607f7 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -1577,88 +1577,95 @@ next_entry: EXPORT_SYMBOL(pccard_loop_tuple); -/*====================================================================== - - This tries to determine if a card has a sensible CIS. It returns - the number of tuples in the CIS, or 0 if the CIS looks bad. The - checks include making sure several critical tuples are present and - valid; seeing if the total number of tuples is reasonable; and - looking for tuples that use reserved codes. - -======================================================================*/ - +/** + * pccard_validate_cis() - check whether card has a sensible CIS + * @s: the struct pcmcia_socket we are to check + * @info: returns the number of tuples in the (valid) CIS, or 0 + * + * This tries to determine if a card has a sensible CIS. In @info, it + * returns the number of tuples in the CIS, or 0 if the CIS looks bad. The + * checks include making sure several critical tuples are present and + * valid; seeing if the total number of tuples is reasonable; and + * looking for tuples that use reserved codes. + * + * The function returns 0 on success. + */ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info) { - tuple_t *tuple; - cisparse_t *p; - unsigned int count = 0; - int ret, reserved, dev_ok = 0, ident_ok = 0; + tuple_t *tuple; + cisparse_t *p; + unsigned int count = 0; + int ret, reserved, dev_ok = 0, ident_ok = 0; - if (!s) - return -EINVAL; + if (!s) + return -EINVAL; - /* We do not want to validate the CIS cache... */ - destroy_cis_cache(s); + /* We do not want to validate the CIS cache... */ + destroy_cis_cache(s); - tuple = kmalloc(sizeof(*tuple), GFP_KERNEL); - if (tuple == NULL) { - dev_printk(KERN_WARNING, &s->dev, "no memory to validate CIS\n"); - return -ENOMEM; - } - p = kmalloc(sizeof(*p), GFP_KERNEL); - if (p == NULL) { - kfree(tuple); - dev_printk(KERN_WARNING, &s->dev, "no memory to validate CIS\n"); - return -ENOMEM; - } + tuple = kmalloc(sizeof(*tuple), GFP_KERNEL); + if (tuple == NULL) { + dev_warn(&s->dev, "no memory to validate CIS\n"); + return -ENOMEM; + } + p = kmalloc(sizeof(*p), GFP_KERNEL); + if (p == NULL) { + kfree(tuple); + dev_warn(&s->dev, "no memory to validate CIS\n"); + return -ENOMEM; + } - count = reserved = 0; - tuple->DesiredTuple = RETURN_FIRST_TUPLE; - tuple->Attributes = TUPLE_RETURN_COMMON; - ret = pccard_get_first_tuple(s, BIND_FN_ALL, tuple); - if (ret != 0) - goto done; - - /* First tuple should be DEVICE; we should really have either that - or a CFTABLE_ENTRY of some sort */ - if ((tuple->TupleCode == CISTPL_DEVICE) || - (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY, p) == 0) || - (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY_CB, p) == 0)) - dev_ok++; - - /* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2 - tuple, for card identification. Certain old D-Link and Linksys - cards have only a broken VERS_2 tuple; hence the bogus test. */ - if ((pccard_read_tuple(s, BIND_FN_ALL, CISTPL_MANFID, p) == 0) || - (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_1, p) == 0) || - (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_2, p) != -ENOSPC)) - ident_ok++; - - if (!dev_ok && !ident_ok) - goto done; - - for (count = 1; count < MAX_TUPLES; count++) { - ret = pccard_get_next_tuple(s, BIND_FN_ALL, tuple); + count = reserved = 0; + tuple->DesiredTuple = RETURN_FIRST_TUPLE; + tuple->Attributes = TUPLE_RETURN_COMMON; + ret = pccard_get_first_tuple(s, BIND_FN_ALL, tuple); if (ret != 0) - break; - if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) || - ((tuple->TupleCode > 0x47) && (tuple->TupleCode < 0x80)) || - ((tuple->TupleCode > 0x90) && (tuple->TupleCode < 0xff))) - reserved++; - } - if ((count == MAX_TUPLES) || (reserved > 5) || - ((!dev_ok || !ident_ok) && (count > 10))) - count = 0; + goto done; + + /* First tuple should be DEVICE; we should really have either that + or a CFTABLE_ENTRY of some sort */ + if ((tuple->TupleCode == CISTPL_DEVICE) || + (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY, p)) || + (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY_CB, p))) + dev_ok++; + + /* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2 + tuple, for card identification. Certain old D-Link and Linksys + cards have only a broken VERS_2 tuple; hence the bogus test. */ + if ((pccard_read_tuple(s, BIND_FN_ALL, CISTPL_MANFID, p) == 0) || + (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_1, p) == 0) || + (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_2, p) != -ENOSPC)) + ident_ok++; + + if (!dev_ok && !ident_ok) + goto done; + + for (count = 1; count < MAX_TUPLES; count++) { + ret = pccard_get_next_tuple(s, BIND_FN_ALL, tuple); + if (ret != 0) + break; + if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) || + ((tuple->TupleCode > 0x47) && (tuple->TupleCode < 0x80)) || + ((tuple->TupleCode > 0x90) && (tuple->TupleCode < 0xff))) + reserved++; + } + if ((count == MAX_TUPLES) || (reserved > 5) || + ((!dev_ok || !ident_ok) && (count > 10))) + count = 0; + + ret = 0; done: - /* invalidate CIS cache on failure */ - if (!dev_ok || !ident_ok || !count) - destroy_cis_cache(s); - - if (info) - *info = count; - kfree(tuple); - kfree(p); - return 0; + /* invalidate CIS cache on failure */ + if (!dev_ok || !ident_ok || !count) { + destroy_cis_cache(s); + ret = -EIO; + } + + if (info) + *info = count; + kfree(tuple); + kfree(p); + return ret; } EXPORT_SYMBOL(pccard_validate_cis); -- cgit v1.2.2 From 88b060d6c03fcb9e4d2018b4349954c4242a5c7f Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Jan 2010 14:14:23 +0100 Subject: pcmcia: improve check for same card in slot after resume During a suspend/resume cycle, an user may change the card in the PCMCIA/CardBus slot. The pcmcia_core can at least look at the socket state to check whether it is the same. For PCMCIA devices, move the detection and handling of such a change to ds.c. For CardBus devices, the PCI hotplug interface doesn't offer a "rescan" facility which also _removes_ devices no longer to be found behind a bridge. Therefore, remove and re-add all devices unconditionally. CC: Jesse Barnes CC: Linus Torvalds Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cistpl.c | 1 + drivers/pcmcia/cs.c | 65 +++++++++++++++++++++++-------------------------- drivers/pcmcia/ds.c | 16 +++++++++++- 3 files changed, 46 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 04bf1ba607f7..a8323cb2e34d 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -377,6 +377,7 @@ int verify_cis_cache(struct pcmcia_socket *s) kfree(buf); return 0; } +EXPORT_SYMBOL(verify_cis_cache); /*====================================================================== diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 96d8d25c209d..8c51493d1f95 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -328,7 +328,7 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority) { int ret; - if (s->state & SOCKET_CARDBUS) + if ((s->state & SOCKET_CARDBUS) && (event != CS_EVENT_CARD_REMOVAL)) return 0; dev_dbg(&s->dev, "send_event(event %d, pri %d, callback 0x%p)\n", @@ -346,13 +346,6 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority) return ret; } -static void socket_remove_drivers(struct pcmcia_socket *skt) -{ - dev_dbg(&skt->dev, "remove_drivers\n"); - - send_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH); -} - static int socket_reset(struct pcmcia_socket *skt) { int status, i; @@ -395,7 +388,7 @@ static void socket_shutdown(struct pcmcia_socket *s) dev_dbg(&s->dev, "shutdown\n"); - socket_remove_drivers(s); + send_event(s, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH); s->state &= SOCKET_INUSE | SOCKET_PRESENT; msleep(shutdown_delay * 10); s->state &= SOCKET_INUSE; @@ -462,7 +455,8 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay) return -EINVAL; } skt->state |= SOCKET_CARDBUS; - } + } else + skt->state &= ~SOCKET_CARDBUS; /* * Decode the card voltage requirements, and apply power to the card. @@ -544,6 +538,8 @@ static int socket_suspend(struct pcmcia_socket *skt) if (skt->state & SOCKET_SUSPEND) return -EBUSY; + skt->suspended_state = skt->state; + send_event(skt, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW); skt->socket = dead_socket; skt->ops->set_socket(skt, &skt->socket); @@ -566,38 +562,37 @@ static int socket_early_resume(struct pcmcia_socket *skt) static int socket_late_resume(struct pcmcia_socket *skt) { - if (!(skt->state & SOCKET_PRESENT)) { - skt->state &= ~SOCKET_SUSPEND; + skt->state &= ~SOCKET_SUSPEND; + + if (!(skt->state & SOCKET_PRESENT)) return socket_insert(skt); + + if (skt->resume_status) { + socket_shutdown(skt); + return 0; } - if (skt->resume_status == 0) { - /* - * FIXME: need a better check here for cardbus cards. - */ - if (verify_cis_cache(skt) != 0) { - dev_dbg(&skt->dev, "cis mismatch - different card\n"); - socket_remove_drivers(skt); - destroy_cis_cache(skt); - kfree(skt->fake_cis); - skt->fake_cis = NULL; - /* - * Workaround: give DS time to schedule removal. - * Remove me once the 100ms delay is eliminated - * in ds.c - */ - msleep(200); - send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); - } else { - dev_dbg(&skt->dev, "cis matches cache\n"); - send_event(skt, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW); - } - } else { + if (skt->suspended_state != skt->state) { + dev_dbg(&skt->dev, + "suspend state 0x%x != resume state 0x%x\n", + skt->suspended_state, skt->state); + socket_shutdown(skt); + return socket_insert(skt); } - skt->state &= ~SOCKET_SUSPEND; +#ifdef CONFIG_CARDBUS + if (skt->state & SOCKET_CARDBUS) { + /* We can't be sure the CardBus card is the same + * as the one previously inserted. Therefore, remove + * and re-add... */ + cb_free(skt); + cb_alloc(skt); + return 0; + } +#endif + send_event(skt, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW); return 0; } diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index defa44c27b97..87e06395c129 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1252,8 +1252,22 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) case CS_EVENT_EJECTION_REQUEST: break; - case CS_EVENT_PM_SUSPEND: case CS_EVENT_PM_RESUME: + if (verify_cis_cache(skt) != 0) { + dev_dbg(&skt->dev, "cis mismatch - different card\n"); + /* first, remove the card */ + ds_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH); + destroy_cis_cache(skt); + kfree(skt->fake_cis); + skt->fake_cis = NULL; + /* now, add the new card */ + ds_event(skt, CS_EVENT_CARD_INSERTION, + CS_EVENT_PRI_LOW); + } + handle_event(skt, event); + break; + + case CS_EVENT_PM_SUSPEND: case CS_EVENT_RESET_PHYSICAL: case CS_EVENT_CARD_RESET: default: -- cgit v1.2.2 From 57197b9b7712eb19f5344c466e8aefbac1adbe55 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Jan 2010 17:27:33 +0100 Subject: pcmcia: CardBus doesn't need CIS access At least no in-kernel CardBus-capable PCI driver makes use of the CIS access functions. Therefore, it seems sensible to remove this unused code, and cleanup cardbus.c a lot. CC: Jesse Barnes CC: Linus Torvalds Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cardbus.c | 175 ++++------------------------------------- drivers/pcmcia/cistpl.c | 200 ++++++++--------------------------------------- 2 files changed, 46 insertions(+), 329 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c index d99f846451a3..ac0686efbf75 100644 --- a/drivers/pcmcia/cardbus.c +++ b/drivers/pcmcia/cardbus.c @@ -20,170 +20,12 @@ */ -#include #include -#include -#include -#include +#include #include -#include -#include -#include -#include #include -#include -#include -#include "cs_internal.h" - -/*====================================================================*/ - -/* Offsets in the Expansion ROM Image Header */ -#define ROM_SIGNATURE 0x0000 /* 2 bytes */ -#define ROM_DATA_PTR 0x0018 /* 2 bytes */ - -/* Offsets in the CardBus PC Card Data Structure */ -#define PCDATA_SIGNATURE 0x0000 /* 4 bytes */ -#define PCDATA_VPD_PTR 0x0008 /* 2 bytes */ -#define PCDATA_LENGTH 0x000a /* 2 bytes */ -#define PCDATA_REVISION 0x000c -#define PCDATA_IMAGE_SZ 0x0010 /* 2 bytes */ -#define PCDATA_ROM_LEVEL 0x0012 /* 2 bytes */ -#define PCDATA_CODE_TYPE 0x0014 -#define PCDATA_INDICATOR 0x0015 - -/*===================================================================== - - Expansion ROM's have a special layout, and pointers specify an - image number and an offset within that image. xlate_rom_addr() - converts an image/offset address to an absolute offset from the - ROM's base address. - -=====================================================================*/ - -static u_int xlate_rom_addr(void __iomem *b, u_int addr) -{ - u_int img = 0, ofs = 0, sz; - u_short data; - while ((readb(b) == 0x55) && (readb(b + 1) == 0xaa)) { - if (img == (addr >> 28)) - return (addr & 0x0fffffff) + ofs; - data = readb(b + ROM_DATA_PTR) + (readb(b + ROM_DATA_PTR + 1) << 8); - sz = 512 * (readb(b + data + PCDATA_IMAGE_SZ) + - (readb(b + data + PCDATA_IMAGE_SZ + 1) << 8)); - if ((sz == 0) || (readb(b + data + PCDATA_INDICATOR) & 0x80)) - break; - b += sz; - ofs += sz; - img++; - } - return 0; -} - -/*===================================================================== - - These are similar to setup_cis_mem and release_cis_mem for 16-bit - cards. The "result" that is used externally is the cb_cis_virt - pointer in the struct pcmcia_socket structure. - -=====================================================================*/ - -static void cb_release_cis_mem(struct pcmcia_socket *s) -{ - if (s->cb_cis_virt) { - dev_dbg(&s->dev, "cb_release_cis_mem()\n"); - iounmap(s->cb_cis_virt); - s->cb_cis_virt = NULL; - s->cb_cis_res = NULL; - } -} - -static int cb_setup_cis_mem(struct pcmcia_socket *s, struct resource *res) -{ - unsigned int start, size; - - if (res == s->cb_cis_res) - return 0; - - if (s->cb_cis_res) - cb_release_cis_mem(s); - - start = res->start; - size = res->end - start + 1; - s->cb_cis_virt = ioremap(start, size); - - if (!s->cb_cis_virt) - return -1; - - s->cb_cis_res = res; - - return 0; -} - -/*===================================================================== - - This is used by the CIS processing code to read CIS information - from a CardBus device. - -=====================================================================*/ - -int read_cb_mem(struct pcmcia_socket *s, int space, u_int addr, u_int len, - void *ptr) -{ - struct pci_dev *dev; - struct resource *res; - - dev_dbg(&s->dev, "read_cb_mem(%d, %#x, %u)\n", space, addr, len); - dev = pci_get_slot(s->cb_dev->subordinate, 0); - if (!dev) - goto fail; - - /* Config space? */ - if (space == 0) { - if (addr + len > 0x100) - goto failput; - for (; len; addr++, ptr++, len--) - pci_read_config_byte(dev, addr, ptr); - return 0; - } - - res = dev->resource + space - 1; - - pci_dev_put(dev); - - if (!res->flags) - goto fail; - - if (cb_setup_cis_mem(s, res) != 0) - goto fail; - - if (space == 7) { - addr = xlate_rom_addr(s->cb_cis_virt, addr); - if (addr == 0) - goto fail; - } - - if (addr + len > res->end - res->start) - goto fail; - - memcpy_fromio(ptr, s->cb_cis_virt + addr, len); - return 0; - -failput: - pci_dev_put(dev); -fail: - memset(ptr, 0xff, len); - return -1; -} - -/*===================================================================== - - cb_alloc() and cb_free() allocate and free the kernel data - structures for a Cardbus device, and handle the lowest level PCI - device setup issues. - -=====================================================================*/ static void cardbus_config_irq_and_cls(struct pci_bus *bus, int irq) { @@ -215,6 +57,13 @@ static void cardbus_config_irq_and_cls(struct pci_bus *bus, int irq) } } +/** + * cb_alloc() - add CardBus device + * @s: the pcmcia_socket where the CardBus device is located + * + * cb_alloc() allocates the kernel data structures for a Cardbus device + * and handles the lowest level PCI device setup issues. + */ int __ref cb_alloc(struct pcmcia_socket *s) { struct pci_bus *bus = s->cb_dev->subordinate; @@ -249,12 +98,16 @@ int __ref cb_alloc(struct pcmcia_socket *s) return 0; } +/** + * cb_free() - remove CardBus device + * @s: the pcmcia_socket where the CardBus device was located + * + * cb_free() handles the lowest level PCI device cleanup. + */ void cb_free(struct pcmcia_socket *s) { struct pci_dev *bridge = s->cb_dev; - cb_release_cis_mem(s); - if (bridge) pci_remove_behind_bridge(bridge); } diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index a8323cb2e34d..368367ced62b 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -268,29 +268,27 @@ EXPORT_SYMBOL(pcmcia_write_cis_mem); static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, size_t len, void *ptr) { - struct cis_cache_entry *cis; - int ret; + struct cis_cache_entry *cis; + int ret; - if (s->fake_cis) { - if (s->fake_cis_len >= addr+len) - memcpy(ptr, s->fake_cis+addr, len); - else - memset(ptr, 0xff, len); - return; - } + if (s->state & SOCKET_CARDBUS) + return; - list_for_each_entry(cis, &s->cis_cache, node) { - if (cis->addr == addr && cis->len == len && cis->attr == attr) { - memcpy(ptr, cis->cache, len); - return; + if (s->fake_cis) { + if (s->fake_cis_len >= addr+len) + memcpy(ptr, s->fake_cis+addr, len); + else + memset(ptr, 0xff, len); + return; + } + + list_for_each_entry(cis, &s->cis_cache, node) { + if (cis->addr == addr && cis->len == len && cis->attr == attr) { + memcpy(ptr, cis->cache, len); + return; + } } - } -#ifdef CONFIG_CARDBUS - if (s->state & SOCKET_CARDBUS) - ret = read_cb_mem(s, attr, addr, len, ptr); - else -#endif ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr); if (ret == 0) { @@ -351,6 +349,9 @@ int verify_cis_cache(struct pcmcia_socket *s) struct cis_cache_entry *cis; char *buf; + if (s->state & SOCKET_CARDBUS) + return -EINVAL; + buf = kmalloc(256, GFP_KERNEL); if (buf == NULL) { dev_printk(KERN_WARNING, &s->dev, @@ -362,12 +363,8 @@ int verify_cis_cache(struct pcmcia_socket *s) if (len > 256) len = 256; -#ifdef CONFIG_CARDBUS - if (s->state & SOCKET_CARDBUS) - read_cb_mem(s, cis->attr, cis->addr, len, buf); - else -#endif - pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf); + + pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf); if (memcmp(buf, cis->cache, len) != 0) { kfree(buf); @@ -427,25 +424,16 @@ int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple { if (!s) return -EINVAL; - if (!(s->state & SOCKET_PRESENT)) + + if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS)) return -ENODEV; tuple->TupleLink = tuple->Flags = 0; -#ifdef CONFIG_CARDBUS - if (s->state & SOCKET_CARDBUS) { - struct pci_dev *dev = s->cb_dev; - u_int ptr; - pci_bus_read_config_dword(dev->subordinate, 0, PCI_CARDBUS_CIS, &ptr); - tuple->CISOffset = ptr & ~7; - SPACE(tuple->Flags) = (ptr & 7); - } else -#endif - { - /* Assume presence of a LONGLINK_C to address 0 */ - tuple->CISOffset = tuple->LinkOffset = 0; - SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1; - } - if (!(s->state & SOCKET_CARDBUS) && (s->functions > 1) && - !(tuple->Attributes & TUPLE_RETURN_COMMON)) { + + /* Assume presence of a LONGLINK_C to address 0 */ + tuple->CISOffset = tuple->LinkOffset = 0; + SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1; + + if ((s->functions > 1) && !(tuple->Attributes & TUPLE_RETURN_COMMON)) { cisdata_t req = tuple->DesiredTuple; tuple->DesiredTuple = CISTPL_LONGLINK_MFC; if (pccard_get_next_tuple(s, function, tuple) == 0) { @@ -481,7 +469,7 @@ static int follow_link(struct pcmcia_socket *s, tuple_t *tuple) } else { return -1; } - if (!(s->state & SOCKET_CARDBUS) && SPACE(tuple->Flags)) { + if (SPACE(tuple->Flags)) { /* This is ugly, but a common CIS error is to code the long link offset incorrectly, so we check the right spot... */ read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link); @@ -507,7 +495,7 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_ if (!s) return -EINVAL; - if (!(s->state & SOCKET_PRESENT)) + if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS)) return -ENODEV; link[1] = tuple->TupleLink; @@ -1192,119 +1180,6 @@ static int parse_cftable_entry(tuple_t *tuple, /*====================================================================*/ -#ifdef CONFIG_CARDBUS - -static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar) -{ - u_char *p; - if (tuple->TupleDataLen < 6) - return -EINVAL; - p = (u_char *)tuple->TupleData; - bar->attr = *p; - p += 2; - bar->size = get_unaligned_le32(p); - return 0; -} - -static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config) -{ - u_char *p; - - p = (u_char *)tuple->TupleData; - if ((*p != 3) || (tuple->TupleDataLen < 6)) - return -EINVAL; - config->last_idx = *(++p); - p++; - config->base = get_unaligned_le32(p); - config->subtuples = tuple->TupleDataLen - 6; - return 0; -} - -static int parse_cftable_entry_cb(tuple_t *tuple, - cistpl_cftable_entry_cb_t *entry) -{ - u_char *p, *q, features; - - p = tuple->TupleData; - q = p + tuple->TupleDataLen; - entry->index = *p & 0x3f; - entry->flags = 0; - if (*p & 0x40) - entry->flags |= CISTPL_CFTABLE_DEFAULT; - - /* Process optional features */ - if (++p == q) - return -EINVAL; - features = *p; p++; - - /* Power options */ - if ((features & 3) > 0) { - p = parse_power(p, q, &entry->vcc); - if (p == NULL) - return -EINVAL; - } else - entry->vcc.present = 0; - if ((features & 3) > 1) { - p = parse_power(p, q, &entry->vpp1); - if (p == NULL) - return -EINVAL; - } else - entry->vpp1.present = 0; - if ((features & 3) > 2) { - p = parse_power(p, q, &entry->vpp2); - if (p == NULL) - return -EINVAL; - } else - entry->vpp2.present = 0; - - /* I/O window options */ - if (features & 0x08) { - if (p == q) - return -EINVAL; - entry->io = *p; p++; - } else - entry->io = 0; - - /* Interrupt options */ - if (features & 0x10) { - p = parse_irq(p, q, &entry->irq); - if (p == NULL) - return -EINVAL; - } else - entry->irq.IRQInfo1 = 0; - - if (features & 0x20) { - if (p == q) - return -EINVAL; - entry->mem = *p; p++; - } else - entry->mem = 0; - - /* Misc features */ - if (features & 0x80) { - if (p == q) - return -EINVAL; - entry->flags |= (*p << 8); - if (*p & 0x80) { - if (++p == q) - return -EINVAL; - entry->flags |= (*p << 16); - } - while (*p & 0x80) - if (++p == q) - return -EINVAL; - p++; - } - - entry->subtuples = q-p; - - return 0; -} - -#endif - -/*====================================================================*/ - static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo) { u_char *p, *q; @@ -1406,17 +1281,6 @@ int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse) case CISTPL_DEVICE_A: ret = parse_device(tuple, &parse->device); break; -#ifdef CONFIG_CARDBUS - case CISTPL_BAR: - ret = parse_bar(tuple, &parse->bar); - break; - case CISTPL_CONFIG_CB: - ret = parse_config_cb(tuple, &parse->config); - break; - case CISTPL_CFTABLE_ENTRY_CB: - ret = parse_cftable_entry_cb(tuple, &parse->cftable_entry_cb); - break; -#endif case CISTPL_CHECKSUM: ret = parse_checksum(tuple, &parse->checksum); break; -- cgit v1.2.2 From 180c33ee409eb3ed605d4ad9884e4a526a7655ff Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Jan 2010 17:34:09 +0100 Subject: pcmcia: call CIS cleanup from ds.c As ds.c is the only real user of CIS access functions, call the cleanup functions from ds.c, too. Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs.c | 3 --- drivers/pcmcia/ds.c | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 8c51493d1f95..9d8b9c1f5a69 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -283,8 +283,6 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket) if (socket->thread) kthread_stop(socket->thread); - release_cis_mem(socket); - /* remove from our own list */ down_write(&pcmcia_socket_list_rwsem); list_del(&socket->socket_list); @@ -399,7 +397,6 @@ static void socket_shutdown(struct pcmcia_socket *s) s->ops->set_socket(s, &s->socket); s->irq.AssignedIRQ = s->irq.Config = 0; s->lock_count = 0; - destroy_cis_cache(s); kfree(s->fake_cis); s->fake_cis = NULL; #ifdef CONFIG_CARDBUS diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 87e06395c129..7bb52b003f0e 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1241,10 +1241,12 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) s->pcmcia_state.present = 0; pcmcia_card_remove(skt, NULL); handle_event(skt, event); + destroy_cis_cache(s); break; case CS_EVENT_CARD_INSERTION: s->pcmcia_state.present = 1; + destroy_cis_cache(s); /* to be on the safe side... */ pcmcia_card_add(skt); handle_event(skt, event); break; @@ -1366,6 +1368,7 @@ static void pcmcia_bus_remove_socket(struct device *dev, /* unregister any unbound devices */ mutex_lock(&socket->skt_mutex); pcmcia_card_remove(socket, NULL); + release_cis_mem(socket); mutex_unlock(&socket->skt_mutex); pcmcia_put_socket(socket); -- cgit v1.2.2 From 3f32b3c093eddc03ed477ae0d7a6938db6b94a05 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Jan 2010 22:22:50 +0100 Subject: pcmcia: rsrc_nonstatic io memory probe improvements Add a lot of documentation to the rsrc_nonstatic io memory probe functions. Also, add a first memory probe call -- just checking whether request_resource() succeeds -- upon adding of resources. Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/rsrc_nonstatic.c | 174 ++++++++++++++++++++++++++-------------- 1 file changed, 114 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index b886385f12e2..120d5ad99296 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -264,18 +264,15 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base, } #endif -/*====================================================================== - - This is tricky... when we set up CIS memory, we try to validate - the memory window space allocations. - -======================================================================*/ +/*======================================================================*/ -/* Validation function for cards with a valid CIS */ +/** + * readable() - iomem validation function for cards with a valid CIS + */ static int readable(struct pcmcia_socket *s, struct resource *res, unsigned int *count) { - int ret = -1; + int ret = -EINVAL; s->cis_mem.res = res; s->cis_virt = ioremap(res->start, s->map_size); @@ -286,13 +283,16 @@ static int readable(struct pcmcia_socket *s, struct resource *res, s->cis_virt = NULL; } s->cis_mem.res = NULL; - if ((ret != 0) || (*count == 0)) - return 0; - return 1; + if ((ret) || (*count == 0)) + return -EINVAL; + return 0; } -/* Validation function for simple memory cards */ -static int checksum(struct pcmcia_socket *s, struct resource *res) +/** + * checksum() - iomem validation function for simple memory cards + */ +static int checksum(struct pcmcia_socket *s, struct resource *res, + unsigned int *value) { pccard_mem_map map; int i, a = 0, b = -1, d; @@ -320,61 +320,83 @@ static int checksum(struct pcmcia_socket *s, struct resource *res) iounmap(virt); } - return (b == -1) ? -1 : (a>>1); -} - -static int -cis_readable(struct pcmcia_socket *s, unsigned long base, unsigned long size) -{ - struct resource *res1, *res2; - unsigned int info1, info2; - int ret = 0; - - res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe"); - res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM, - "PCMCIA memprobe"); - - if (res1 && res2) { - ret = readable(s, res1, &info1); - ret += readable(s, res2, &info2); - } + if (b == -1) + return -EINVAL; - free_region(res2); - free_region(res1); + *value = a; - return (ret == 2) && (info1 == info2); + return 0; } -static int -checksum_match(struct pcmcia_socket *s, unsigned long base, unsigned long size) +/** + * do_validate_mem() - low level validate a memory region for PCMCIA use + * @s: PCMCIA socket to validate + * @base: start address of resource to check + * @size: size of resource to check + * @validate: validation function to use + * + * do_validate_mem() splits up the memory region which is to be checked + * into two parts. Both are passed to the @validate() function. If + * @validate() returns non-zero, or the value parameter to @validate() + * is zero, or the value parameter is different between both calls, + * the check fails, and -EINVAL is returned. Else, 0 is returned. + */ +static int do_validate_mem(struct pcmcia_socket *s, + unsigned long base, unsigned long size, + int validate (struct pcmcia_socket *s, + struct resource *res, + unsigned int *value)) { struct resource *res1, *res2; - int a = -1, b = -1; + unsigned int info1 = 1, info2 = 1; + int ret = -EINVAL; res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe"); res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM, "PCMCIA memprobe"); if (res1 && res2) { - a = checksum(s, res1); - b = checksum(s, res2); + ret = 0; + if (validate) { + ret = validate(s, res1, &info1); + ret += validate(s, res2, &info2); + } } free_region(res2); free_region(res1); - return (a == b) && (a >= 0); -} + dev_dbg(&s->dev, "cs: memory probe 0x%06lx-0x%06lx: %p %p %u %u %u", + base, base+size-1, res1, res2, ret, info1, info2); -/*====================================================================== + if ((ret) || (info1 != info2) || (info1 == 0)) + return -EINVAL; - The memory probe. If the memory list includes a 64K-aligned block - below 1MB, we probe in 64K chunks, and as soon as we accumulate at - least mem_limit free space, we quit. + return 0; +} -======================================================================*/ -static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) +/** + * do_mem_probe() - validate a memory region for PCMCIA use + * @s: PCMCIA socket to validate + * @base: start address of resource to check + * @num: size of resource to check + * @validate: validation function to use + * @fallback: validation function to use if validate fails + * + * do_mem_probe() checks a memory region for use by the PCMCIA subsystem. + * To do so, the area is split up into sensible parts, and then passed + * into the @validate() function. Only if @validate() and @fallback() fail, + * the area is marked as unavaibale for use by the PCMCIA subsystem. The + * function returns the size of the usable memory area. + */ +static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num, + int validate (struct pcmcia_socket *s, + struct resource *res, + unsigned int *value), + int fallback (struct pcmcia_socket *s, + struct resource *res, + unsigned int *value)) { struct socket_data *s_data = s->resource_data; u_long i, j, bad, fail, step; @@ -392,15 +414,14 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) for (i = j = base; i < base+num; i = j + step) { if (!fail) { for (j = i; j < base+num; j += step) { - if (cis_readable(s, j, step)) + if (!do_validate_mem(s, j, step, validate)) break; } fail = ((i == base) && (j == base+num)); } - if (fail) { - for (j = i; j < base+num; j += 2*step) - if (checksum_match(s, j, step) && - checksum_match(s, j + step, step)) + if ((fail) && (fallback)) { + for (j = i; j < base+num; j += step) + if (!do_validate_mem(s, j, step, fallback)) break; } if (i != j) { @@ -415,8 +436,14 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) return num - bad; } + #ifdef CONFIG_PCMCIA_PROBE +/** + * inv_probe() - top-to-bottom search for one usuable high memory area + * @s: PCMCIA socket to validate + * @m: resource_map to check + */ static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s) { struct socket_data *s_data = s->resource_data; @@ -431,9 +458,18 @@ static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s) } if (m->base < 0x100000) return 0; - return do_mem_probe(m->base, m->num, s); + return do_mem_probe(s, m->base, m->num, readable, checksum); } +/** + * validate_mem() - memory probe function + * @s: PCMCIA socket to validate + * @probe_mask: MEM_PROBE_LOW | MEM_PROBE_HIGH + * + * The memory probe. If the memory list includes a 64K-aligned block + * below 1MB, we probe in 64K chunks, and as soon as we accumulate at + * least mem_limit free space, we quit. Returns 0 on usuable ports. + */ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) { struct resource_map *m, mm; @@ -456,7 +492,8 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) if (mm.base >= 0x100000) continue; if ((mm.base | mm.num) & 0xffff) { - ok += do_mem_probe(mm.base, mm.num, s); + ok += do_mem_probe(s, mm.base, mm.num, readable, + checksum); continue; } /* Special probe for 64K-aligned block */ @@ -466,7 +503,8 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) if (ok >= mem_limit) sub_interval(&s_data->mem_db, b, 0x10000); else - ok += do_mem_probe(b, 0x10000, s); + ok += do_mem_probe(s, b, 0x10000, + readable, checksum); } } } @@ -479,6 +517,13 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) #else /* CONFIG_PCMCIA_PROBE */ +/** + * validate_mem() - memory probe function + * @s: PCMCIA socket to validate + * @probe_mask: ignored + * + * Returns 0 on usuable ports. + */ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) { struct resource_map *m, mm; @@ -487,7 +532,7 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) { mm = *m; - ok += do_mem_probe(mm.base, mm.num, s); + ok += do_mem_probe(s, mm.base, mm.num, readable, checksum); } if (ok > 0) return 0; @@ -497,7 +542,13 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) #endif /* CONFIG_PCMCIA_PROBE */ -/* +/** + * pcmcia_nonstatic_validate_mem() - try to validate iomem for PCMCIA use + * @s: PCMCIA socket to validate + * + * This is tricky... when we set up CIS memory, we try to validate + * the memory window space allocations. + * * Locking note: Must be called with skt_mutex held! */ static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) @@ -515,10 +566,11 @@ static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) probe_mask = MEM_PROBE_HIGH; if (probe_mask & ~s_data->rsrc_mem_probe) { - if (s->state & SOCKET_PRESENT) + if (s->state & SOCKET_PRESENT) { ret = validate_mem(s, probe_mask); - if (!ret) - s_data->rsrc_mem_probe |= probe_mask; + if (!ret) + s_data->rsrc_mem_probe |= probe_mask; + } } mutex_unlock(&rsrc_mutex); @@ -723,6 +775,8 @@ static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned switch (action) { case ADD_MANAGED_RESOURCE: ret = add_interval(&data->mem_db, start, size); + if (!ret) + do_mem_probe(s, start, size, NULL, NULL); break; case REMOVE_MANAGED_RESOURCE: ret = sub_interval(&data->mem_db, start, size); -- cgit v1.2.2 From 593f010bc0d8f7fde2ce948cac3f77f6a3d9db2b Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Jan 2010 22:59:15 +0100 Subject: pcmcia: do not lock socket driver module in pcmcia_get_socket() Do not lock the socket driver module in pcmcia_get_socket(), as the PCMCIA core can handle a socket module removal: In pcmcia_unregister_socket(), we explicitely wait for the last put_device() to succeed. Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 9d8b9c1f5a69..f0630a61da90 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -140,19 +140,13 @@ struct pcmcia_socket *pcmcia_get_socket(struct pcmcia_socket *skt) struct device *dev = get_device(&skt->dev); if (!dev) return NULL; - skt = dev_get_drvdata(dev); - if (!try_module_get(skt->owner)) { - put_device(&skt->dev); - return NULL; - } - return skt; + return dev_get_drvdata(dev); } EXPORT_SYMBOL(pcmcia_get_socket); void pcmcia_put_socket(struct pcmcia_socket *skt) { - module_put(skt->owner); put_device(&skt->dev); } EXPORT_SYMBOL(pcmcia_put_socket); -- cgit v1.2.2 From e3deec090558d5cb5ffdc574e5560f3ed9723394 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 3 Nov 2009 12:33:07 -0600 Subject: [SCSI] eliminate potential kmalloc failure in scsi_get_vpd_page() The best way to fix this is to eliminate the intenal kmalloc() and make the caller allocate the required amount of storage. Signed-off-by: James Bottomley --- drivers/scsi/scsi.c | 40 ++++++++++++---------------------------- drivers/scsi/sd.c | 26 +++++++++++++++----------- drivers/scsi/ses.c | 10 +++++++--- 3 files changed, 34 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index a60da5555577..513661f45e5f 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -1026,55 +1026,39 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer, * responsible for calling kfree() on this pointer when it is no longer * needed. If we cannot retrieve the VPD page this routine returns %NULL. */ -unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page) +int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf, + int buf_len) { int i, result; - unsigned int len; - const unsigned int init_vpd_len = 255; - unsigned char *buf = kmalloc(init_vpd_len, GFP_KERNEL); - - if (!buf) - return NULL; /* Ask for all the pages supported by this device */ - result = scsi_vpd_inquiry(sdev, buf, 0, init_vpd_len); + result = scsi_vpd_inquiry(sdev, buf, 0, buf_len); if (result) goto fail; /* If the user actually wanted this page, we can skip the rest */ if (page == 0) - return buf; + return -EINVAL; - for (i = 0; i < buf[3]; i++) + for (i = 0; i < min((int)buf[3], buf_len - 4); i++) if (buf[i + 4] == page) goto found; + + if (i < buf[3] && i > buf_len) + /* ran off the end of the buffer, give us benefit of doubt */ + goto found; /* The device claims it doesn't support the requested page */ goto fail; found: - result = scsi_vpd_inquiry(sdev, buf, page, 255); + result = scsi_vpd_inquiry(sdev, buf, page, buf_len); if (result) goto fail; - /* - * Some pages are longer than 255 bytes. The actual length of - * the page is returned in the header. - */ - len = ((buf[2] << 8) | buf[3]) + 4; - if (len <= init_vpd_len) - return buf; - - kfree(buf); - buf = kmalloc(len, GFP_KERNEL); - result = scsi_vpd_inquiry(sdev, buf, page, len); - if (result) - goto fail; - - return buf; + return 0; fail: - kfree(buf); - return NULL; + return -EINVAL; } EXPORT_SYMBOL_GPL(scsi_get_vpd_page); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 255da53e5a01..c5e9a99d4066 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1946,13 +1946,13 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) { struct request_queue *q = sdkp->disk->queue; unsigned int sector_sz = sdkp->device->sector_size; - char *buffer; + const int vpd_len = 32; + unsigned char *buffer = kmalloc(vpd_len, GFP_KERNEL); - /* Block Limits VPD */ - buffer = scsi_get_vpd_page(sdkp->device, 0xb0); - - if (buffer == NULL) - return; + if (!buffer || + /* Block Limits VPD */ + scsi_get_vpd_page(sdkp->device, 0xb0, buffer, vpd_len)) + goto out; blk_queue_io_min(sdkp->disk->queue, get_unaligned_be16(&buffer[6]) * sector_sz); @@ -1984,6 +1984,7 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) get_unaligned_be32(&buffer[32]) & ~(1 << 31); } + out: kfree(buffer); } @@ -1993,20 +1994,23 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) */ static void sd_read_block_characteristics(struct scsi_disk *sdkp) { - char *buffer; + unsigned char *buffer; u16 rot; + const int vpd_len = 32; - /* Block Device Characteristics VPD */ - buffer = scsi_get_vpd_page(sdkp->device, 0xb1); + buffer = kmalloc(vpd_len, GFP_KERNEL); - if (buffer == NULL) - return; + if (!buffer || + /* Block Device Characteristics VPD */ + scsi_get_vpd_page(sdkp->device, 0xb1, buffer, vpd_len)) + goto out; rot = get_unaligned_be16(&buffer[4]); if (rot == 1) queue_flag_set_unlocked(QUEUE_FLAG_NONROT, sdkp->disk->queue); + out: kfree(buffer); } diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 55b034b72708..1d7a8780e00c 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -448,13 +448,17 @@ static void ses_match_to_enclosure(struct enclosure_device *edev, .addr = 0, }; - buf = scsi_get_vpd_page(sdev, 0x83); - if (!buf) - return; + buf = kmalloc(INIT_ALLOC_SIZE, GFP_KERNEL); + if (!buf || scsi_get_vpd_page(sdev, 0x83, buf, INIT_ALLOC_SIZE)) + goto free; ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0); vpd_len = ((buf[2] << 8) | buf[3]) + 4; + kfree(buf); + buf = kmalloc(vpd_len, GFP_KERNEL); + if (!buf ||scsi_get_vpd_page(sdev, 0x83, buf, vpd_len)) + goto free; desc = buf + 4; while (desc < buf + vpd_len) { -- cgit v1.2.2 From 40c4f3e4eaa7eda2b0a00abd4d69778808d26f77 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 4 Dec 2009 20:38:49 +0100 Subject: [SCSI] libsrp: fix typo -- replace RDAM by RDMA Fixed a typo in libsrp.c: replaced two occurrences of 'RDAM' by 'RDMA'. Signed-off-by: Bart Van Assche Acked-by: FUJITA Tomonori Signed-off-by: James Bottomley --- drivers/scsi/libsrp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c index ab19b3b4be52..f79602f28ba7 100644 --- a/drivers/scsi/libsrp.c +++ b/drivers/scsi/libsrp.c @@ -1,5 +1,5 @@ /* - * SCSI RDAM Protocol lib functions + * SCSI RDMA Protocol lib functions * * Copyright (C) 2006 FUJITA Tomonori * @@ -440,6 +440,6 @@ int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info, } EXPORT_SYMBOL_GPL(srp_cmd_queue); -MODULE_DESCRIPTION("SCSI RDAM Protocol lib functions"); +MODULE_DESCRIPTION("SCSI RDMA Protocol lib functions"); MODULE_AUTHOR("FUJITA Tomonori"); MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 9b7dac086bec7c71722d6e79464609e17f0996e7 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 4 Dec 2009 20:43:37 +0100 Subject: [SCSI] ibmvscsi: fix a typo in a source code comment Signed-off-by: Bart Van Assche Acked-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index e475b7957c2d..e3a18e0ef276 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -40,7 +40,7 @@ * (CRQ), which is just a buffer of 16 byte entries in the receiver's * Senders cannot access the buffer directly, but send messages by * making a hypervisor call and passing in the 16 bytes. The hypervisor - * puts the message in the next 16 byte space in round-robbin fashion, + * puts the message in the next 16 byte space in round-robin fashion, * turns on the high order bit of the message (the valid bit), and * generates an interrupt to the receiver (if interrupts are turned on.) * The receiver just turns off the valid bit when they have copied out -- cgit v1.2.2 From 8fe79162a6807bf120140d64e96da54fc273b88b Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 8 Dec 2009 14:08:57 -0800 Subject: [SCSI] eata: fix buffer overflow Allows i == MAX_INT_PARAM, which is out of range. Signed-off-by: Roel Kluin Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/eata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index c7076ce25e21..3c5abf7cd762 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -1509,7 +1509,7 @@ static int option_setup(char *str) char *cur = str; int i = 1; - while (cur && isdigit(*cur) && i <= MAX_INT_PARAM) { + while (cur && isdigit(*cur) && i < MAX_INT_PARAM) { ints[i++] = simple_strtoul(cur, NULL, 0); if ((cur = strchr(cur, ',')) != NULL) -- cgit v1.2.2 From 4a02462af1f4c3498e6a330ffd5c063118309b31 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 8 Dec 2009 14:08:59 -0800 Subject: [SCSI] u14-34f: fix buffer overflow This allows i == MAX_INT_PARAM, which is out of range for ints[] Signed-off-by: Roel Kluin Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/u14-34f.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index 54023d41fd15..26e8e0e6b8dd 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -1070,7 +1070,7 @@ static int option_setup(char *str) { char *cur = str; int i = 1; - while (cur && isdigit(*cur) && i <= MAX_INT_PARAM) { + while (cur && isdigit(*cur) && i < MAX_INT_PARAM) { ints[i++] = simple_strtoul(cur, NULL, 0); if ((cur = strchr(cur, ',')) != NULL) cur++; -- cgit v1.2.2 From 340f052001d46aff9e7e853c492e0d3f5554d42f Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 8 Dec 2009 14:08:56 -0800 Subject: [SCSI] ibmmca: fix buffer overflow Allows i == IM_MAX_HOSTS, which is out of range. Signed-off-by: Roel Kluin Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/ibmmca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c index 9c1e6a5b5af0..9a4b69d4f4eb 100644 --- a/drivers/scsi/ibmmca.c +++ b/drivers/scsi/ibmmca.c @@ -2336,7 +2336,7 @@ static int option_setup(char *str) char *cur = str; int i = 1; - while (cur && isdigit(*cur) && i <= IM_MAX_HOSTS) { + while (cur && isdigit(*cur) && i < IM_MAX_HOSTS) { ints[i++] = simple_strtoul(cur, NULL, 0); if ((cur = strchr(cur, ',')) != NULL) cur++; -- cgit v1.2.2 From e47c11c7a402a054a85cb917a6ed020f6b5fae04 Mon Sep 17 00:00:00 2001 From: Erik Ekman Date: Mon, 14 Dec 2009 21:21:56 +0100 Subject: [SCSI] fusion: fix warning when not using procfs Fixes the following warning: drivers/message/fusion/mptbase.c:129: warning: 'mpt_proc_root_dir' defined but not used also moves it from public data section since it is static. Signed-off-by: Erik Ekman Acked-by: "Desai, Kashyap" Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 44d2037e9e56..5382b5a44aff 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -126,8 +126,6 @@ static int mfcounter = 0; * Public data... */ -static struct proc_dir_entry *mpt_proc_root_dir; - #define WHOINIT_UNKNOWN 0xAA /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -146,6 +144,9 @@ static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS]; static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS]; static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS]; +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry *mpt_proc_root_dir; +#endif /* * Driver Callback Index's -- cgit v1.2.2 From f2818663c82b7297ff4aa38cbddb870dc02f7104 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Tue, 15 Dec 2009 09:26:06 +0100 Subject: [SCSI] scsi_transport_fc: Remove capping from dev_loss_tmo Currently dev_loss_tmo is capped by SCSI_DEVICE_BLOCK_MAX_TIMEOUT. This causes problem with multipathing when the 'no_path_retry' setting exceeds the dev_loss_tmo setting, as then the system might run into a deadlock when all paths have been removed temporarily for longer than dev_loss_tmo. The principal reasons for the capping has been that we should not allow a remote port to remain in status 'blocked' indefinitely, so the capping is there to ensure that the port status is being reset eventually. However, the fast_io_fail_tmo will also move the remote port out of the 'blocked' state, so for any HBA driver implementing both the capping should really be on the fast_io_fail_tmo, and not on the dev_loss_tmo. This patch implements just that, ie the fast_io_fail_tmo is capped to SCSI_DEVICE_BLOCK_TIMEOUT and the capping is removed from dev_loss_tmo when fast_io_fail_tmo is set. This allows us to synchronize the dev_loss_tmo setting to the 'no_path_retry' setting from multipathing thus avoiding the deadlock. Signed-off-by: Hannes Reinecke Acked-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_fc.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 653f22a8deb9..79660ee3e211 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -475,7 +475,8 @@ MODULE_PARM_DESC(dev_loss_tmo, "Maximum number of seconds that the FC transport should" " insulate the loss of a remote port. Once this value is" " exceeded, the scsi target is removed. Value should be" - " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT."); + " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT if" + " fast_io_fail_tmo is not set."); /* * Netlink Infrastructure @@ -842,9 +843,17 @@ store_fc_rport_dev_loss_tmo(struct device *dev, struct device_attribute *attr, (rport->port_state == FC_PORTSTATE_NOTPRESENT)) return -EBUSY; val = simple_strtoul(buf, &cp, 0); - if ((*cp && (*cp != '\n')) || - (val < 0) || (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)) + if ((*cp && (*cp != '\n')) || (val < 0)) return -EINVAL; + + /* + * If fast_io_fail is off we have to cap + * dev_loss_tmo at SCSI_DEVICE_BLOCK_MAX_TIMEOUT + */ + if (rport->fast_io_fail_tmo == -1 && + val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT) + return -EINVAL; + i->f->set_rport_dev_loss_tmo(rport, val); return count; } @@ -925,9 +934,16 @@ store_fc_rport_fast_io_fail_tmo(struct device *dev, rport->fast_io_fail_tmo = -1; else { val = simple_strtoul(buf, &cp, 0); - if ((*cp && (*cp != '\n')) || - (val < 0) || (val >= rport->dev_loss_tmo)) + if ((*cp && (*cp != '\n')) || (val < 0)) return -EINVAL; + /* + * Cap fast_io_fail by dev_loss_tmo or + * SCSI_DEVICE_BLOCK_MAX_TIMEOUT. + */ + if ((val >= rport->dev_loss_tmo) || + (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)) + return -EINVAL; + rport->fast_io_fail_tmo = val; } return count; -- cgit v1.2.2 From 02507a80b35edd720480540d917e9f92cc371009 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sat, 5 Dec 2009 12:30:42 +1100 Subject: [SCSI] mac_esp: fix PIO mode, take 2 The mac_esp PIO algorithm no longer works in 2.6.31 and crashes my Centris 660av. So here's a better one. Also, force async with esp_set_offset() rather than esp_slave_configure(). One of the SCSI drives I tested still doesn't like the PIO mode and fails with "esp: esp0: Reconnect IRQ2 timeout" (the same drive works fine in PDMA mode). This failure happens when esp_reconnect_with_tag() tries to read in two tag bytes but the chip only provides one (0x20). I don't know what causes this. I decided not to waste any more time trying to fix it because the best solution is to rip out the PIO mode altogether and use the DMA engine. Signed-off-by: Finn Thain Signed-off-by: James Bottomley --- drivers/scsi/esp_scsi.c | 14 +++----- drivers/scsi/mac_esp.c | 95 +++++++++++++++++++++++++------------------------ 2 files changed, 53 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index a680e18b5f3b..e2bc779f86c1 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -1449,9 +1449,6 @@ static void esp_msgin_sdtr(struct esp *esp, struct esp_target_data *tp) if (offset > 15) goto do_reject; - if (esp->flags & ESP_FLAG_DISABLE_SYNC) - offset = 0; - if (offset) { int one_clock; @@ -2405,12 +2402,6 @@ static int esp_slave_configure(struct scsi_device *dev) struct esp_target_data *tp = &esp->target[dev->id]; int goal_tags, queue_depth; - if (esp->flags & ESP_FLAG_DISABLE_SYNC) { - /* Bypass async domain validation */ - dev->ppr = 0; - dev->sdtr = 0; - } - goal_tags = 0; if (dev->tagged_supported) { @@ -2660,7 +2651,10 @@ static void esp_set_offset(struct scsi_target *target, int offset) struct esp *esp = shost_priv(host); struct esp_target_data *tp = &esp->target[target->id]; - tp->nego_goal_offset = offset; + if (esp->flags & ESP_FLAG_DISABLE_SYNC) + tp->nego_goal_offset = 0; + else + tp->nego_goal_offset = offset; tp->flags |= ESP_TGT_CHECK_NEGO; } diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index c24e86f07804..dd808ae942a1 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -22,7 +22,6 @@ #include #include - #include #include @@ -279,24 +278,27 @@ static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count, * Programmed IO routines follow. */ -static inline int mac_esp_wait_for_fifo(struct esp *esp) +static inline unsigned int mac_esp_wait_for_fifo(struct esp *esp) { int i = 500000; do { - if (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES) - return 0; + unsigned int fbytes = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; + + if (fbytes) + return fbytes; udelay(2); } while (--i); printk(KERN_ERR PFX "FIFO is empty (sreg %02x)\n", esp_read8(ESP_STATUS)); - return 1; + return 0; } static inline int mac_esp_wait_for_intr(struct esp *esp) { + struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp); int i = 500000; do { @@ -308,6 +310,7 @@ static inline int mac_esp_wait_for_intr(struct esp *esp) } while (--i); printk(KERN_ERR PFX "IRQ timeout (sreg %02x)\n", esp->sreg); + mep->error = 1; return 1; } @@ -347,11 +350,10 @@ static inline int mac_esp_wait_for_intr(struct esp *esp) static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, u32 dma_count, int write, u8 cmd) { - unsigned long flags; struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp); u8 *fifo = esp->regs + ESP_FDATA * 16; - local_irq_save(flags); + disable_irq(esp->host->irq); cmd &= ~ESP_CMD_DMA; mep->error = 0; @@ -359,11 +361,35 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, if (write) { scsi_esp_cmd(esp, cmd); - if (!mac_esp_wait_for_intr(esp)) { - if (mac_esp_wait_for_fifo(esp)) - esp_count = 0; - } else { - esp_count = 0; + while (1) { + unsigned int n; + + n = mac_esp_wait_for_fifo(esp); + if (!n) + break; + + if (n > esp_count) + n = esp_count; + esp_count -= n; + + MAC_ESP_PIO_LOOP("%2@,%0@+", n); + + if (!esp_count) + break; + + if (mac_esp_wait_for_intr(esp)) + break; + + if (((esp->sreg & ESP_STAT_PMASK) != ESP_DIP) && + ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP)) + break; + + esp->ireg = esp_read8(ESP_INTRPT); + if ((esp->ireg & (ESP_INTR_DC | ESP_INTR_BSERV)) != + ESP_INTR_BSERV) + break; + + scsi_esp_cmd(esp, ESP_CMD_TI); } } else { scsi_esp_cmd(esp, ESP_CMD_FLUSH); @@ -374,47 +400,24 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, MAC_ESP_PIO_LOOP("%0@+,%2@", esp_count); scsi_esp_cmd(esp, cmd); - } - - while (esp_count) { - unsigned int n; - - if (mac_esp_wait_for_intr(esp)) { - mep->error = 1; - break; - } - - if (esp->sreg & ESP_STAT_SPAM) { - printk(KERN_ERR PFX "gross error\n"); - mep->error = 1; - break; - } - n = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; - - if (write) { - if (n > esp_count) - n = esp_count; - esp_count -= n; - - MAC_ESP_PIO_LOOP("%2@,%0@+", n); + while (esp_count) { + unsigned int n; - if ((esp->sreg & ESP_STAT_PMASK) == ESP_STATP) + if (mac_esp_wait_for_intr(esp)) break; - if (esp_count) { - esp->ireg = esp_read8(ESP_INTRPT); - if (esp->ireg & ESP_INTR_DC) - break; + if (((esp->sreg & ESP_STAT_PMASK) != ESP_DOP) && + ((esp->sreg & ESP_STAT_PMASK) != ESP_MOP)) + break; - scsi_esp_cmd(esp, ESP_CMD_TI); - } - } else { esp->ireg = esp_read8(ESP_INTRPT); - if (esp->ireg & ESP_INTR_DC) + if ((esp->ireg & (ESP_INTR_DC | ESP_INTR_BSERV)) != + ESP_INTR_BSERV) break; - n = MAC_ESP_FIFO_SIZE - n; + n = MAC_ESP_FIFO_SIZE - + (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES); if (n > esp_count) n = esp_count; @@ -429,7 +432,7 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, } } - local_irq_restore(flags); + enable_irq(esp->host->irq); } static int mac_esp_irq_pending(struct esp *esp) -- cgit v1.2.2 From 65f89c2396aa113a06fe7e2f6ba46f0712cb4806 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 19:01:13 +0530 Subject: [SCSI] mptfusion: Added MPI_SCSIIO_CONTROL_HEADOFQ priority There is a 'ioprio' field in the BIO and the Request structure. check this priority field and set MPI_SCSIIO_CONTROL_HEADOFQ to pass down I/O priority. An enhancement to the LSI Disk Array Controller firmware is being developed to look at the Head Of Queue bit to allow I/Os with the HOQ bit set to be processed before I/Os which do not have the HOQ bit set. In order to set the HOQ bit, the mpt fusion driver needs to look at the 'ioprio' field in the request structure associated with the scsi command. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptscsih.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 57752751712b..8128d3095f9f 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -1438,9 +1438,14 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES) && (SCpnt->device->tagged_supported)) { scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ; - } else { + if (SCpnt->request && SCpnt->request->ioprio) { + if (((SCpnt->request->ioprio & 0x7) == 1) || + !(SCpnt->request->ioprio & 0x7)) + scsictl |= MPI_SCSIIO_CONTROL_HEADOFQ; + } + } else scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED; - } + /* Use the above information to set up the message frame */ -- cgit v1.2.2 From e0f553ab58f478321717100e44b28f765bd2a045 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 19:01:58 +0530 Subject: [SCSI] mptfusion: Added sysfs expander manufacture information at the time of expander add. Added new function mptsas_exp_manufacture_info, which will obtain the REPORT_MANUFACTURING, and fill the details into the sas_expander_device object when the expander port is created. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptsas.c | 186 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) (limited to 'drivers') diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 83873e3d0ce7..1b7f550daebc 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -2686,6 +2686,187 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, return error; } +struct rep_manu_request{ + u8 smp_frame_type; + u8 function; + u8 reserved; + u8 request_length; +}; + +struct rep_manu_reply{ + u8 smp_frame_type; /* 0x41 */ + u8 function; /* 0x01 */ + u8 function_result; + u8 response_length; + u16 expander_change_count; + u8 reserved0[2]; + u8 sas_format:1; + u8 reserved1:7; + u8 reserved2[3]; + u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; + u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; + u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN]; + u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN]; + u16 component_id; + u8 component_revision_id; + u8 reserved3; + u8 vendor_specific[8]; +}; + +/** + * mptsas_exp_repmanufacture_info - + * @ioc: per adapter object + * @sas_address: expander sas address + * @edev: the sas_expander_device object + * + * Fills in the sas_expander_device object when SMP port is created. + * + * Returns 0 for success, non-zero for failure. + */ +static int +mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc, + u64 sas_address, struct sas_expander_device *edev) +{ + MPT_FRAME_HDR *mf; + SmpPassthroughRequest_t *smpreq; + SmpPassthroughReply_t *smprep; + struct rep_manu_reply *manufacture_reply; + struct rep_manu_request *manufacture_request; + int ret; + int flagsLength; + unsigned long timeleft; + char *psge; + unsigned long flags; + void *data_out = NULL; + dma_addr_t data_out_dma = 0; + u32 sz; + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n", + __func__, ioc->name); + return -EFAULT; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + + ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex); + if (ret) + goto out; + + mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); + if (!mf) { + ret = -ENOMEM; + goto out_unlock; + } + + smpreq = (SmpPassthroughRequest_t *)mf; + memset(smpreq, 0, sizeof(*smpreq)); + + sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply); + + data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma); + if (!data_out) { + printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + ret = -ENOMEM; + goto put_mf; + } + + manufacture_request = data_out; + manufacture_request->smp_frame_type = 0x40; + manufacture_request->function = 1; + manufacture_request->reserved = 0; + manufacture_request->request_length = 0; + + smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; + smpreq->PhysicalPort = 0xFF; + *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address); + smpreq->RequestDataLength = sizeof(struct rep_manu_request); + + psge = (char *) + (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4)); + + flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_SYSTEM_ADDRESS | + MPI_SGE_FLAGS_HOST_TO_IOC | + MPI_SGE_FLAGS_END_OF_BUFFER; + flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; + flagsLength |= sizeof(struct rep_manu_request); + + ioc->add_sge(psge, flagsLength, data_out_dma); + psge += ioc->SGE_size; + + flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_SYSTEM_ADDRESS | + MPI_SGE_FLAGS_IOC_TO_HOST | + MPI_SGE_FLAGS_END_OF_BUFFER; + flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; + flagsLength |= sizeof(struct rep_manu_reply); + ioc->add_sge(psge, flagsLength, data_out_dma + + sizeof(struct rep_manu_request)); + + INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) + mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); + + timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); + if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; + mpt_free_msg_frame(ioc, mf); + mf = NULL; + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out_free; + if (!timeleft) + mpt_HardResetHandler(ioc, CAN_SLEEP); + goto out_free; + } + + mf = NULL; + + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) { + u8 *tmp; + + smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; + if (le16_to_cpu(smprep->ResponseDataLength) != + sizeof(struct rep_manu_reply)) + goto out_free; + + manufacture_reply = data_out + sizeof(struct rep_manu_request); + strncpy(edev->vendor_id, manufacture_reply->vendor_id, + SAS_EXPANDER_VENDOR_ID_LEN); + strncpy(edev->product_id, manufacture_reply->product_id, + SAS_EXPANDER_PRODUCT_ID_LEN); + strncpy(edev->product_rev, manufacture_reply->product_rev, + SAS_EXPANDER_PRODUCT_REV_LEN); + edev->level = manufacture_reply->sas_format; + if (manufacture_reply->sas_format) { + strncpy(edev->component_vendor_id, + manufacture_reply->component_vendor_id, + SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); + tmp = (u8 *)&manufacture_reply->component_id; + edev->component_id = tmp[0] << 8 | tmp[1]; + edev->component_revision_id = + manufacture_reply->component_revision_id; + } + } else { + printk(MYIOC_s_ERR_FMT + "%s: smp passthru reply failed to be returned\n", + ioc->name, __func__); + ret = -ENXIO; + } +out_free: + if (data_out_dma) + pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma); +put_mf: + if (mf) + mpt_free_msg_frame(ioc, mf); +out_unlock: + CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) + mutex_unlock(&ioc->sas_mgmt.mutex); +out: + return ret; + } + static void mptsas_parse_device_info(struct sas_identify *identify, struct mptsas_devinfo *device_info) @@ -2967,6 +3148,11 @@ static int mptsas_probe_one_phy(struct device *dev, goto out; } mptsas_set_rphy(ioc, phy_info, rphy); + if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE || + identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) + mptsas_exp_repmanufacture_info(ioc, + identify.sas_address, + rphy_to_expander_device(rphy)); } out: -- cgit v1.2.2 From 64e155adc250ab68255b761c1faa77799aa1e41a Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 19:02:29 +0530 Subject: [SCSI] mptfusion: block device when target is being removed by FW Add support to set the sdev state to SDEV_BLOCK during device removal to stop IOs comming to the deleting driver immediately. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptsas.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 1b7f550daebc..c20bbe45da82 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1075,6 +1075,19 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id) return 0; } +static void +mptsas_block_io_sdev(struct scsi_device *sdev, void *data) +{ + scsi_device_set_state(sdev, SDEV_BLOCK); +} + +static void +mptsas_block_io_starget(struct scsi_target *starget) +{ + if (starget) + starget_for_each_device(starget, NULL, mptsas_block_io_sdev); +} + /** * mptsas_target_reset_queue * @@ -1098,10 +1111,11 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc, id = sas_event_data->TargetID; channel = sas_event_data->Bus; - if (!(vtarget = mptsas_find_vtarget(ioc, channel, id))) - return; - - vtarget->deleted = 1; /* block IO */ + vtarget = mptsas_find_vtarget(ioc, channel, id); + if (vtarget) { + mptsas_block_io_starget(vtarget->starget); + vtarget->deleted = 1; /* block IO */ + } target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event), GFP_ATOMIC); @@ -1868,7 +1882,8 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) if (ioc->sas_discovery_quiesce_io) return SCSI_MLQUEUE_HOST_BUSY; -// scsi_print_command(SCpnt); + if (ioc->debug_level & MPT_DEBUG_SCSI) + scsi_print_command(SCpnt); return mptscsih_qcmd(SCpnt,done); } -- cgit v1.2.2 From de81562f2f9852a1f2c609ede1e26c07ed457c60 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 19:02:59 +0530 Subject: [SCSI] mptfusion: corrected if condition check for SCSIIO and PASSTHROUGH commands Modified the function type check to verify it is not MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH or MPI_FUNCTION_SCSI_IO_REQUEST. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index 352acd05c46b..caa8f568a41c 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -360,8 +360,8 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function) u16 iocstatus; /* bus reset is only good for SCSI IO, RAID PASSTHRU */ - if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) || - (function == MPI_FUNCTION_SCSI_IO_REQUEST)) { + if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || + function == MPI_FUNCTION_SCSI_IO_REQUEST)) { dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt, not SCSI_IO!!\n", ioc->name)); return -EPERM; -- cgit v1.2.2 From 4ffd005a4dedf536330756742595ec904f740f48 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 19:04:49 +0530 Subject: [SCSI] mptfusion: Bump version 03.04.14 Version upgrade to 3.04.14. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index b4948671eb92..9718c8f2e959 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -76,8 +76,8 @@ #define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.04.13" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.13" +#define MPT_LINUX_VERSION_COMMON "3.04.14" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.14" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ -- cgit v1.2.2 From 3dbf6c0012d12473461b7485006db373e8192fa5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 19 Dec 2009 08:17:27 +0100 Subject: [SCSI] pm8001: Use kzalloc for allocating only one thing Use kzalloc rather than kcalloc(1,...) The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ @@ - kcalloc(1, + kzalloc( ...) // Signed-off-by: Julia Lawall Acked-by:Jack Wang Signed-off-by: James Bottomley --- drivers/scsi/pm8001/pm8001_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index c2f1032496cb..f80c1da8f6ca 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -654,7 +654,7 @@ static int __devinit pm8001_pci_probe(struct pci_dev *pdev, } chip = &pm8001_chips[ent->driver_data]; SHOST_TO_SAS_HA(shost) = - kcalloc(1, sizeof(struct sas_ha_struct), GFP_KERNEL); + kzalloc(sizeof(struct sas_ha_struct), GFP_KERNEL); if (!SHOST_TO_SAS_HA(shost)) { rc = -ENOMEM; goto err_out_free_host; -- cgit v1.2.2 From 0ed8570ef4d51bb46e2028b2e3c3ddd1f860e193 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 21 Dec 2009 16:27:55 -0800 Subject: [SCSI] cxgbi3: remove unnecessary NULL test Stanse found that c3cn is poked many times around in cxgb3i_conn_pdu_ready, there is no need to check if it is NULL. Remove the test. Signed-off-by: Jiri Slaby Reviewed-by: Mike Christie Acked-by: Karen Xie Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/cxgb3i/cxgb3i_pdu.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxgb3i/cxgb3i_pdu.c b/drivers/scsi/cxgb3i/cxgb3i_pdu.c index 1fe3b0f1f3c9..9c38539557fc 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_pdu.c +++ b/drivers/scsi/cxgb3i/cxgb3i_pdu.c @@ -461,10 +461,8 @@ void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn) skb = skb_peek(&c3cn->receive_queue); } read_unlock(&c3cn->callback_lock); - if (c3cn) { - c3cn->copied_seq += read; - cxgb3i_c3cn_rx_credits(c3cn, read); - } + c3cn->copied_seq += read; + cxgb3i_c3cn_rx_credits(c3cn, read); conn->rxdata_octets += read; if (err) { -- cgit v1.2.2 From 5d7ebb9c7a04d29efce1099024944dfd94d9f63c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 28 Dec 2009 20:08:39 +0200 Subject: [SCSI] FlashPoint: fix off by one tests The check on MAX_SCSI_TAR should be >= instead of > or we could go past the end of the array. Joe Eykholt aslo correctly points out that the check on MAX_LUN should be >= as well. That matches with how it is used in the rest of the file. Signed-off-by: Dan Carpenter Signed-off-by: James Bottomley --- drivers/scsi/FlashPoint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c index b898d382b7b0..e40cdfb7541f 100644 --- a/drivers/scsi/FlashPoint.c +++ b/drivers/scsi/FlashPoint.c @@ -3924,7 +3924,7 @@ static void FPT_sinits(struct sccb *p_sccb, unsigned char p_card) { struct sccb_mgr_tar_info *currTar_Info; - if ((p_sccb->TargID > MAX_SCSI_TAR) || (p_sccb->Lun > MAX_LUN)) { + if ((p_sccb->TargID >= MAX_SCSI_TAR) || (p_sccb->Lun >= MAX_LUN)) { return; } currTar_Info = &FPT_sccbMgrTbl[p_card][p_sccb->TargID]; -- cgit v1.2.2 From e7efe5932b1d3916c79326a4221693ea90a900e2 Mon Sep 17 00:00:00 2001 From: Douglas Gilbert Date: Sun, 3 Jan 2010 13:51:15 -0500 Subject: [SCSI] skip sense logging for some ATA PASS-THROUGH cdbs Further to the lsml thread titled: "does scsi_io_completion need to dump sense data for ata pass through (ck_cond = 1) ?" This is a patch to skip logging when the sense data is associated with a SENSE_KEY of "RECOVERED_ERROR" and the additional sense code is "ATA PASS-THROUGH INFORMATION AVAILABLE". This only occurs with the SAT ATA PASS-THROUGH commands when CK_COND=1 (in the cdb). It indicates that the sense data contains ATA registers. Smartmontools uses such commands on ATA disks connected via SAT. Periodic checks such as those done by smartd cause nuisance entries into logs that are: - neither errors nor warnings - pointless unless the cdb that caused them are also logged Signed-off-by: Douglas Gilbert Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index c6642423cc67..56977097de9f 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -773,8 +773,14 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) * we already took a copy of the original into rq->errors which * is what gets returned to the user */ - if (sense_valid && sshdr.sense_key == RECOVERED_ERROR) { - if (!(req->cmd_flags & REQ_QUIET)) + if (sense_valid && (sshdr.sense_key == RECOVERED_ERROR)) { + /* if ATA PASS-THROUGH INFORMATION AVAILABLE skip + * print since caller wants ATA registers. Only occurs on + * SCSI ATA PASS_THROUGH commands when CK_COND=1 + */ + if ((sshdr.asc == 0x0) && (sshdr.ascq == 0x1d)) + ; + else if (!(req->cmd_flags & REQ_QUIET)) scsi_print_sense("", cmd); result = 0; /* BLOCK_PC may have set error */ -- cgit v1.2.2 From 1fe6dbf4d0afba52ad0249f398e6296a1433a004 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 4 Jan 2010 10:19:34 -0500 Subject: [SCSI] gdth: Convert to use regular kernel types. converted using this script.. perl -p -i -e 's|ulong32|u32|g' drivers/scsi/gdth* perl -p -i -e 's|ulong64|u64|g' drivers/scsi/gdth* perl -p -i -e 's|ushort|u16|g' drivers/scsi/gdth* perl -p -i -e 's|unchar|u8|g' drivers/scsi/gdth* perl -p -i -e 's|ulong|unsigned long|g' drivers/scsi/gdth* perl -p -i -e 's|PACKED|__attribute__((packed))|g' drivers/scsi/gdth* sha1sum of the generated code was identical before and after. Signed-off-by: Dave Jones Signed-off-by: James Bottomley --- drivers/scsi/gdth.c | 430 ++++++++++----------- drivers/scsi/gdth.h | 952 +++++++++++++++++++++++----------------------- drivers/scsi/gdth_ioctl.h | 366 +++++++++--------- drivers/scsi/gdth_proc.c | 42 +- drivers/scsi/gdth_proc.h | 4 +- 5 files changed, 893 insertions(+), 901 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 9e8fce0f0c1b..ba3c94c9c25f 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -140,40 +140,40 @@ #include "gdth.h" static void gdth_delay(int milliseconds); -static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs); +static void gdth_eval_mapping(u32 size, u32 *cyls, int *heads, int *secs); static irqreturn_t gdth_interrupt(int irq, void *dev_id); static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int gdth_from_wait, int* pIndex); -static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index, +static int gdth_sync_event(gdth_ha_str *ha, int service, u8 index, Scsi_Cmnd *scp); static int gdth_async_event(gdth_ha_str *ha); static void gdth_log_event(gdth_evt_data *dvr, char *buffer); -static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar priority); +static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, u8 priority); static void gdth_next(gdth_ha_str *ha); -static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b); +static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, u8 b); static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp); -static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, ushort source, - ushort idx, gdth_evt_data *evt); +static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, u16 source, + u16 idx, gdth_evt_data *evt); static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr); -static void gdth_readapp_event(gdth_ha_str *ha, unchar application, +static void gdth_readapp_event(gdth_ha_str *ha, u8 application, gdth_evt_str *estr); static void gdth_clear_events(void); static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, - char *buffer, ushort count); + char *buffer, u16 count); static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp); -static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive); +static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, u16 hdrive); static void gdth_enable_int(gdth_ha_str *ha); static int gdth_test_busy(gdth_ha_str *ha); static int gdth_get_cmd_index(gdth_ha_str *ha); static void gdth_release_event(gdth_ha_str *ha); -static int gdth_wait(gdth_ha_str *ha, int index,ulong32 time); -static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode, - ulong32 p1, ulong64 p2,ulong64 p3); +static int gdth_wait(gdth_ha_str *ha, int index,u32 time); +static int gdth_internal_cmd(gdth_ha_str *ha, u8 service, u16 opcode, + u32 p1, u64 p2,u64 p3); static int gdth_search_drives(gdth_ha_str *ha); -static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive); +static int gdth_analyse_hdrive(gdth_ha_str *ha, u16 hdrive); static const char *gdth_ctr_name(gdth_ha_str *ha); @@ -189,7 +189,7 @@ static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp, static void gdth_scsi_done(struct scsi_cmnd *scp); #ifdef DEBUG_GDTH -static unchar DebugState = DEBUG_GDTH; +static u8 DebugState = DEBUG_GDTH; #ifdef __SERIAL__ #define MAX_SERBUF 160 @@ -270,30 +270,30 @@ static int ser_printk(const char *fmt, ...) #endif #ifdef GDTH_STATISTICS -static ulong32 max_rq=0, max_index=0, max_sg=0; +static u32 max_rq=0, max_index=0, max_sg=0; #ifdef INT_COAL -static ulong32 max_int_coal=0; +static u32 max_int_coal=0; #endif -static ulong32 act_ints=0, act_ios=0, act_stats=0, act_rq=0; +static u32 act_ints=0, act_ios=0, act_stats=0, act_rq=0; static struct timer_list gdth_timer; #endif -#define PTR2USHORT(a) (ushort)(ulong)(a) +#define PTR2USHORT(a) (u16)(unsigned long)(a) #define GDTOFFSOF(a,b) (size_t)&(((a*)0)->b) #define INDEX_OK(i,t) ((i)(a)->virt_bus ? (b-1):(b)) #ifdef CONFIG_ISA -static unchar gdth_drq_tab[4] = {5,6,7,7}; /* DRQ table */ +static u8 gdth_drq_tab[4] = {5,6,7,7}; /* DRQ table */ #endif #if defined(CONFIG_EISA) || defined(CONFIG_ISA) -static unchar gdth_irq_tab[6] = {0,10,11,12,14,0}; /* IRQ table */ +static u8 gdth_irq_tab[6] = {0,10,11,12,14,0}; /* IRQ table */ #endif -static unchar gdth_polling; /* polling if TRUE */ +static u8 gdth_polling; /* polling if TRUE */ static int gdth_ctr_count = 0; /* controller count */ static LIST_HEAD(gdth_instances); /* controller list */ -static unchar gdth_write_through = FALSE; /* write through */ +static u8 gdth_write_through = FALSE; /* write through */ static gdth_evt_str ebuffer[MAX_EVENTS]; /* event buffer */ static int elastidx; static int eoldidx; @@ -303,7 +303,7 @@ static int major; #define DOU 2 /* OUT data direction */ #define DNO DIN /* no data transfer */ #define DUN DIN /* unknown data direction */ -static unchar gdth_direction_tab[0x100] = { +static u8 gdth_direction_tab[0x100] = { DNO,DNO,DIN,DIN,DOU,DIN,DIN,DOU,DIN,DUN,DOU,DOU,DUN,DUN,DUN,DIN, DNO,DIN,DIN,DOU,DIN,DOU,DNO,DNO,DOU,DNO,DIN,DNO,DIN,DOU,DNO,DUN, DIN,DUN,DIN,DUN,DOU,DIN,DUN,DUN,DIN,DIN,DOU,DNO,DUN,DIN,DOU,DOU, @@ -390,7 +390,7 @@ static gdth_ha_str *gdth_find_ha(int hanum) static struct gdth_cmndinfo *gdth_get_cmndinfo(gdth_ha_str *ha) { struct gdth_cmndinfo *priv = NULL; - ulong flags; + unsigned long flags; int i; spin_lock_irqsave(&ha->smp_lock, flags); @@ -493,7 +493,7 @@ int gdth_execute(struct Scsi_Host *shost, gdth_cmd_str *gdtcmd, char *cmnd, return rval; } -static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs) +static void gdth_eval_mapping(u32 size, u32 *cyls, int *heads, int *secs) { *cyls = size /HEADS/SECS; if (*cyls <= MAXCYLS) { @@ -514,9 +514,9 @@ static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs /* controller search and initialization functions */ #ifdef CONFIG_EISA -static int __init gdth_search_eisa(ushort eisa_adr) +static int __init gdth_search_eisa(u16 eisa_adr) { - ulong32 id; + u32 id; TRACE(("gdth_search_eisa() adr. %x\n",eisa_adr)); id = inl(eisa_adr+ID0REG); @@ -533,13 +533,13 @@ static int __init gdth_search_eisa(ushort eisa_adr) #endif /* CONFIG_EISA */ #ifdef CONFIG_ISA -static int __init gdth_search_isa(ulong32 bios_adr) +static int __init gdth_search_isa(u32 bios_adr) { void __iomem *addr; - ulong32 id; + u32 id; TRACE(("gdth_search_isa() bios adr. %x\n",bios_adr)); - if ((addr = ioremap(bios_adr+BIOS_ID_OFFS, sizeof(ulong32))) != NULL) { + if ((addr = ioremap(bios_adr+BIOS_ID_OFFS, sizeof(u32))) != NULL) { id = readl(addr); iounmap(addr); if (id == GDT2_ID) /* GDT2000 */ @@ -551,7 +551,7 @@ static int __init gdth_search_isa(ulong32 bios_adr) #ifdef CONFIG_PCI -static bool gdth_search_vortex(ushort device) +static bool gdth_search_vortex(u16 device) { if (device <= PCI_DEVICE_ID_VORTEX_GDT6555) return true; @@ -603,9 +603,9 @@ static void __devexit gdth_pci_remove_one(struct pci_dev *pdev) static int __devinit gdth_pci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - ushort vendor = pdev->vendor; - ushort device = pdev->device; - ulong base0, base1, base2; + u16 vendor = pdev->vendor; + u16 device = pdev->device; + unsigned long base0, base1, base2; int rc; gdth_pci_str gdth_pcistr; gdth_ha_str *ha = NULL; @@ -658,10 +658,10 @@ static int __devinit gdth_pci_init_one(struct pci_dev *pdev, #endif /* CONFIG_PCI */ #ifdef CONFIG_EISA -static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha) +static int __init gdth_init_eisa(u16 eisa_adr,gdth_ha_str *ha) { - ulong32 retries,id; - unchar prot_ver,eisacf,i,irq_found; + u32 retries,id; + u8 prot_ver,eisacf,i,irq_found; TRACE(("gdth_init_eisa() adr. %x\n",eisa_adr)); @@ -688,7 +688,7 @@ static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha) return 0; } ha->bmic = eisa_adr; - ha->brd_phys = (ulong32)eisa_adr >> 12; + ha->brd_phys = (u32)eisa_adr >> 12; outl(0,eisa_adr+MAILBOXREG); outl(0,eisa_adr+MAILBOXREG+4); @@ -752,12 +752,12 @@ static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha) #endif /* CONFIG_EISA */ #ifdef CONFIG_ISA -static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha) +static int __init gdth_init_isa(u32 bios_adr,gdth_ha_str *ha) { register gdt2_dpram_str __iomem *dp2_ptr; int i; - unchar irq_drq,prot_ver; - ulong32 retries; + u8 irq_drq,prot_ver; + u32 retries; TRACE(("gdth_init_isa() bios adr. %x\n",bios_adr)); @@ -812,7 +812,7 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha) } gdth_delay(1); } - prot_ver = (unchar)readl(&dp2_ptr->u.ic.S_Info[0]); + prot_ver = (u8)readl(&dp2_ptr->u.ic.S_Info[0]); writeb(0, &dp2_ptr->u.ic.Status); writeb(0xff, &dp2_ptr->io.irqdel); if (prot_ver != PROTOCOL_VERSION) { @@ -859,9 +859,9 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, register gdt6_dpram_str __iomem *dp6_ptr; register gdt6c_dpram_str __iomem *dp6c_ptr; register gdt6m_dpram_str __iomem *dp6m_ptr; - ulong32 retries; - unchar prot_ver; - ushort command; + u32 retries; + u8 prot_ver; + u16 command; int i, found = FALSE; TRACE(("gdth_init_pci()\n")); @@ -871,7 +871,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, else ha->oem_id = OEM_ID_ICP; ha->brd_phys = (pdev->bus->number << 8) | (pdev->devfn & 0xf8); - ha->stype = (ulong32)pdev->device; + ha->stype = (u32)pdev->device; ha->irq = pdev->irq; ha->pdev = pdev; @@ -891,7 +891,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, found = FALSE; for (i = 0xC8000; i < 0xE8000; i += 0x4000) { iounmap(ha->brd); - ha->brd = ioremap(i, sizeof(ushort)); + ha->brd = ioremap(i, sizeof(u16)); if (ha->brd == NULL) { printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; @@ -947,7 +947,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, } gdth_delay(1); } - prot_ver = (unchar)readl(&dp6_ptr->u.ic.S_Info[0]); + prot_ver = (u8)readl(&dp6_ptr->u.ic.S_Info[0]); writeb(0, &dp6_ptr->u.ic.S_Status); writeb(0xff, &dp6_ptr->io.irqdel); if (prot_ver != PROTOCOL_VERSION) { @@ -1000,7 +1000,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, found = FALSE; for (i = 0xC8000; i < 0xE8000; i += 0x4000) { iounmap(ha->brd); - ha->brd = ioremap(i, sizeof(ushort)); + ha->brd = ioremap(i, sizeof(u16)); if (ha->brd == NULL) { printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; @@ -1059,7 +1059,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, } gdth_delay(1); } - prot_ver = (unchar)readl(&dp6c_ptr->u.ic.S_Info[0]); + prot_ver = (u8)readl(&dp6c_ptr->u.ic.S_Info[0]); writeb(0, &dp6c_ptr->u.ic.Status); if (prot_ver != PROTOCOL_VERSION) { printk("GDT-PCI: Illegal protocol version\n"); @@ -1128,7 +1128,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, found = FALSE; for (i = 0xC8000; i < 0xE8000; i += 0x4000) { iounmap(ha->brd); - ha->brd = ioremap(i, sizeof(ushort)); + ha->brd = ioremap(i, sizeof(u16)); if (ha->brd == NULL) { printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; @@ -1180,7 +1180,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, } gdth_delay(1); } - prot_ver = (unchar)readl(&dp6m_ptr->u.ic.S_Info[0]); + prot_ver = (u8)readl(&dp6m_ptr->u.ic.S_Info[0]); writeb(0, &dp6m_ptr->u.ic.S_Status); if (prot_ver != PROTOCOL_VERSION) { printk("GDT-PCI: Illegal protocol version\n"); @@ -1223,7 +1223,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, } gdth_delay(1); } - prot_ver = (unchar)(readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16); + prot_ver = (u8)(readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16); writeb(0, &dp6m_ptr->u.ic.S_Status); if (prot_ver < 0x2b) /* FW < x.43: no 64-bit DMA support */ ha->dma64_support = 0; @@ -1239,7 +1239,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, static void __devinit gdth_enable_int(gdth_ha_str *ha) { - ulong flags; + unsigned long flags; gdt2_dpram_str __iomem *dp2_ptr; gdt6_dpram_str __iomem *dp6_ptr; gdt6m_dpram_str __iomem *dp6m_ptr; @@ -1274,14 +1274,14 @@ static void __devinit gdth_enable_int(gdth_ha_str *ha) } /* return IStatus if interrupt was from this card else 0 */ -static unchar gdth_get_status(gdth_ha_str *ha) +static u8 gdth_get_status(gdth_ha_str *ha) { - unchar IStatus = 0; + u8 IStatus = 0; TRACE(("gdth_get_status() irq %d ctr_count %d\n", ha->irq, gdth_ctr_count)); if (ha->type == GDT_EISA) - IStatus = inb((ushort)ha->bmic + EDOORREG); + IStatus = inb((u16)ha->bmic + EDOORREG); else if (ha->type == GDT_ISA) IStatus = readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index); @@ -1329,7 +1329,7 @@ static int gdth_get_cmd_index(gdth_ha_str *ha) if (ha->cmd_tab[i].cmnd == UNUSED_CMND) { ha->cmd_tab[i].cmnd = ha->pccb->RequestBuffer; ha->cmd_tab[i].service = ha->pccb->Service; - ha->pccb->CommandIndex = (ulong32)i+2; + ha->pccb->CommandIndex = (u32)i+2; return (i+2); } } @@ -1362,7 +1362,7 @@ static void gdth_copy_command(gdth_ha_str *ha) register gdt6c_dpram_str __iomem *dp6c_ptr; gdt6_dpram_str __iomem *dp6_ptr; gdt2_dpram_str __iomem *dp2_ptr; - ushort cp_count,dp_offset,cmd_no; + u16 cp_count,dp_offset,cmd_no; TRACE(("gdth_copy_command() hanum %d\n", ha->hanum)); @@ -1386,28 +1386,28 @@ static void gdth_copy_command(gdth_ha_str *ha) dp2_ptr = ha->brd; writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp2_ptr->u.ic.comm_queue[cmd_no].offset); - writew((ushort)cmd_ptr->Service, + writew((u16)cmd_ptr->Service, &dp2_ptr->u.ic.comm_queue[cmd_no].serv_id); memcpy_toio(&dp2_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); } else if (ha->type == GDT_PCI) { dp6_ptr = ha->brd; writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp6_ptr->u.ic.comm_queue[cmd_no].offset); - writew((ushort)cmd_ptr->Service, + writew((u16)cmd_ptr->Service, &dp6_ptr->u.ic.comm_queue[cmd_no].serv_id); memcpy_toio(&dp6_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); } else if (ha->type == GDT_PCINEW) { dp6c_ptr = ha->brd; writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp6c_ptr->u.ic.comm_queue[cmd_no].offset); - writew((ushort)cmd_ptr->Service, + writew((u16)cmd_ptr->Service, &dp6c_ptr->u.ic.comm_queue[cmd_no].serv_id); memcpy_toio(&dp6c_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); } else if (ha->type == GDT_PCIMPR) { dp6m_ptr = ha->brd; writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp6m_ptr->u.ic.comm_queue[cmd_no].offset); - writew((ushort)cmd_ptr->Service, + writew((u16)cmd_ptr->Service, &dp6m_ptr->u.ic.comm_queue[cmd_no].serv_id); memcpy_toio(&dp6m_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); } @@ -1420,14 +1420,14 @@ static void gdth_release_event(gdth_ha_str *ha) #ifdef GDTH_STATISTICS { - ulong32 i,j; + u32 i,j; for (i=0,j=0; jcmd_tab[j].cmnd != UNUSED_CMND) ++i; } if (max_index < i) { max_index = i; - TRACE3(("GDT: max_index = %d\n",(ushort)i)); + TRACE3(("GDT: max_index = %d\n",(u16)i)); } } #endif @@ -1450,7 +1450,7 @@ static void gdth_release_event(gdth_ha_str *ha) } } -static int gdth_wait(gdth_ha_str *ha, int index, ulong32 time) +static int gdth_wait(gdth_ha_str *ha, int index, u32 time) { int answer_found = FALSE; int wait_index = 0; @@ -1476,8 +1476,8 @@ static int gdth_wait(gdth_ha_str *ha, int index, ulong32 time) } -static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode, - ulong32 p1, ulong64 p2, ulong64 p3) +static int gdth_internal_cmd(gdth_ha_str *ha, u8 service, u16 opcode, + u32 p1, u64 p2, u64 p3) { register gdth_cmd_str *cmd_ptr; int retries,index; @@ -1501,35 +1501,35 @@ static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode, if (service == CACHESERVICE) { if (opcode == GDT_IOCTL) { cmd_ptr->u.ioctl.subfunc = p1; - cmd_ptr->u.ioctl.channel = (ulong32)p2; - cmd_ptr->u.ioctl.param_size = (ushort)p3; + cmd_ptr->u.ioctl.channel = (u32)p2; + cmd_ptr->u.ioctl.param_size = (u16)p3; cmd_ptr->u.ioctl.p_param = ha->scratch_phys; } else { if (ha->cache_feat & GDT_64BIT) { - cmd_ptr->u.cache64.DeviceNo = (ushort)p1; + cmd_ptr->u.cache64.DeviceNo = (u16)p1; cmd_ptr->u.cache64.BlockNo = p2; } else { - cmd_ptr->u.cache.DeviceNo = (ushort)p1; - cmd_ptr->u.cache.BlockNo = (ulong32)p2; + cmd_ptr->u.cache.DeviceNo = (u16)p1; + cmd_ptr->u.cache.BlockNo = (u32)p2; } } } else if (service == SCSIRAWSERVICE) { if (ha->raw_feat & GDT_64BIT) { cmd_ptr->u.raw64.direction = p1; - cmd_ptr->u.raw64.bus = (unchar)p2; - cmd_ptr->u.raw64.target = (unchar)p3; - cmd_ptr->u.raw64.lun = (unchar)(p3 >> 8); + cmd_ptr->u.raw64.bus = (u8)p2; + cmd_ptr->u.raw64.target = (u8)p3; + cmd_ptr->u.raw64.lun = (u8)(p3 >> 8); } else { cmd_ptr->u.raw.direction = p1; - cmd_ptr->u.raw.bus = (unchar)p2; - cmd_ptr->u.raw.target = (unchar)p3; - cmd_ptr->u.raw.lun = (unchar)(p3 >> 8); + cmd_ptr->u.raw.bus = (u8)p2; + cmd_ptr->u.raw.target = (u8)p3; + cmd_ptr->u.raw.lun = (u8)(p3 >> 8); } } else if (service == SCREENSERVICE) { if (opcode == GDT_REALTIME) { - *(ulong32 *)&cmd_ptr->u.screen.su.data[0] = p1; - *(ulong32 *)&cmd_ptr->u.screen.su.data[4] = (ulong32)p2; - *(ulong32 *)&cmd_ptr->u.screen.su.data[8] = (ulong32)p3; + *(u32 *)&cmd_ptr->u.screen.su.data[0] = p1; + *(u32 *)&cmd_ptr->u.screen.su.data[4] = (u32)p2; + *(u32 *)&cmd_ptr->u.screen.su.data[8] = (u32)p3; } } ha->cmd_len = sizeof(gdth_cmd_str); @@ -1555,9 +1555,9 @@ static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode, static int __devinit gdth_search_drives(gdth_ha_str *ha) { - ushort cdev_cnt, i; + u16 cdev_cnt, i; int ok; - ulong32 bus_no, drv_cnt, drv_no, j; + u32 bus_no, drv_cnt, drv_no, j; gdth_getch_str *chn; gdth_drlist_str *drl; gdth_iochan_str *ioc; @@ -1570,8 +1570,8 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) #endif #ifdef GDTH_RTC - unchar rtc[12]; - ulong flags; + u8 rtc[12]; + unsigned long flags; #endif TRACE(("gdth_search_drives() hanum %d\n", ha->hanum)); @@ -1584,7 +1584,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) if (ok) ha->screen_feat = GDT_64BIT; } - if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC)) + if (force_dma32 || (!ok && ha->status == (u16)S_NOFUNC)) ok = gdth_internal_cmd(ha, SCREENSERVICE, GDT_INIT, 0, 0, 0); if (!ok) { printk("GDT-HA %d: Initialization error screen service (code %d)\n", @@ -1609,11 +1609,11 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) rtc[j] = CMOS_READ(j); } while (rtc[0] != CMOS_READ(0)); spin_unlock_irqrestore(&rtc_lock, flags); - TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(ulong32 *)&rtc[0], - *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8])); + TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(u32 *)&rtc[0], + *(u32 *)&rtc[4], *(u32 *)&rtc[8])); /* 3. send to controller firmware */ - gdth_internal_cmd(ha, SCREENSERVICE, GDT_REALTIME, *(ulong32 *)&rtc[0], - *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]); + gdth_internal_cmd(ha, SCREENSERVICE, GDT_REALTIME, *(u32 *)&rtc[0], + *(u32 *)&rtc[4], *(u32 *)&rtc[8]); #endif /* unfreeze all IOs */ @@ -1627,7 +1627,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) if (ok) ha->cache_feat = GDT_64BIT; } - if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC)) + if (force_dma32 || (!ok && ha->status == (u16)S_NOFUNC)) ok = gdth_internal_cmd(ha, CACHESERVICE, GDT_INIT, LINUX_OS, 0, 0); if (!ok) { printk("GDT-HA %d: Initialization error cache service (code %d)\n", @@ -1635,7 +1635,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) return 0; } TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n")); - cdev_cnt = (ushort)ha->info; + cdev_cnt = (u16)ha->info; ha->fw_vers = ha->service; #ifdef INT_COAL @@ -1644,7 +1644,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) pmod = (gdth_perf_modes *)ha->pscratch; pmod->version = 1; pmod->st_mode = 1; /* enable one status buffer */ - *((ulong64 *)&pmod->st_buff_addr1) = ha->coal_stat_phys; + *((u64 *)&pmod->st_buff_addr1) = ha->coal_stat_phys; pmod->st_buff_indx1 = COALINDEX; pmod->st_buff_addr2 = 0; pmod->st_buff_u_addr2 = 0; @@ -1705,7 +1705,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) else ha->bus_id[bus_no] = 0xff; } - ha->bus_cnt = (unchar)bus_no; + ha->bus_cnt = (u8)bus_no; } TRACE2(("gdth_search_drives() %d channels\n",ha->bus_cnt)); @@ -1789,12 +1789,12 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) /* logical drives */ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_DRV_CNT, - INVALID_CHANNEL,sizeof(ulong32))) { - drv_cnt = *(ulong32 *)ha->pscratch; + INVALID_CHANNEL,sizeof(u32))) { + drv_cnt = *(u32 *)ha->pscratch; if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_DRV_LIST, - INVALID_CHANNEL,drv_cnt * sizeof(ulong32))) { + INVALID_CHANNEL,drv_cnt * sizeof(u32))) { for (j = 0; j < drv_cnt; ++j) { - drv_no = ((ulong32 *)ha->pscratch)[j]; + drv_no = ((u32 *)ha->pscratch)[j]; if (drv_no < MAX_LDRIVES) { ha->hdr[drv_no].is_logdrv = TRUE; TRACE2(("Drive %d is log. drive\n",drv_no)); @@ -1838,7 +1838,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) if (ok) ha->raw_feat = GDT_64BIT; } - if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC)) + if (force_dma32 || (!ok && ha->status == (u16)S_NOFUNC)) ok = gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_INIT, 0, 0, 0); if (!ok) { printk("GDT-HA %d: Initialization error raw service (code %d)\n", @@ -1854,7 +1854,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) if (gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_GET_FEAT, 0, 0, 0)) { TRACE2(("gdth_search_dr(): get feat RAWSERVICE %d\n", ha->info)); - ha->raw_feat |= (ushort)ha->info; + ha->raw_feat |= (u16)ha->info; } } @@ -1865,7 +1865,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) if (gdth_internal_cmd(ha, CACHESERVICE, GDT_GET_FEAT, 0, 0, 0)) { TRACE2(("gdth_search_dr(): get feat CACHESERV. %d\n", ha->info)); - ha->cache_feat |= (ushort)ha->info; + ha->cache_feat |= (u16)ha->info; } } @@ -1923,9 +1923,9 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) return 1; } -static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive) +static int gdth_analyse_hdrive(gdth_ha_str *ha, u16 hdrive) { - ulong32 drv_cyls; + u32 drv_cyls; int drv_hds, drv_secs; TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n", ha->hanum, hdrive)); @@ -1944,17 +1944,17 @@ static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive) } else { drv_hds = ha->info2 & 0xff; drv_secs = (ha->info2 >> 8) & 0xff; - drv_cyls = (ulong32)ha->hdr[hdrive].size / drv_hds / drv_secs; + drv_cyls = (u32)ha->hdr[hdrive].size / drv_hds / drv_secs; } - ha->hdr[hdrive].heads = (unchar)drv_hds; - ha->hdr[hdrive].secs = (unchar)drv_secs; + ha->hdr[hdrive].heads = (u8)drv_hds; + ha->hdr[hdrive].secs = (u8)drv_secs; /* round size */ ha->hdr[hdrive].size = drv_cyls * drv_hds * drv_secs; if (ha->cache_feat & GDT_64BIT) { if (gdth_internal_cmd(ha, CACHESERVICE, GDT_X_INFO, hdrive, 0, 0) && ha->info2 != 0) { - ha->hdr[hdrive].size = ((ulong64)ha->info2 << 32) | ha->info; + ha->hdr[hdrive].size = ((u64)ha->info2 << 32) | ha->info; } } TRACE2(("gdth_search_dr() cdr. %d size %d hds %d scs %d\n", @@ -1964,7 +1964,7 @@ static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive) if (gdth_internal_cmd(ha, CACHESERVICE, GDT_DEVTYPE, hdrive, 0, 0)) { TRACE2(("gdth_search_dr() cache drive %d devtype %d\n", hdrive,ha->info)); - ha->hdr[hdrive].devtype = (ushort)ha->info; + ha->hdr[hdrive].devtype = (u16)ha->info; } /* cluster info */ @@ -1972,14 +1972,14 @@ static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive) TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n", hdrive,ha->info)); if (!shared_access) - ha->hdr[hdrive].cluster_type = (unchar)ha->info; + ha->hdr[hdrive].cluster_type = (u8)ha->info; } /* R/W attributes */ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_RW_ATTRIBS, hdrive, 0, 0)) { TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n", hdrive,ha->info)); - ha->hdr[hdrive].rw_attribs = (unchar)ha->info; + ha->hdr[hdrive].rw_attribs = (u8)ha->info; } return 1; @@ -1988,12 +1988,12 @@ static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive) /* command queueing/sending functions */ -static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar priority) +static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, u8 priority) { struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); register Scsi_Cmnd *pscp; register Scsi_Cmnd *nscp; - ulong flags; + unsigned long flags; TRACE(("gdth_putq() priority %d\n",priority)); spin_lock_irqsave(&ha->smp_lock, flags); @@ -2023,7 +2023,7 @@ static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar priority) ++flags; if (max_rq < flags) { max_rq = flags; - TRACE3(("GDT: max_rq = %d\n",(ushort)max_rq)); + TRACE3(("GDT: max_rq = %d\n",(u16)max_rq)); } #endif } @@ -2032,9 +2032,9 @@ static void gdth_next(gdth_ha_str *ha) { register Scsi_Cmnd *pscp; register Scsi_Cmnd *nscp; - unchar b, t, l, firsttime; - unchar this_cmd, next_cmd; - ulong flags = 0; + u8 b, t, l, firsttime; + u8 this_cmd, next_cmd; + unsigned long flags = 0; int cmd_index; TRACE(("gdth_next() hanum %d\n", ha->hanum)); @@ -2282,20 +2282,20 @@ static void gdth_next(gdth_ha_str *ha) * buffers, kmap_atomic() as needed. */ static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, - char *buffer, ushort count) + char *buffer, u16 count) { - ushort cpcount,i, max_sg = scsi_sg_count(scp); - ushort cpsum,cpnow; + u16 cpcount,i, max_sg = scsi_sg_count(scp); + u16 cpsum,cpnow; struct scatterlist *sl; char *address; - cpcount = min_t(ushort, count, scsi_bufflen(scp)); + cpcount = min_t(u16, count, scsi_bufflen(scp)); if (cpcount) { cpsum=0; scsi_for_each_sg(scp, sl, max_sg, i) { unsigned long flags; - cpnow = (ushort)sl->length; + cpnow = (u16)sl->length; TRACE(("copy_internal() now %d sum %d count %d %d\n", cpnow, cpsum, cpcount, scsi_bufflen(scp))); if (cpsum+cpnow > cpcount) @@ -2325,7 +2325,7 @@ static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) { - unchar t; + u8 t; gdth_inq_data inq; gdth_rdcap_data rdc; gdth_sense_data sd; @@ -2389,7 +2389,7 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) case READ_CAPACITY: TRACE2(("Read capacity hdrive %d\n",t)); - if (ha->hdr[t].size > (ulong64)0xffffffff) + if (ha->hdr[t].size > (u64)0xffffffff) rdc.last_block_no = 0xffffffff; else rdc.last_block_no = cpu_to_be32(ha->hdr[t].size-1); @@ -2425,12 +2425,12 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) return 0; } -static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive) +static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, u16 hdrive) { register gdth_cmd_str *cmdp; struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); - ulong32 cnt, blockcnt; - ulong64 no, blockno; + u32 cnt, blockcnt; + u64 no, blockno; int i, cmd_index, read_write, sgcnt, mode64; cmdp = ha->pccb; @@ -2498,17 +2498,17 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive) if (read_write) { if (scp->cmd_len == 16) { - memcpy(&no, &scp->cmnd[2], sizeof(ulong64)); + memcpy(&no, &scp->cmnd[2], sizeof(u64)); blockno = be64_to_cpu(no); - memcpy(&cnt, &scp->cmnd[10], sizeof(ulong32)); + memcpy(&cnt, &scp->cmnd[10], sizeof(u32)); blockcnt = be32_to_cpu(cnt); } else if (scp->cmd_len == 10) { - memcpy(&no, &scp->cmnd[2], sizeof(ulong32)); + memcpy(&no, &scp->cmnd[2], sizeof(u32)); blockno = be32_to_cpu(no); - memcpy(&cnt, &scp->cmnd[7], sizeof(ushort)); + memcpy(&cnt, &scp->cmnd[7], sizeof(u16)); blockcnt = be16_to_cpu(cnt); } else { - memcpy(&no, &scp->cmnd[0], sizeof(ulong32)); + memcpy(&no, &scp->cmnd[0], sizeof(u32)); blockno = be32_to_cpu(no) & 0x001fffffUL; blockcnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4]; } @@ -2516,7 +2516,7 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive) cmdp->u.cache64.BlockNo = blockno; cmdp->u.cache64.BlockCnt = blockcnt; } else { - cmdp->u.cache.BlockNo = (ulong32)blockno; + cmdp->u.cache.BlockNo = (u32)blockno; cmdp->u.cache.BlockCnt = blockcnt; } @@ -2528,12 +2528,12 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive) if (mode64) { struct scatterlist *sl; - cmdp->u.cache64.DestAddr= (ulong64)-1; + cmdp->u.cache64.DestAddr= (u64)-1; cmdp->u.cache64.sg_canz = sgcnt; scsi_for_each_sg(scp, sl, sgcnt, i) { cmdp->u.cache64.sg_lst[i].sg_ptr = sg_dma_address(sl); #ifdef GDTH_DMA_STATISTICS - if (cmdp->u.cache64.sg_lst[i].sg_ptr > (ulong64)0xffffffff) + if (cmdp->u.cache64.sg_lst[i].sg_ptr > (u64)0xffffffff) ha->dma64_cnt++; else ha->dma32_cnt++; @@ -2555,8 +2555,8 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive) } #ifdef GDTH_STATISTICS - if (max_sg < (ulong32)sgcnt) { - max_sg = (ulong32)sgcnt; + if (max_sg < (u32)sgcnt) { + max_sg = (u32)sgcnt; TRACE3(("GDT: max_sg = %d\n",max_sg)); } #endif @@ -2572,7 +2572,7 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive) TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n", cmdp->OpCode,cmdp->u.cache64.BlockNo,cmdp->u.cache64.BlockCnt)); ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache64.sg_lst) + - (ushort)cmdp->u.cache64.sg_canz * sizeof(gdth_sg64_str); + (u16)cmdp->u.cache64.sg_canz * sizeof(gdth_sg64_str); } else { TRACE(("cache cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n", cmdp->u.cache.DestAddr,cmdp->u.cache.sg_canz, @@ -2581,7 +2581,7 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive) TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n", cmdp->OpCode,cmdp->u.cache.BlockNo,cmdp->u.cache.BlockCnt)); ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) + - (ushort)cmdp->u.cache.sg_canz * sizeof(gdth_sg_str); + (u16)cmdp->u.cache.sg_canz * sizeof(gdth_sg_str); } if (ha->cmd_len & 3) ha->cmd_len += (4 - (ha->cmd_len & 3)); @@ -2600,15 +2600,15 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive) return cmd_index; } -static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b) +static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, u8 b) { register gdth_cmd_str *cmdp; - ushort i; + u16 i; dma_addr_t sense_paddr; int cmd_index, sgcnt, mode64; - unchar t,l; + u8 t,l; struct page *page; - ulong offset; + unsigned long offset; struct gdth_cmndinfo *cmndinfo; t = scp->device->id; @@ -2654,7 +2654,7 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b) } else { page = virt_to_page(scp->sense_buffer); - offset = (ulong)scp->sense_buffer & ~PAGE_MASK; + offset = (unsigned long)scp->sense_buffer & ~PAGE_MASK; sense_paddr = pci_map_page(ha->pdev,page,offset, 16,PCI_DMA_FROMDEVICE); @@ -2703,12 +2703,12 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b) if (mode64) { struct scatterlist *sl; - cmdp->u.raw64.sdata = (ulong64)-1; + cmdp->u.raw64.sdata = (u64)-1; cmdp->u.raw64.sg_ranz = sgcnt; scsi_for_each_sg(scp, sl, sgcnt, i) { cmdp->u.raw64.sg_lst[i].sg_ptr = sg_dma_address(sl); #ifdef GDTH_DMA_STATISTICS - if (cmdp->u.raw64.sg_lst[i].sg_ptr > (ulong64)0xffffffff) + if (cmdp->u.raw64.sg_lst[i].sg_ptr > (u64)0xffffffff) ha->dma64_cnt++; else ha->dma32_cnt++; @@ -2744,7 +2744,7 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b) cmdp->u.raw64.sg_lst[0].sg_len)); /* evaluate command size */ ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst) + - (ushort)cmdp->u.raw64.sg_ranz * sizeof(gdth_sg64_str); + (u16)cmdp->u.raw64.sg_ranz * sizeof(gdth_sg64_str); } else { TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n", cmdp->u.raw.sdata,cmdp->u.raw.sg_ranz, @@ -2752,7 +2752,7 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b) cmdp->u.raw.sg_lst[0].sg_len)); /* evaluate command size */ ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) + - (ushort)cmdp->u.raw.sg_ranz * sizeof(gdth_sg_str); + (u16)cmdp->u.raw.sg_ranz * sizeof(gdth_sg_str); } } /* check space */ @@ -2802,7 +2802,7 @@ static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) if (cmdp->OpCode == GDT_IOCTL) { TRACE2(("IOCTL\n")); ha->cmd_len = - GDTOFFSOF(gdth_cmd_str,u.ioctl.p_param) + sizeof(ulong64); + GDTOFFSOF(gdth_cmd_str,u.ioctl.p_param) + sizeof(u64); } else if (cmdp->Service == CACHESERVICE) { TRACE2(("cache command %d\n",cmdp->OpCode)); if (ha->cache_feat & GDT_64BIT) @@ -2840,8 +2840,8 @@ static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) /* Controller event handling functions */ -static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, ushort source, - ushort idx, gdth_evt_data *evt) +static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, u16 source, + u16 idx, gdth_evt_data *evt) { gdth_evt_str *e; struct timeval tv; @@ -2890,7 +2890,7 @@ static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr) { gdth_evt_str *e; int eindex; - ulong flags; + unsigned long flags; TRACE2(("gdth_read_event() handle %d\n", handle)); spin_lock_irqsave(&ha->smp_lock, flags); @@ -2919,12 +2919,12 @@ static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr) } static void gdth_readapp_event(gdth_ha_str *ha, - unchar application, gdth_evt_str *estr) + u8 application, gdth_evt_str *estr) { gdth_evt_str *e; int eindex; - ulong flags; - unchar found = FALSE; + unsigned long flags; + u8 found = FALSE; TRACE2(("gdth_readapp_event() app. %d\n", application)); spin_lock_irqsave(&ha->smp_lock, flags); @@ -2969,9 +2969,9 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, gdt2_dpram_str __iomem *dp2_ptr; Scsi_Cmnd *scp; int rval, i; - unchar IStatus; - ushort Service; - ulong flags = 0; + u8 IStatus; + u16 Service; + unsigned long flags = 0; #ifdef INT_COAL int coalesced = FALSE; int next = FALSE; @@ -3018,7 +3018,7 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, if (coalesced) { /* For coalesced requests all status information is found in the status buffer */ - IStatus = (unchar)(pcs->status & 0xff); + IStatus = (u8)(pcs->status & 0xff); } #endif @@ -3197,7 +3197,7 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, ++act_int_coal; if (act_int_coal > max_int_coal) { max_int_coal = act_int_coal; - printk("GDT: max_int_coal = %d\n",(ushort)max_int_coal); + printk("GDT: max_int_coal = %d\n",(u16)max_int_coal); } #endif /* see if there is another status */ @@ -3225,12 +3225,12 @@ static irqreturn_t gdth_interrupt(int irq, void *dev_id) return __gdth_interrupt(ha, false, NULL); } -static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index, +static int gdth_sync_event(gdth_ha_str *ha, int service, u8 index, Scsi_Cmnd *scp) { gdth_msg_str *msg; gdth_cmd_str *cmdp; - unchar b, t; + u8 b, t; struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); cmdp = ha->pccb; @@ -3263,7 +3263,7 @@ static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index, cmdp->u.screen.su.msg.msg_addr = ha->msg_phys; ha->cmd_offs_dpmem = 0; ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) - + sizeof(ulong64); + + sizeof(u64); ha->cmd_cnt = 0; gdth_copy_command(ha); gdth_release_event(ha); @@ -3297,7 +3297,7 @@ static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index, cmdp->u.screen.su.msg.msg_addr = ha->msg_phys; ha->cmd_offs_dpmem = 0; ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) - + sizeof(ulong64); + + sizeof(u64); ha->cmd_cnt = 0; gdth_copy_command(ha); gdth_release_event(ha); @@ -3335,7 +3335,7 @@ static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index, cmndinfo->OpCode)); /* special commands GDT_CLUST_INFO/GDT_MOUNT ? */ if (cmndinfo->OpCode == GDT_CLUST_INFO) { - ha->hdr[t].cluster_type = (unchar)ha->info; + ha->hdr[t].cluster_type = (u8)ha->info; if (!(ha->hdr[t].cluster_type & CLUSTER_MOUNTED)) { /* NOT MOUNTED -> MOUNT */ @@ -3397,7 +3397,7 @@ static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index, ha->hdr[t].cluster_type &= ~CLUSTER_RESERVED; } memset((char*)scp->sense_buffer,0,16); - if (ha->status == (ushort)S_CACHE_RESERV) { + if (ha->status == (u16)S_CACHE_RESERV) { scp->result = (DID_OK << 16) | (RESERVATION_CONFLICT << 1); } else { scp->sense_buffer[0] = 0x70; @@ -3614,16 +3614,16 @@ static int gdth_async_event(gdth_ha_str *ha) cmdp->u.screen.su.msg.msg_addr = ha->msg_phys; ha->cmd_offs_dpmem = 0; ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) - + sizeof(ulong64); + + sizeof(u64); ha->cmd_cnt = 0; gdth_copy_command(ha); if (ha->type == GDT_EISA) - printk("[EISA slot %d] ",(ushort)ha->brd_phys); + printk("[EISA slot %d] ",(u16)ha->brd_phys); else if (ha->type == GDT_ISA) - printk("[DPMEM 0x%4X] ",(ushort)ha->brd_phys); + printk("[DPMEM 0x%4X] ",(u16)ha->brd_phys); else - printk("[PCI %d/%d] ",(ushort)(ha->brd_phys>>8), - (ushort)((ha->brd_phys>>3)&0x1f)); + printk("[PCI %d/%d] ",(u16)(ha->brd_phys>>8), + (u16)((ha->brd_phys>>3)&0x1f)); gdth_release_event(ha); } @@ -3640,7 +3640,7 @@ static int gdth_async_event(gdth_ha_str *ha) ha->dvr.eu.async.service = ha->service; ha->dvr.eu.async.status = ha->status; ha->dvr.eu.async.info = ha->info; - *(ulong32 *)ha->dvr.eu.async.scsi_coord = ha->info2; + *(u32 *)ha->dvr.eu.async.scsi_coord = ha->info2; } gdth_store_event( ha, ES_ASYNC, ha->service, &ha->dvr ); gdth_log_event( &ha->dvr, NULL ); @@ -3648,8 +3648,8 @@ static int gdth_async_event(gdth_ha_str *ha) /* new host drive from expand? */ if (ha->service == CACHESERVICE && ha->status == 56) { TRACE2(("gdth_async_event(): new host drive %d created\n", - (ushort)ha->info)); - /* gdth_analyse_hdrive(hanum, (ushort)ha->info); */ + (u16)ha->info)); + /* gdth_analyse_hdrive(hanum, (u16)ha->info); */ } } return 1; @@ -3680,13 +3680,13 @@ static void gdth_log_event(gdth_evt_data *dvr, char *buffer) for (j=0,i=1; i < f[0]; i+=2) { switch (f[i+1]) { case 4: - stack.b[j++] = *(ulong32*)&dvr->eu.stream[(int)f[i]]; + stack.b[j++] = *(u32*)&dvr->eu.stream[(int)f[i]]; break; case 2: - stack.b[j++] = *(ushort*)&dvr->eu.stream[(int)f[i]]; + stack.b[j++] = *(u16*)&dvr->eu.stream[(int)f[i]]; break; case 1: - stack.b[j++] = *(unchar*)&dvr->eu.stream[(int)f[i]]; + stack.b[j++] = *(u8*)&dvr->eu.stream[(int)f[i]]; break; default: break; @@ -3712,14 +3712,14 @@ static void gdth_log_event(gdth_evt_data *dvr, char *buffer) } #ifdef GDTH_STATISTICS -static unchar gdth_timer_running; +static u8 gdth_timer_running; -static void gdth_timeout(ulong data) +static void gdth_timeout(unsigned long data) { - ulong32 i; + u32 i; Scsi_Cmnd *nscp; gdth_ha_str *ha; - ulong flags; + unsigned long flags; if(unlikely(list_empty(&gdth_instances))) { gdth_timer_running = 0; @@ -3891,8 +3891,8 @@ static enum blk_eh_timer_return gdth_timed_out(struct scsi_cmnd *scp) { gdth_ha_str *ha = shost_priv(scp->device->host); struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); - unchar b, t; - ulong flags; + u8 b, t; + unsigned long flags; enum blk_eh_timer_return retval = BLK_EH_NOT_HANDLED; TRACE(("%s() cmd 0x%x\n", scp->cmnd[0], __func__)); @@ -3924,9 +3924,9 @@ static int gdth_eh_bus_reset(Scsi_Cmnd *scp) { gdth_ha_str *ha = shost_priv(scp->device->host); int i; - ulong flags; + unsigned long flags; Scsi_Cmnd *cmnd; - unchar b; + u8 b; TRACE2(("gdth_eh_bus_reset()\n")); @@ -3974,7 +3974,7 @@ static int gdth_eh_bus_reset(Scsi_Cmnd *scp) static int gdth_bios_param(struct scsi_device *sdev,struct block_device *bdev,sector_t cap,int *ip) { - unchar b, t; + u8 b, t; gdth_ha_str *ha = shost_priv(sdev->host); struct scsi_device *sd; unsigned capacity; @@ -4062,7 +4062,7 @@ static int ioc_event(void __user *arg) { gdth_ioctl_event evt; gdth_ha_str *ha; - ulong flags; + unsigned long flags; if (copy_from_user(&evt, arg, sizeof(gdth_ioctl_event))) return -EFAULT; @@ -4098,8 +4098,8 @@ static int ioc_event(void __user *arg) static int ioc_lockdrv(void __user *arg) { gdth_ioctl_lockdrv ldrv; - unchar i, j; - ulong flags; + u8 i, j; + unsigned long flags; gdth_ha_str *ha; if (copy_from_user(&ldrv, arg, sizeof(gdth_ioctl_lockdrv))) @@ -4165,7 +4165,7 @@ static int ioc_general(void __user *arg, char *cmnd) { gdth_ioctl_general gen; char *buf = NULL; - ulong64 paddr; + u64 paddr; gdth_ha_str *ha; int rval; @@ -4194,7 +4194,7 @@ static int ioc_general(void __user *arg, char *cmnd) gen.command.u.cache64.DeviceNo = gen.command.u.cache.DeviceNo; /* addresses */ if (ha->cache_feat & SCATTER_GATHER) { - gen.command.u.cache64.DestAddr = (ulong64)-1; + gen.command.u.cache64.DestAddr = (u64)-1; gen.command.u.cache64.sg_canz = 1; gen.command.u.cache64.sg_lst[0].sg_ptr = paddr; gen.command.u.cache64.sg_lst[0].sg_len = gen.data_len; @@ -4207,7 +4207,7 @@ static int ioc_general(void __user *arg, char *cmnd) if (ha->cache_feat & SCATTER_GATHER) { gen.command.u.cache.DestAddr = 0xffffffff; gen.command.u.cache.sg_canz = 1; - gen.command.u.cache.sg_lst[0].sg_ptr = (ulong32)paddr; + gen.command.u.cache.sg_lst[0].sg_ptr = (u32)paddr; gen.command.u.cache.sg_lst[0].sg_len = gen.data_len; gen.command.u.cache.sg_lst[1].sg_len = 0; } else { @@ -4230,7 +4230,7 @@ static int ioc_general(void __user *arg, char *cmnd) gen.command.u.raw64.direction = gen.command.u.raw.direction; /* addresses */ if (ha->raw_feat & SCATTER_GATHER) { - gen.command.u.raw64.sdata = (ulong64)-1; + gen.command.u.raw64.sdata = (u64)-1; gen.command.u.raw64.sg_ranz = 1; gen.command.u.raw64.sg_lst[0].sg_ptr = paddr; gen.command.u.raw64.sg_lst[0].sg_len = gen.data_len; @@ -4244,14 +4244,14 @@ static int ioc_general(void __user *arg, char *cmnd) if (ha->raw_feat & SCATTER_GATHER) { gen.command.u.raw.sdata = 0xffffffff; gen.command.u.raw.sg_ranz = 1; - gen.command.u.raw.sg_lst[0].sg_ptr = (ulong32)paddr; + gen.command.u.raw.sg_lst[0].sg_ptr = (u32)paddr; gen.command.u.raw.sg_lst[0].sg_len = gen.data_len; gen.command.u.raw.sg_lst[1].sg_len = 0; } else { gen.command.u.raw.sdata = paddr; gen.command.u.raw.sg_ranz = 0; } - gen.command.u.raw.sense_data = (ulong32)paddr + gen.data_len; + gen.command.u.raw.sense_data = (u32)paddr + gen.data_len; } } else { gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); @@ -4283,7 +4283,7 @@ static int ioc_hdrlist(void __user *arg, char *cmnd) gdth_ioctl_rescan *rsc; gdth_cmd_str *cmd; gdth_ha_str *ha; - unchar i; + u8 i; int rc = -ENOMEM; u32 cluster_type = 0; @@ -4335,11 +4335,11 @@ static int ioc_rescan(void __user *arg, char *cmnd) { gdth_ioctl_rescan *rsc; gdth_cmd_str *cmd; - ushort i, status, hdr_cnt; - ulong32 info; + u16 i, status, hdr_cnt; + u32 info; int cyls, hds, secs; int rc = -ENOMEM; - ulong flags; + unsigned long flags; gdth_ha_str *ha; rsc = kmalloc(sizeof(*rsc), GFP_KERNEL); @@ -4367,7 +4367,7 @@ static int ioc_rescan(void __user *arg, char *cmnd) status = __gdth_execute(ha->sdev, cmd, cmnd, 30, &info); i = 0; - hdr_cnt = (status == S_OK ? (ushort)info : 0); + hdr_cnt = (status == S_OK ? (u16)info : 0); } else { i = rsc->hdr_no; hdr_cnt = i + 1; @@ -4418,7 +4418,7 @@ static int ioc_rescan(void __user *arg, char *cmnd) status = __gdth_execute(ha->sdev, cmd, cmnd, 30, &info); spin_lock_irqsave(&ha->smp_lock, flags); - ha->hdr[i].devtype = (status == S_OK ? (ushort)info : 0); + ha->hdr[i].devtype = (status == S_OK ? (u16)info : 0); spin_unlock_irqrestore(&ha->smp_lock, flags); cmd->Service = CACHESERVICE; @@ -4432,7 +4432,7 @@ static int ioc_rescan(void __user *arg, char *cmnd) spin_lock_irqsave(&ha->smp_lock, flags); ha->hdr[i].cluster_type = - ((status == S_OK && !shared_access) ? (ushort)info : 0); + ((status == S_OK && !shared_access) ? (u16)info : 0); spin_unlock_irqrestore(&ha->smp_lock, flags); rsc->hdr_list[i].cluster_type = ha->hdr[i].cluster_type; @@ -4446,7 +4446,7 @@ static int ioc_rescan(void __user *arg, char *cmnd) status = __gdth_execute(ha->sdev, cmd, cmnd, 30, &info); spin_lock_irqsave(&ha->smp_lock, flags); - ha->hdr[i].rw_attribs = (status == S_OK ? (ushort)info : 0); + ha->hdr[i].rw_attribs = (status == S_OK ? (u16)info : 0); spin_unlock_irqrestore(&ha->smp_lock, flags); } @@ -4466,7 +4466,7 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, { gdth_ha_str *ha; Scsi_Cmnd *scp; - ulong flags; + unsigned long flags; char cmnd[MAX_COMMAND_SIZE]; void __user *argp = (void __user *)arg; @@ -4495,9 +4495,9 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, { gdth_ioctl_osvers osv; - osv.version = (unchar)(LINUX_VERSION_CODE >> 16); - osv.subversion = (unchar)(LINUX_VERSION_CODE >> 8); - osv.revision = (ushort)(LINUX_VERSION_CODE & 0xff); + osv.version = (u8)(LINUX_VERSION_CODE >> 16); + osv.subversion = (u8)(LINUX_VERSION_CODE >> 8); + osv.revision = (u16)(LINUX_VERSION_CODE & 0xff); if (copy_to_user(argp, &osv, sizeof(gdth_ioctl_osvers))) return -EFAULT; break; @@ -4512,10 +4512,10 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, return -EFAULT; if (ha->type == GDT_ISA || ha->type == GDT_EISA) { - ctrt.type = (unchar)((ha->stype>>20) - 0x10); + ctrt.type = (u8)((ha->stype>>20) - 0x10); } else { if (ha->type != GDT_PCIMPR) { - ctrt.type = (unchar)((ha->stype<<4) + 6); + ctrt.type = (u8)((ha->stype<<4) + 6); } else { ctrt.type = (ha->oem_id == OEM_ID_INTEL ? 0xfd : 0xfe); @@ -4546,7 +4546,7 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, case GDTIOCTL_LOCKCHN: { gdth_ioctl_lockchn lchn; - unchar i, j; + u8 i, j; if (copy_from_user(&lchn, argp, sizeof(gdth_ioctl_lockchn)) || (NULL == (ha = gdth_find_ha(lchn.ionode)))) @@ -4670,7 +4670,7 @@ static struct scsi_host_template gdth_template = { }; #ifdef CONFIG_ISA -static int __init gdth_isa_probe_one(ulong32 isa_bios) +static int __init gdth_isa_probe_one(u32 isa_bios) { struct Scsi_Host *shp; gdth_ha_str *ha; @@ -4802,7 +4802,7 @@ static int __init gdth_isa_probe_one(ulong32 isa_bios) #endif /* CONFIG_ISA */ #ifdef CONFIG_EISA -static int __init gdth_eisa_probe_one(ushort eisa_slot) +static int __init gdth_eisa_probe_one(u16 eisa_slot) { struct Scsi_Host *shp; gdth_ha_str *ha; @@ -5120,7 +5120,7 @@ static void gdth_remove_one(gdth_ha_str *ha) scsi_host_put(shp); } -static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) +static int gdth_halt(struct notifier_block *nb, unsigned long event, void *buf) { gdth_ha_str *ha; @@ -5158,14 +5158,14 @@ static int __init gdth_init(void) if (probe_eisa_isa) { /* scanning for controllers, at first: ISA controller */ #ifdef CONFIG_ISA - ulong32 isa_bios; + u32 isa_bios; for (isa_bios = 0xc8000UL; isa_bios <= 0xd8000UL; isa_bios += 0x8000UL) gdth_isa_probe_one(isa_bios); #endif #ifdef CONFIG_EISA { - ushort eisa_slot; + u16 eisa_slot; for (eisa_slot = 0x1000; eisa_slot <= 0x8000; eisa_slot += 0x1000) gdth_eisa_probe_one(eisa_slot); diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h index 1646444e9bd5..120a0625a7b5 100644 --- a/drivers/scsi/gdth.h +++ b/drivers/scsi/gdth.h @@ -321,524 +321,524 @@ /* screenservice message */ typedef struct { - ulong32 msg_handle; /* message handle */ - ulong32 msg_len; /* size of message */ - ulong32 msg_alen; /* answer length */ - unchar msg_answer; /* answer flag */ - unchar msg_ext; /* more messages */ - unchar msg_reserved[2]; + u32 msg_handle; /* message handle */ + u32 msg_len; /* size of message */ + u32 msg_alen; /* answer length */ + u8 msg_answer; /* answer flag */ + u8 msg_ext; /* more messages */ + u8 msg_reserved[2]; char msg_text[MSGLEN+2]; /* the message text */ -} PACKED gdth_msg_str; +} __attribute__((packed)) gdth_msg_str; /* IOCTL data structures */ /* Status coalescing buffer for returning multiple requests per interrupt */ typedef struct { - ulong32 status; - ulong32 ext_status; - ulong32 info0; - ulong32 info1; -} PACKED gdth_coal_status; + u32 status; + u32 ext_status; + u32 info0; + u32 info1; +} __attribute__((packed)) gdth_coal_status; /* performance mode data structure */ typedef struct { - ulong32 version; /* The version of this IOCTL structure. */ - ulong32 st_mode; /* 0=dis., 1=st_buf_addr1 valid, 2=both */ - ulong32 st_buff_addr1; /* physical address of status buffer 1 */ - ulong32 st_buff_u_addr1; /* reserved for 64 bit addressing */ - ulong32 st_buff_indx1; /* reserved command idx. for this buffer */ - ulong32 st_buff_addr2; /* physical address of status buffer 1 */ - ulong32 st_buff_u_addr2; /* reserved for 64 bit addressing */ - ulong32 st_buff_indx2; /* reserved command idx. for this buffer */ - ulong32 st_buff_size; /* size of each buffer in bytes */ - ulong32 cmd_mode; /* 0 = mode disabled, 1 = cmd_buff_addr1 */ - ulong32 cmd_buff_addr1; /* physical address of cmd buffer 1 */ - ulong32 cmd_buff_u_addr1; /* reserved for 64 bit addressing */ - ulong32 cmd_buff_indx1; /* cmd buf addr1 unique identifier */ - ulong32 cmd_buff_addr2; /* physical address of cmd buffer 1 */ - ulong32 cmd_buff_u_addr2; /* reserved for 64 bit addressing */ - ulong32 cmd_buff_indx2; /* cmd buf addr1 unique identifier */ - ulong32 cmd_buff_size; /* size of each cmd bufer in bytes */ - ulong32 reserved1; - ulong32 reserved2; -} PACKED gdth_perf_modes; + u32 version; /* The version of this IOCTL structure. */ + u32 st_mode; /* 0=dis., 1=st_buf_addr1 valid, 2=both */ + u32 st_buff_addr1; /* physical address of status buffer 1 */ + u32 st_buff_u_addr1; /* reserved for 64 bit addressing */ + u32 st_buff_indx1; /* reserved command idx. for this buffer */ + u32 st_buff_addr2; /* physical address of status buffer 1 */ + u32 st_buff_u_addr2; /* reserved for 64 bit addressing */ + u32 st_buff_indx2; /* reserved command idx. for this buffer */ + u32 st_buff_size; /* size of each buffer in bytes */ + u32 cmd_mode; /* 0 = mode disabled, 1 = cmd_buff_addr1 */ + u32 cmd_buff_addr1; /* physical address of cmd buffer 1 */ + u32 cmd_buff_u_addr1; /* reserved for 64 bit addressing */ + u32 cmd_buff_indx1; /* cmd buf addr1 unique identifier */ + u32 cmd_buff_addr2; /* physical address of cmd buffer 1 */ + u32 cmd_buff_u_addr2; /* reserved for 64 bit addressing */ + u32 cmd_buff_indx2; /* cmd buf addr1 unique identifier */ + u32 cmd_buff_size; /* size of each cmd bufer in bytes */ + u32 reserved1; + u32 reserved2; +} __attribute__((packed)) gdth_perf_modes; /* SCSI drive info */ typedef struct { - unchar vendor[8]; /* vendor string */ - unchar product[16]; /* product string */ - unchar revision[4]; /* revision */ - ulong32 sy_rate; /* current rate for sync. tr. */ - ulong32 sy_max_rate; /* max. rate for sync. tr. */ - ulong32 no_ldrive; /* belongs to this log. drv.*/ - ulong32 blkcnt; /* number of blocks */ - ushort blksize; /* size of block in bytes */ - unchar available; /* flag: access is available */ - unchar init; /* medium is initialized */ - unchar devtype; /* SCSI devicetype */ - unchar rm_medium; /* medium is removable */ - unchar wp_medium; /* medium is write protected */ - unchar ansi; /* SCSI I/II or III? */ - unchar protocol; /* same as ansi */ - unchar sync; /* flag: sync. transfer enab. */ - unchar disc; /* flag: disconnect enabled */ - unchar queueing; /* flag: command queing enab. */ - unchar cached; /* flag: caching enabled */ - unchar target_id; /* target ID of device */ - unchar lun; /* LUN id of device */ - unchar orphan; /* flag: drive fragment */ - ulong32 last_error; /* sense key or drive state */ - ulong32 last_result; /* result of last command */ - ulong32 check_errors; /* err. in last surface check */ - unchar percent; /* progress for surface check */ - unchar last_check; /* IOCTRL operation */ - unchar res[2]; - ulong32 flags; /* from 1.19/2.19: raw reserv.*/ - unchar multi_bus; /* multi bus dev? (fibre ch.) */ - unchar mb_status; /* status: available? */ - unchar res2[2]; - unchar mb_alt_status; /* status on second bus */ - unchar mb_alt_bid; /* number of second bus */ - unchar mb_alt_tid; /* target id on second bus */ - unchar res3; - unchar fc_flag; /* from 1.22/2.22: info valid?*/ - unchar res4; - ushort fc_frame_size; /* frame size (bytes) */ + u8 vendor[8]; /* vendor string */ + u8 product[16]; /* product string */ + u8 revision[4]; /* revision */ + u32 sy_rate; /* current rate for sync. tr. */ + u32 sy_max_rate; /* max. rate for sync. tr. */ + u32 no_ldrive; /* belongs to this log. drv.*/ + u32 blkcnt; /* number of blocks */ + u16 blksize; /* size of block in bytes */ + u8 available; /* flag: access is available */ + u8 init; /* medium is initialized */ + u8 devtype; /* SCSI devicetype */ + u8 rm_medium; /* medium is removable */ + u8 wp_medium; /* medium is write protected */ + u8 ansi; /* SCSI I/II or III? */ + u8 protocol; /* same as ansi */ + u8 sync; /* flag: sync. transfer enab. */ + u8 disc; /* flag: disconnect enabled */ + u8 queueing; /* flag: command queing enab. */ + u8 cached; /* flag: caching enabled */ + u8 target_id; /* target ID of device */ + u8 lun; /* LUN id of device */ + u8 orphan; /* flag: drive fragment */ + u32 last_error; /* sense key or drive state */ + u32 last_result; /* result of last command */ + u32 check_errors; /* err. in last surface check */ + u8 percent; /* progress for surface check */ + u8 last_check; /* IOCTRL operation */ + u8 res[2]; + u32 flags; /* from 1.19/2.19: raw reserv.*/ + u8 multi_bus; /* multi bus dev? (fibre ch.) */ + u8 mb_status; /* status: available? */ + u8 res2[2]; + u8 mb_alt_status; /* status on second bus */ + u8 mb_alt_bid; /* number of second bus */ + u8 mb_alt_tid; /* target id on second bus */ + u8 res3; + u8 fc_flag; /* from 1.22/2.22: info valid?*/ + u8 res4; + u16 fc_frame_size; /* frame size (bytes) */ char wwn[8]; /* world wide name */ -} PACKED gdth_diskinfo_str; +} __attribute__((packed)) gdth_diskinfo_str; /* get SCSI channel count */ typedef struct { - ulong32 channel_no; /* number of channel */ - ulong32 drive_cnt; /* drive count */ - unchar siop_id; /* SCSI processor ID */ - unchar siop_state; /* SCSI processor state */ -} PACKED gdth_getch_str; + u32 channel_no; /* number of channel */ + u32 drive_cnt; /* drive count */ + u8 siop_id; /* SCSI processor ID */ + u8 siop_state; /* SCSI processor state */ +} __attribute__((packed)) gdth_getch_str; /* get SCSI drive numbers */ typedef struct { - ulong32 sc_no; /* SCSI channel */ - ulong32 sc_cnt; /* sc_list[] elements */ - ulong32 sc_list[MAXID]; /* minor device numbers */ -} PACKED gdth_drlist_str; + u32 sc_no; /* SCSI channel */ + u32 sc_cnt; /* sc_list[] elements */ + u32 sc_list[MAXID]; /* minor device numbers */ +} __attribute__((packed)) gdth_drlist_str; /* get grown/primary defect count */ typedef struct { - unchar sddc_type; /* 0x08: grown, 0x10: prim. */ - unchar sddc_format; /* list entry format */ - unchar sddc_len; /* list entry length */ - unchar sddc_res; - ulong32 sddc_cnt; /* entry count */ -} PACKED gdth_defcnt_str; + u8 sddc_type; /* 0x08: grown, 0x10: prim. */ + u8 sddc_format; /* list entry format */ + u8 sddc_len; /* list entry length */ + u8 sddc_res; + u32 sddc_cnt; /* entry count */ +} __attribute__((packed)) gdth_defcnt_str; /* disk statistics */ typedef struct { - ulong32 bid; /* SCSI channel */ - ulong32 first; /* first SCSI disk */ - ulong32 entries; /* number of elements */ - ulong32 count; /* (R) number of init. el. */ - ulong32 mon_time; /* time stamp */ + u32 bid; /* SCSI channel */ + u32 first; /* first SCSI disk */ + u32 entries; /* number of elements */ + u32 count; /* (R) number of init. el. */ + u32 mon_time; /* time stamp */ struct { - unchar tid; /* target ID */ - unchar lun; /* LUN */ - unchar res[2]; - ulong32 blk_size; /* block size in bytes */ - ulong32 rd_count; /* bytes read */ - ulong32 wr_count; /* bytes written */ - ulong32 rd_blk_count; /* blocks read */ - ulong32 wr_blk_count; /* blocks written */ - ulong32 retries; /* retries */ - ulong32 reassigns; /* reassigns */ - } PACKED list[1]; -} PACKED gdth_dskstat_str; + u8 tid; /* target ID */ + u8 lun; /* LUN */ + u8 res[2]; + u32 blk_size; /* block size in bytes */ + u32 rd_count; /* bytes read */ + u32 wr_count; /* bytes written */ + u32 rd_blk_count; /* blocks read */ + u32 wr_blk_count; /* blocks written */ + u32 retries; /* retries */ + u32 reassigns; /* reassigns */ + } __attribute__((packed)) list[1]; +} __attribute__((packed)) gdth_dskstat_str; /* IO channel header */ typedef struct { - ulong32 version; /* version (-1UL: newest) */ - unchar list_entries; /* list entry count */ - unchar first_chan; /* first channel number */ - unchar last_chan; /* last channel number */ - unchar chan_count; /* (R) channel count */ - ulong32 list_offset; /* offset of list[0] */ -} PACKED gdth_iochan_header; + u32 version; /* version (-1UL: newest) */ + u8 list_entries; /* list entry count */ + u8 first_chan; /* first channel number */ + u8 last_chan; /* last channel number */ + u8 chan_count; /* (R) channel count */ + u32 list_offset; /* offset of list[0] */ +} __attribute__((packed)) gdth_iochan_header; /* get IO channel description */ typedef struct { gdth_iochan_header hdr; struct { - ulong32 address; /* channel address */ - unchar type; /* type (SCSI, FCAL) */ - unchar local_no; /* local number */ - ushort features; /* channel features */ - } PACKED list[MAXBUS]; -} PACKED gdth_iochan_str; + u32 address; /* channel address */ + u8 type; /* type (SCSI, FCAL) */ + u8 local_no; /* local number */ + u16 features; /* channel features */ + } __attribute__((packed)) list[MAXBUS]; +} __attribute__((packed)) gdth_iochan_str; /* get raw IO channel description */ typedef struct { gdth_iochan_header hdr; struct { - unchar proc_id; /* processor id */ - unchar proc_defect; /* defect ? */ - unchar reserved[2]; - } PACKED list[MAXBUS]; -} PACKED gdth_raw_iochan_str; + u8 proc_id; /* processor id */ + u8 proc_defect; /* defect ? */ + u8 reserved[2]; + } __attribute__((packed)) list[MAXBUS]; +} __attribute__((packed)) gdth_raw_iochan_str; /* array drive component */ typedef struct { - ulong32 al_controller; /* controller ID */ - unchar al_cache_drive; /* cache drive number */ - unchar al_status; /* cache drive state */ - unchar al_res[2]; -} PACKED gdth_arraycomp_str; + u32 al_controller; /* controller ID */ + u8 al_cache_drive; /* cache drive number */ + u8 al_status; /* cache drive state */ + u8 al_res[2]; +} __attribute__((packed)) gdth_arraycomp_str; /* array drive information */ typedef struct { - unchar ai_type; /* array type (RAID0,4,5) */ - unchar ai_cache_drive_cnt; /* active cachedrives */ - unchar ai_state; /* array drive state */ - unchar ai_master_cd; /* master cachedrive */ - ulong32 ai_master_controller; /* ID of master controller */ - ulong32 ai_size; /* user capacity [sectors] */ - ulong32 ai_striping_size; /* striping size [sectors] */ - ulong32 ai_secsize; /* sector size [bytes] */ - ulong32 ai_err_info; /* failed cache drive */ - unchar ai_name[8]; /* name of the array drive */ - unchar ai_controller_cnt; /* number of controllers */ - unchar ai_removable; /* flag: removable */ - unchar ai_write_protected; /* flag: write protected */ - unchar ai_devtype; /* type: always direct access */ + u8 ai_type; /* array type (RAID0,4,5) */ + u8 ai_cache_drive_cnt; /* active cachedrives */ + u8 ai_state; /* array drive state */ + u8 ai_master_cd; /* master cachedrive */ + u32 ai_master_controller; /* ID of master controller */ + u32 ai_size; /* user capacity [sectors] */ + u32 ai_striping_size; /* striping size [sectors] */ + u32 ai_secsize; /* sector size [bytes] */ + u32 ai_err_info; /* failed cache drive */ + u8 ai_name[8]; /* name of the array drive */ + u8 ai_controller_cnt; /* number of controllers */ + u8 ai_removable; /* flag: removable */ + u8 ai_write_protected; /* flag: write protected */ + u8 ai_devtype; /* type: always direct access */ gdth_arraycomp_str ai_drives[35]; /* drive components: */ - unchar ai_drive_entries; /* number of drive components */ - unchar ai_protected; /* protection flag */ - unchar ai_verify_state; /* state of a parity verify */ - unchar ai_ext_state; /* extended array drive state */ - unchar ai_expand_state; /* array expand state (>=2.18)*/ - unchar ai_reserved[3]; -} PACKED gdth_arrayinf_str; + u8 ai_drive_entries; /* number of drive components */ + u8 ai_protected; /* protection flag */ + u8 ai_verify_state; /* state of a parity verify */ + u8 ai_ext_state; /* extended array drive state */ + u8 ai_expand_state; /* array expand state (>=2.18)*/ + u8 ai_reserved[3]; +} __attribute__((packed)) gdth_arrayinf_str; /* get array drive list */ typedef struct { - ulong32 controller_no; /* controller no. */ - unchar cd_handle; /* master cachedrive */ - unchar is_arrayd; /* Flag: is array drive? */ - unchar is_master; /* Flag: is array master? */ - unchar is_parity; /* Flag: is parity drive? */ - unchar is_hotfix; /* Flag: is hotfix drive? */ - unchar res[3]; -} PACKED gdth_alist_str; + u32 controller_no; /* controller no. */ + u8 cd_handle; /* master cachedrive */ + u8 is_arrayd; /* Flag: is array drive? */ + u8 is_master; /* Flag: is array master? */ + u8 is_parity; /* Flag: is parity drive? */ + u8 is_hotfix; /* Flag: is hotfix drive? */ + u8 res[3]; +} __attribute__((packed)) gdth_alist_str; typedef struct { - ulong32 entries_avail; /* allocated entries */ - ulong32 entries_init; /* returned entries */ - ulong32 first_entry; /* first entry number */ - ulong32 list_offset; /* offset of following list */ + u32 entries_avail; /* allocated entries */ + u32 entries_init; /* returned entries */ + u32 first_entry; /* first entry number */ + u32 list_offset; /* offset of following list */ gdth_alist_str list[1]; /* list */ -} PACKED gdth_arcdl_str; +} __attribute__((packed)) gdth_arcdl_str; /* cache info/config IOCTL */ typedef struct { - ulong32 version; /* firmware version */ - ushort state; /* cache state (on/off) */ - ushort strategy; /* cache strategy */ - ushort write_back; /* write back state (on/off) */ - ushort block_size; /* cache block size */ -} PACKED gdth_cpar_str; + u32 version; /* firmware version */ + u16 state; /* cache state (on/off) */ + u16 strategy; /* cache strategy */ + u16 write_back; /* write back state (on/off) */ + u16 block_size; /* cache block size */ +} __attribute__((packed)) gdth_cpar_str; typedef struct { - ulong32 csize; /* cache size */ - ulong32 read_cnt; /* read/write counter */ - ulong32 write_cnt; - ulong32 tr_hits; /* hits */ - ulong32 sec_hits; - ulong32 sec_miss; /* misses */ -} PACKED gdth_cstat_str; + u32 csize; /* cache size */ + u32 read_cnt; /* read/write counter */ + u32 write_cnt; + u32 tr_hits; /* hits */ + u32 sec_hits; + u32 sec_miss; /* misses */ +} __attribute__((packed)) gdth_cstat_str; typedef struct { gdth_cpar_str cpar; gdth_cstat_str cstat; -} PACKED gdth_cinfo_str; +} __attribute__((packed)) gdth_cinfo_str; /* cache drive info */ typedef struct { - unchar cd_name[8]; /* cache drive name */ - ulong32 cd_devtype; /* SCSI devicetype */ - ulong32 cd_ldcnt; /* number of log. drives */ - ulong32 cd_last_error; /* last error */ - unchar cd_initialized; /* drive is initialized */ - unchar cd_removable; /* media is removable */ - unchar cd_write_protected; /* write protected */ - unchar cd_flags; /* Pool Hot Fix? */ - ulong32 ld_blkcnt; /* number of blocks */ - ulong32 ld_blksize; /* blocksize */ - ulong32 ld_dcnt; /* number of disks */ - ulong32 ld_slave; /* log. drive index */ - ulong32 ld_dtype; /* type of logical drive */ - ulong32 ld_last_error; /* last error */ - unchar ld_name[8]; /* log. drive name */ - unchar ld_error; /* error */ -} PACKED gdth_cdrinfo_str; + u8 cd_name[8]; /* cache drive name */ + u32 cd_devtype; /* SCSI devicetype */ + u32 cd_ldcnt; /* number of log. drives */ + u32 cd_last_error; /* last error */ + u8 cd_initialized; /* drive is initialized */ + u8 cd_removable; /* media is removable */ + u8 cd_write_protected; /* write protected */ + u8 cd_flags; /* Pool Hot Fix? */ + u32 ld_blkcnt; /* number of blocks */ + u32 ld_blksize; /* blocksize */ + u32 ld_dcnt; /* number of disks */ + u32 ld_slave; /* log. drive index */ + u32 ld_dtype; /* type of logical drive */ + u32 ld_last_error; /* last error */ + u8 ld_name[8]; /* log. drive name */ + u8 ld_error; /* error */ +} __attribute__((packed)) gdth_cdrinfo_str; /* OEM string */ typedef struct { - ulong32 ctl_version; - ulong32 file_major_version; - ulong32 file_minor_version; - ulong32 buffer_size; - ulong32 cpy_count; - ulong32 ext_error; - ulong32 oem_id; - ulong32 board_id; -} PACKED gdth_oem_str_params; - -typedef struct { - unchar product_0_1_name[16]; - unchar product_4_5_name[16]; - unchar product_cluster_name[16]; - unchar product_reserved[16]; - unchar scsi_cluster_target_vendor_id[16]; - unchar cluster_raid_fw_name[16]; - unchar oem_brand_name[16]; - unchar oem_raid_type[16]; - unchar bios_type[13]; - unchar bios_title[50]; - unchar oem_company_name[37]; - ulong32 pci_id_1; - ulong32 pci_id_2; - unchar validation_status[80]; - unchar reserved_1[4]; - unchar scsi_host_drive_inquiry_vendor_id[16]; - unchar library_file_template[16]; - unchar reserved_2[16]; - unchar tool_name_1[32]; - unchar tool_name_2[32]; - unchar tool_name_3[32]; - unchar oem_contact_1[84]; - unchar oem_contact_2[84]; - unchar oem_contact_3[84]; -} PACKED gdth_oem_str; + u32 ctl_version; + u32 file_major_version; + u32 file_minor_version; + u32 buffer_size; + u32 cpy_count; + u32 ext_error; + u32 oem_id; + u32 board_id; +} __attribute__((packed)) gdth_oem_str_params; + +typedef struct { + u8 product_0_1_name[16]; + u8 product_4_5_name[16]; + u8 product_cluster_name[16]; + u8 product_reserved[16]; + u8 scsi_cluster_target_vendor_id[16]; + u8 cluster_raid_fw_name[16]; + u8 oem_brand_name[16]; + u8 oem_raid_type[16]; + u8 bios_type[13]; + u8 bios_title[50]; + u8 oem_company_name[37]; + u32 pci_id_1; + u32 pci_id_2; + u8 validation_status[80]; + u8 reserved_1[4]; + u8 scsi_host_drive_inquiry_vendor_id[16]; + u8 library_file_template[16]; + u8 reserved_2[16]; + u8 tool_name_1[32]; + u8 tool_name_2[32]; + u8 tool_name_3[32]; + u8 oem_contact_1[84]; + u8 oem_contact_2[84]; + u8 oem_contact_3[84]; +} __attribute__((packed)) gdth_oem_str; typedef struct { gdth_oem_str_params params; gdth_oem_str text; -} PACKED gdth_oem_str_ioctl; +} __attribute__((packed)) gdth_oem_str_ioctl; /* board features */ typedef struct { - unchar chaining; /* Chaining supported */ - unchar striping; /* Striping (RAID-0) supp. */ - unchar mirroring; /* Mirroring (RAID-1) supp. */ - unchar raid; /* RAID-4/5/10 supported */ -} PACKED gdth_bfeat_str; + u8 chaining; /* Chaining supported */ + u8 striping; /* Striping (RAID-0) supp. */ + u8 mirroring; /* Mirroring (RAID-1) supp. */ + u8 raid; /* RAID-4/5/10 supported */ +} __attribute__((packed)) gdth_bfeat_str; /* board info IOCTL */ typedef struct { - ulong32 ser_no; /* serial no. */ - unchar oem_id[2]; /* OEM ID */ - ushort ep_flags; /* eprom flags */ - ulong32 proc_id; /* processor ID */ - ulong32 memsize; /* memory size (bytes) */ - unchar mem_banks; /* memory banks */ - unchar chan_type; /* channel type */ - unchar chan_count; /* channel count */ - unchar rdongle_pres; /* dongle present? */ - ulong32 epr_fw_ver; /* (eprom) firmware version */ - ulong32 upd_fw_ver; /* (update) firmware version */ - ulong32 upd_revision; /* update revision */ + u32 ser_no; /* serial no. */ + u8 oem_id[2]; /* OEM ID */ + u16 ep_flags; /* eprom flags */ + u32 proc_id; /* processor ID */ + u32 memsize; /* memory size (bytes) */ + u8 mem_banks; /* memory banks */ + u8 chan_type; /* channel type */ + u8 chan_count; /* channel count */ + u8 rdongle_pres; /* dongle present? */ + u32 epr_fw_ver; /* (eprom) firmware version */ + u32 upd_fw_ver; /* (update) firmware version */ + u32 upd_revision; /* update revision */ char type_string[16]; /* controller name */ char raid_string[16]; /* RAID firmware name */ - unchar update_pres; /* update present? */ - unchar xor_pres; /* XOR engine present? */ - unchar prom_type; /* ROM type (eprom/flash) */ - unchar prom_count; /* number of ROM devices */ - ulong32 dup_pres; /* duplexing module present? */ - ulong32 chan_pres; /* number of expansion chn. */ - ulong32 mem_pres; /* memory expansion inst. ? */ - unchar ft_bus_system; /* fault bus supported? */ - unchar subtype_valid; /* board_subtype valid? */ - unchar board_subtype; /* subtype/hardware level */ - unchar ramparity_pres; /* RAM parity check hardware? */ -} PACKED gdth_binfo_str; + u8 update_pres; /* update present? */ + u8 xor_pres; /* XOR engine present? */ + u8 prom_type; /* ROM type (eprom/flash) */ + u8 prom_count; /* number of ROM devices */ + u32 dup_pres; /* duplexing module present? */ + u32 chan_pres; /* number of expansion chn. */ + u32 mem_pres; /* memory expansion inst. ? */ + u8 ft_bus_system; /* fault bus supported? */ + u8 subtype_valid; /* board_subtype valid? */ + u8 board_subtype; /* subtype/hardware level */ + u8 ramparity_pres; /* RAM parity check hardware? */ +} __attribute__((packed)) gdth_binfo_str; /* get host drive info */ typedef struct { char name[8]; /* host drive name */ - ulong32 size; /* size (sectors) */ - unchar host_drive; /* host drive number */ - unchar log_drive; /* log. drive (master) */ - unchar reserved; - unchar rw_attribs; /* r/w attribs */ - ulong32 start_sec; /* start sector */ -} PACKED gdth_hentry_str; - -typedef struct { - ulong32 entries; /* entry count */ - ulong32 offset; /* offset of entries */ - unchar secs_p_head; /* sectors/head */ - unchar heads_p_cyl; /* heads/cylinder */ - unchar reserved; - unchar clust_drvtype; /* cluster drive type */ - ulong32 location; /* controller number */ + u32 size; /* size (sectors) */ + u8 host_drive; /* host drive number */ + u8 log_drive; /* log. drive (master) */ + u8 reserved; + u8 rw_attribs; /* r/w attribs */ + u32 start_sec; /* start sector */ +} __attribute__((packed)) gdth_hentry_str; + +typedef struct { + u32 entries; /* entry count */ + u32 offset; /* offset of entries */ + u8 secs_p_head; /* sectors/head */ + u8 heads_p_cyl; /* heads/cylinder */ + u8 reserved; + u8 clust_drvtype; /* cluster drive type */ + u32 location; /* controller number */ gdth_hentry_str entry[MAX_HDRIVES]; /* entries */ -} PACKED gdth_hget_str; +} __attribute__((packed)) gdth_hget_str; /* DPRAM structures */ /* interface area ISA/PCI */ typedef struct { - unchar S_Cmd_Indx; /* special command */ - unchar volatile S_Status; /* status special command */ - ushort reserved1; - ulong32 S_Info[4]; /* add. info special command */ - unchar volatile Sema0; /* command semaphore */ - unchar reserved2[3]; - unchar Cmd_Index; /* command number */ - unchar reserved3[3]; - ushort volatile Status; /* command status */ - ushort Service; /* service(for async.events) */ - ulong32 Info[2]; /* additional info */ + u8 S_Cmd_Indx; /* special command */ + u8 volatile S_Status; /* status special command */ + u16 reserved1; + u32 S_Info[4]; /* add. info special command */ + u8 volatile Sema0; /* command semaphore */ + u8 reserved2[3]; + u8 Cmd_Index; /* command number */ + u8 reserved3[3]; + u16 volatile Status; /* command status */ + u16 Service; /* service(for async.events) */ + u32 Info[2]; /* additional info */ struct { - ushort offset; /* command offs. in the DPRAM*/ - ushort serv_id; /* service */ - } PACKED comm_queue[MAXOFFSETS]; /* command queue */ - ulong32 bios_reserved[2]; - unchar gdt_dpr_cmd[1]; /* commands */ -} PACKED gdt_dpr_if; + u16 offset; /* command offs. in the DPRAM*/ + u16 serv_id; /* service */ + } __attribute__((packed)) comm_queue[MAXOFFSETS]; /* command queue */ + u32 bios_reserved[2]; + u8 gdt_dpr_cmd[1]; /* commands */ +} __attribute__((packed)) gdt_dpr_if; /* SRAM structure PCI controllers */ typedef struct { - ulong32 magic; /* controller ID from BIOS */ - ushort need_deinit; /* switch betw. BIOS/driver */ - unchar switch_support; /* see need_deinit */ - unchar padding[9]; - unchar os_used[16]; /* OS code per service */ - unchar unused[28]; - unchar fw_magic; /* contr. ID from firmware */ -} PACKED gdt_pci_sram; + u32 magic; /* controller ID from BIOS */ + u16 need_deinit; /* switch betw. BIOS/driver */ + u8 switch_support; /* see need_deinit */ + u8 padding[9]; + u8 os_used[16]; /* OS code per service */ + u8 unused[28]; + u8 fw_magic; /* contr. ID from firmware */ +} __attribute__((packed)) gdt_pci_sram; /* SRAM structure EISA controllers (but NOT GDT3000/3020) */ typedef struct { - unchar os_used[16]; /* OS code per service */ - ushort need_deinit; /* switch betw. BIOS/driver */ - unchar switch_support; /* see need_deinit */ - unchar padding; -} PACKED gdt_eisa_sram; + u8 os_used[16]; /* OS code per service */ + u16 need_deinit; /* switch betw. BIOS/driver */ + u8 switch_support; /* see need_deinit */ + u8 padding; +} __attribute__((packed)) gdt_eisa_sram; /* DPRAM ISA controllers */ typedef struct { union { struct { - unchar bios_used[0x3c00-32]; /* 15KB - 32Bytes BIOS */ - ulong32 magic; /* controller (EISA) ID */ - ushort need_deinit; /* switch betw. BIOS/driver */ - unchar switch_support; /* see need_deinit */ - unchar padding[9]; - unchar os_used[16]; /* OS code per service */ - } PACKED dp_sram; - unchar bios_area[0x4000]; /* 16KB reserved for BIOS */ + u8 bios_used[0x3c00-32]; /* 15KB - 32Bytes BIOS */ + u32 magic; /* controller (EISA) ID */ + u16 need_deinit; /* switch betw. BIOS/driver */ + u8 switch_support; /* see need_deinit */ + u8 padding[9]; + u8 os_used[16]; /* OS code per service */ + } __attribute__((packed)) dp_sram; + u8 bios_area[0x4000]; /* 16KB reserved for BIOS */ } bu; union { gdt_dpr_if ic; /* interface area */ - unchar if_area[0x3000]; /* 12KB for interface */ + u8 if_area[0x3000]; /* 12KB for interface */ } u; struct { - unchar memlock; /* write protection DPRAM */ - unchar event; /* release event */ - unchar irqen; /* board interrupts enable */ - unchar irqdel; /* acknowledge board int. */ - unchar volatile Sema1; /* status semaphore */ - unchar rq; /* IRQ/DRQ configuration */ - } PACKED io; -} PACKED gdt2_dpram_str; + u8 memlock; /* write protection DPRAM */ + u8 event; /* release event */ + u8 irqen; /* board interrupts enable */ + u8 irqdel; /* acknowledge board int. */ + u8 volatile Sema1; /* status semaphore */ + u8 rq; /* IRQ/DRQ configuration */ + } __attribute__((packed)) io; +} __attribute__((packed)) gdt2_dpram_str; /* DPRAM PCI controllers */ typedef struct { union { gdt_dpr_if ic; /* interface area */ - unchar if_area[0xff0-sizeof(gdt_pci_sram)]; + u8 if_area[0xff0-sizeof(gdt_pci_sram)]; } u; gdt_pci_sram gdt6sr; /* SRAM structure */ struct { - unchar unused0[1]; - unchar volatile Sema1; /* command semaphore */ - unchar unused1[3]; - unchar irqen; /* board interrupts enable */ - unchar unused2[2]; - unchar event; /* release event */ - unchar unused3[3]; - unchar irqdel; /* acknowledge board int. */ - unchar unused4[3]; - } PACKED io; -} PACKED gdt6_dpram_str; + u8 unused0[1]; + u8 volatile Sema1; /* command semaphore */ + u8 unused1[3]; + u8 irqen; /* board interrupts enable */ + u8 unused2[2]; + u8 event; /* release event */ + u8 unused3[3]; + u8 irqdel; /* acknowledge board int. */ + u8 unused4[3]; + } __attribute__((packed)) io; +} __attribute__((packed)) gdt6_dpram_str; /* PLX register structure (new PCI controllers) */ typedef struct { - unchar cfg_reg; /* DPRAM cfg.(2:below 1MB,0:anywhere)*/ - unchar unused1[0x3f]; - unchar volatile sema0_reg; /* command semaphore */ - unchar volatile sema1_reg; /* status semaphore */ - unchar unused2[2]; - ushort volatile status; /* command status */ - ushort service; /* service */ - ulong32 info[2]; /* additional info */ - unchar unused3[0x10]; - unchar ldoor_reg; /* PCI to local doorbell */ - unchar unused4[3]; - unchar volatile edoor_reg; /* local to PCI doorbell */ - unchar unused5[3]; - unchar control0; /* control0 register(unused) */ - unchar control1; /* board interrupts enable */ - unchar unused6[0x16]; -} PACKED gdt6c_plx_regs; + u8 cfg_reg; /* DPRAM cfg.(2:below 1MB,0:anywhere)*/ + u8 unused1[0x3f]; + u8 volatile sema0_reg; /* command semaphore */ + u8 volatile sema1_reg; /* status semaphore */ + u8 unused2[2]; + u16 volatile status; /* command status */ + u16 service; /* service */ + u32 info[2]; /* additional info */ + u8 unused3[0x10]; + u8 ldoor_reg; /* PCI to local doorbell */ + u8 unused4[3]; + u8 volatile edoor_reg; /* local to PCI doorbell */ + u8 unused5[3]; + u8 control0; /* control0 register(unused) */ + u8 control1; /* board interrupts enable */ + u8 unused6[0x16]; +} __attribute__((packed)) gdt6c_plx_regs; /* DPRAM new PCI controllers */ typedef struct { union { gdt_dpr_if ic; /* interface area */ - unchar if_area[0x4000-sizeof(gdt_pci_sram)]; + u8 if_area[0x4000-sizeof(gdt_pci_sram)]; } u; gdt_pci_sram gdt6sr; /* SRAM structure */ -} PACKED gdt6c_dpram_str; +} __attribute__((packed)) gdt6c_dpram_str; /* i960 register structure (PCI MPR controllers) */ typedef struct { - unchar unused1[16]; - unchar volatile sema0_reg; /* command semaphore */ - unchar unused2; - unchar volatile sema1_reg; /* status semaphore */ - unchar unused3; - ushort volatile status; /* command status */ - ushort service; /* service */ - ulong32 info[2]; /* additional info */ - unchar ldoor_reg; /* PCI to local doorbell */ - unchar unused4[11]; - unchar volatile edoor_reg; /* local to PCI doorbell */ - unchar unused5[7]; - unchar edoor_en_reg; /* board interrupts enable */ - unchar unused6[27]; - ulong32 unused7[939]; - ulong32 severity; + u8 unused1[16]; + u8 volatile sema0_reg; /* command semaphore */ + u8 unused2; + u8 volatile sema1_reg; /* status semaphore */ + u8 unused3; + u16 volatile status; /* command status */ + u16 service; /* service */ + u32 info[2]; /* additional info */ + u8 ldoor_reg; /* PCI to local doorbell */ + u8 unused4[11]; + u8 volatile edoor_reg; /* local to PCI doorbell */ + u8 unused5[7]; + u8 edoor_en_reg; /* board interrupts enable */ + u8 unused6[27]; + u32 unused7[939]; + u32 severity; char evt_str[256]; /* event string */ -} PACKED gdt6m_i960_regs; +} __attribute__((packed)) gdt6m_i960_regs; /* DPRAM PCI MPR controllers */ typedef struct { gdt6m_i960_regs i960r; /* 4KB i960 registers */ union { gdt_dpr_if ic; /* interface area */ - unchar if_area[0x3000-sizeof(gdt_pci_sram)]; + u8 if_area[0x3000-sizeof(gdt_pci_sram)]; } u; gdt_pci_sram gdt6sr; /* SRAM structure */ -} PACKED gdt6m_dpram_str; +} __attribute__((packed)) gdt6m_dpram_str; /* PCI resources */ typedef struct { struct pci_dev *pdev; - ulong dpmem; /* DPRAM address */ - ulong io; /* IO address */ + unsigned long dpmem; /* DPRAM address */ + unsigned long io; /* IO address */ } gdth_pci_str; @@ -846,93 +846,93 @@ typedef struct { typedef struct { struct Scsi_Host *shost; struct list_head list; - ushort hanum; - ushort oem_id; /* OEM */ - ushort type; /* controller class */ - ulong32 stype; /* subtype (PCI: device ID) */ - ushort fw_vers; /* firmware version */ - ushort cache_feat; /* feat. cache serv. (s/g,..)*/ - ushort raw_feat; /* feat. raw service (s/g,..)*/ - ushort screen_feat; /* feat. raw service (s/g,..)*/ - ushort bmic; /* BMIC address (EISA) */ + u16 hanum; + u16 oem_id; /* OEM */ + u16 type; /* controller class */ + u32 stype; /* subtype (PCI: device ID) */ + u16 fw_vers; /* firmware version */ + u16 cache_feat; /* feat. cache serv. (s/g,..)*/ + u16 raw_feat; /* feat. raw service (s/g,..)*/ + u16 screen_feat; /* feat. raw service (s/g,..)*/ + u16 bmic; /* BMIC address (EISA) */ void __iomem *brd; /* DPRAM address */ - ulong32 brd_phys; /* slot number/BIOS address */ + u32 brd_phys; /* slot number/BIOS address */ gdt6c_plx_regs *plx; /* PLX regs (new PCI contr.) */ gdth_cmd_str cmdext; gdth_cmd_str *pccb; /* address command structure */ - ulong32 ccb_phys; /* phys. address */ + u32 ccb_phys; /* phys. address */ #ifdef INT_COAL gdth_coal_status *coal_stat; /* buffer for coalescing int.*/ - ulong64 coal_stat_phys; /* phys. address */ + u64 coal_stat_phys; /* phys. address */ #endif char *pscratch; /* scratch (DMA) buffer */ - ulong64 scratch_phys; /* phys. address */ - unchar scratch_busy; /* in use? */ - unchar dma64_support; /* 64-bit DMA supported? */ + u64 scratch_phys; /* phys. address */ + u8 scratch_busy; /* in use? */ + u8 dma64_support; /* 64-bit DMA supported? */ gdth_msg_str *pmsg; /* message buffer */ - ulong64 msg_phys; /* phys. address */ - unchar scan_mode; /* current scan mode */ - unchar irq; /* IRQ */ - unchar drq; /* DRQ (ISA controllers) */ - ushort status; /* command status */ - ushort service; /* service/firmware ver./.. */ - ulong32 info; - ulong32 info2; /* additional info */ + u64 msg_phys; /* phys. address */ + u8 scan_mode; /* current scan mode */ + u8 irq; /* IRQ */ + u8 drq; /* DRQ (ISA controllers) */ + u16 status; /* command status */ + u16 service; /* service/firmware ver./.. */ + u32 info; + u32 info2; /* additional info */ Scsi_Cmnd *req_first; /* top of request queue */ struct { - unchar present; /* Flag: host drive present? */ - unchar is_logdrv; /* Flag: log. drive (master)? */ - unchar is_arraydrv; /* Flag: array drive? */ - unchar is_master; /* Flag: array drive master? */ - unchar is_parity; /* Flag: parity drive? */ - unchar is_hotfix; /* Flag: hotfix drive? */ - unchar master_no; /* number of master drive */ - unchar lock; /* drive locked? (hot plug) */ - unchar heads; /* mapping */ - unchar secs; - ushort devtype; /* further information */ - ulong64 size; /* capacity */ - unchar ldr_no; /* log. drive no. */ - unchar rw_attribs; /* r/w attributes */ - unchar cluster_type; /* cluster properties */ - unchar media_changed; /* Flag:MOUNT/UNMOUNT occured */ - ulong32 start_sec; /* start sector */ + u8 present; /* Flag: host drive present? */ + u8 is_logdrv; /* Flag: log. drive (master)? */ + u8 is_arraydrv; /* Flag: array drive? */ + u8 is_master; /* Flag: array drive master? */ + u8 is_parity; /* Flag: parity drive? */ + u8 is_hotfix; /* Flag: hotfix drive? */ + u8 master_no; /* number of master drive */ + u8 lock; /* drive locked? (hot plug) */ + u8 heads; /* mapping */ + u8 secs; + u16 devtype; /* further information */ + u64 size; /* capacity */ + u8 ldr_no; /* log. drive no. */ + u8 rw_attribs; /* r/w attributes */ + u8 cluster_type; /* cluster properties */ + u8 media_changed; /* Flag:MOUNT/UNMOUNT occured */ + u32 start_sec; /* start sector */ } hdr[MAX_LDRIVES]; /* host drives */ struct { - unchar lock; /* channel locked? (hot plug) */ - unchar pdev_cnt; /* physical device count */ - unchar local_no; /* local channel number */ - unchar io_cnt[MAXID]; /* current IO count */ - ulong32 address; /* channel address */ - ulong32 id_list[MAXID]; /* IDs of the phys. devices */ + u8 lock; /* channel locked? (hot plug) */ + u8 pdev_cnt; /* physical device count */ + u8 local_no; /* local channel number */ + u8 io_cnt[MAXID]; /* current IO count */ + u32 address; /* channel address */ + u32 id_list[MAXID]; /* IDs of the phys. devices */ } raw[MAXBUS]; /* SCSI channels */ struct { Scsi_Cmnd *cmnd; /* pending request */ - ushort service; /* service */ + u16 service; /* service */ } cmd_tab[GDTH_MAXCMDS]; /* table of pend. requests */ struct gdth_cmndinfo { /* per-command private info */ int index; int internal_command; /* don't call scsi_done */ gdth_cmd_str *internal_cmd_str; /* crier for internal messages*/ dma_addr_t sense_paddr; /* sense dma-addr */ - unchar priority; + u8 priority; int timeout_count; /* # of timeout calls */ volatile int wait_for_completion; - ushort status; - ulong32 info; + u16 status; + u32 info; enum dma_data_direction dma_dir; int phase; /* ???? */ int OpCode; } cmndinfo[GDTH_MAXCMDS]; /* index==0 is free */ - unchar bus_cnt; /* SCSI bus count */ - unchar tid_cnt; /* Target ID count */ - unchar bus_id[MAXBUS]; /* IOP IDs */ - unchar virt_bus; /* number of virtual bus */ - unchar more_proc; /* more /proc info supported */ - ushort cmd_cnt; /* command count in DPRAM */ - ushort cmd_len; /* length of actual command */ - ushort cmd_offs_dpmem; /* actual offset in DPRAM */ - ushort ic_all_size; /* sizeof DPRAM interf. area */ + u8 bus_cnt; /* SCSI bus count */ + u8 tid_cnt; /* Target ID count */ + u8 bus_id[MAXBUS]; /* IOP IDs */ + u8 virt_bus; /* number of virtual bus */ + u8 more_proc; /* more /proc info supported */ + u16 cmd_cnt; /* command count in DPRAM */ + u16 cmd_len; /* length of actual command */ + u16 cmd_offs_dpmem; /* actual offset in DPRAM */ + u16 ic_all_size; /* sizeof DPRAM interf. area */ gdth_cpar_str cpar; /* controller cache par. */ gdth_bfeat_str bfeat; /* controller features */ gdth_binfo_str binfo; /* controller info */ @@ -941,7 +941,7 @@ typedef struct { struct pci_dev *pdev; char oem_name[8]; #ifdef GDTH_DMA_STATISTICS - ulong dma32_cnt, dma64_cnt; /* statistics: DMA buffer */ + unsigned long dma32_cnt, dma64_cnt; /* statistics: DMA buffer */ #endif struct scsi_device *sdev; } gdth_ha_str; @@ -953,65 +953,65 @@ static inline struct gdth_cmndinfo *gdth_cmnd_priv(struct scsi_cmnd* cmd) /* INQUIRY data format */ typedef struct { - unchar type_qual; - unchar modif_rmb; - unchar version; - unchar resp_aenc; - unchar add_length; - unchar reserved1; - unchar reserved2; - unchar misc; - unchar vendor[8]; - unchar product[16]; - unchar revision[4]; -} PACKED gdth_inq_data; + u8 type_qual; + u8 modif_rmb; + u8 version; + u8 resp_aenc; + u8 add_length; + u8 reserved1; + u8 reserved2; + u8 misc; + u8 vendor[8]; + u8 product[16]; + u8 revision[4]; +} __attribute__((packed)) gdth_inq_data; /* READ_CAPACITY data format */ typedef struct { - ulong32 last_block_no; - ulong32 block_length; -} PACKED gdth_rdcap_data; + u32 last_block_no; + u32 block_length; +} __attribute__((packed)) gdth_rdcap_data; /* READ_CAPACITY (16) data format */ typedef struct { - ulong64 last_block_no; - ulong32 block_length; -} PACKED gdth_rdcap16_data; + u64 last_block_no; + u32 block_length; +} __attribute__((packed)) gdth_rdcap16_data; /* REQUEST_SENSE data format */ typedef struct { - unchar errorcode; - unchar segno; - unchar key; - ulong32 info; - unchar add_length; - ulong32 cmd_info; - unchar adsc; - unchar adsq; - unchar fruc; - unchar key_spec[3]; -} PACKED gdth_sense_data; + u8 errorcode; + u8 segno; + u8 key; + u32 info; + u8 add_length; + u32 cmd_info; + u8 adsc; + u8 adsq; + u8 fruc; + u8 key_spec[3]; +} __attribute__((packed)) gdth_sense_data; /* MODE_SENSE data format */ typedef struct { struct { - unchar data_length; - unchar med_type; - unchar dev_par; - unchar bd_length; - } PACKED hd; + u8 data_length; + u8 med_type; + u8 dev_par; + u8 bd_length; + } __attribute__((packed)) hd; struct { - unchar dens_code; - unchar block_count[3]; - unchar reserved; - unchar block_length[3]; - } PACKED bd; -} PACKED gdth_modep_data; + u8 dens_code; + u8 block_count[3]; + u8 reserved; + u8 block_length[3]; + } __attribute__((packed)) bd; +} __attribute__((packed)) gdth_modep_data; /* stack frame */ typedef struct { - ulong b[10]; /* 32/64 bit compiler ! */ -} PACKED gdth_stackframe; + unsigned long b[10]; /* 32/64 bit compiler ! */ +} __attribute__((packed)) gdth_stackframe; /* function prototyping */ diff --git a/drivers/scsi/gdth_ioctl.h b/drivers/scsi/gdth_ioctl.h index 783fae737f17..b004c6165887 100644 --- a/drivers/scsi/gdth_ioctl.h +++ b/drivers/scsi/gdth_ioctl.h @@ -32,109 +32,101 @@ #define MAX_HDRIVES MAX_LDRIVES /* max. host drive count */ #endif -/* typedefs */ -#ifdef __KERNEL__ -typedef u32 ulong32; -typedef u64 ulong64; -#endif - -#define PACKED __attribute__((packed)) - /* scatter/gather element */ typedef struct { - ulong32 sg_ptr; /* address */ - ulong32 sg_len; /* length */ -} PACKED gdth_sg_str; + u32 sg_ptr; /* address */ + u32 sg_len; /* length */ +} __attribute__((packed)) gdth_sg_str; /* scatter/gather element - 64bit addresses */ typedef struct { - ulong64 sg_ptr; /* address */ - ulong32 sg_len; /* length */ -} PACKED gdth_sg64_str; + u64 sg_ptr; /* address */ + u32 sg_len; /* length */ +} __attribute__((packed)) gdth_sg64_str; /* command structure */ typedef struct { - ulong32 BoardNode; /* board node (always 0) */ - ulong32 CommandIndex; /* command number */ - ushort OpCode; /* the command (READ,..) */ + u32 BoardNode; /* board node (always 0) */ + u32 CommandIndex; /* command number */ + u16 OpCode; /* the command (READ,..) */ union { struct { - ushort DeviceNo; /* number of cache drive */ - ulong32 BlockNo; /* block number */ - ulong32 BlockCnt; /* block count */ - ulong32 DestAddr; /* dest. addr. (if s/g: -1) */ - ulong32 sg_canz; /* s/g element count */ + u16 DeviceNo; /* number of cache drive */ + u32 BlockNo; /* block number */ + u32 BlockCnt; /* block count */ + u32 DestAddr; /* dest. addr. (if s/g: -1) */ + u32 sg_canz; /* s/g element count */ gdth_sg_str sg_lst[GDTH_MAXSG]; /* s/g list */ - } PACKED cache; /* cache service cmd. str. */ + } __attribute__((packed)) cache; /* cache service cmd. str. */ struct { - ushort DeviceNo; /* number of cache drive */ - ulong64 BlockNo; /* block number */ - ulong32 BlockCnt; /* block count */ - ulong64 DestAddr; /* dest. addr. (if s/g: -1) */ - ulong32 sg_canz; /* s/g element count */ + u16 DeviceNo; /* number of cache drive */ + u64 BlockNo; /* block number */ + u32 BlockCnt; /* block count */ + u64 DestAddr; /* dest. addr. (if s/g: -1) */ + u32 sg_canz; /* s/g element count */ gdth_sg64_str sg_lst[GDTH_MAXSG]; /* s/g list */ - } PACKED cache64; /* cache service cmd. str. */ + } __attribute__((packed)) cache64; /* cache service cmd. str. */ struct { - ushort param_size; /* size of p_param buffer */ - ulong32 subfunc; /* IOCTL function */ - ulong32 channel; /* device */ - ulong64 p_param; /* buffer */ - } PACKED ioctl; /* IOCTL command structure */ + u16 param_size; /* size of p_param buffer */ + u32 subfunc; /* IOCTL function */ + u32 channel; /* device */ + u64 p_param; /* buffer */ + } __attribute__((packed)) ioctl; /* IOCTL command structure */ struct { - ushort reserved; + u16 reserved; union { struct { - ulong32 msg_handle; /* message handle */ - ulong64 msg_addr; /* message buffer address */ - } PACKED msg; - unchar data[12]; /* buffer for rtc data, ... */ + u32 msg_handle; /* message handle */ + u64 msg_addr; /* message buffer address */ + } __attribute__((packed)) msg; + u8 data[12]; /* buffer for rtc data, ... */ } su; - } PACKED screen; /* screen service cmd. str. */ + } __attribute__((packed)) screen; /* screen service cmd. str. */ struct { - ushort reserved; - ulong32 direction; /* data direction */ - ulong32 mdisc_time; /* disc. time (0: no timeout)*/ - ulong32 mcon_time; /* connect time(0: no to.) */ - ulong32 sdata; /* dest. addr. (if s/g: -1) */ - ulong32 sdlen; /* data length (bytes) */ - ulong32 clen; /* SCSI cmd. length(6,10,12) */ - unchar cmd[12]; /* SCSI command */ - unchar target; /* target ID */ - unchar lun; /* LUN */ - unchar bus; /* SCSI bus number */ - unchar priority; /* only 0 used */ - ulong32 sense_len; /* sense data length */ - ulong32 sense_data; /* sense data addr. */ - ulong32 link_p; /* linked cmds (not supp.) */ - ulong32 sg_ranz; /* s/g element count */ + u16 reserved; + u32 direction; /* data direction */ + u32 mdisc_time; /* disc. time (0: no timeout)*/ + u32 mcon_time; /* connect time(0: no to.) */ + u32 sdata; /* dest. addr. (if s/g: -1) */ + u32 sdlen; /* data length (bytes) */ + u32 clen; /* SCSI cmd. length(6,10,12) */ + u8 cmd[12]; /* SCSI command */ + u8 target; /* target ID */ + u8 lun; /* LUN */ + u8 bus; /* SCSI bus number */ + u8 priority; /* only 0 used */ + u32 sense_len; /* sense data length */ + u32 sense_data; /* sense data addr. */ + u32 link_p; /* linked cmds (not supp.) */ + u32 sg_ranz; /* s/g element count */ gdth_sg_str sg_lst[GDTH_MAXSG]; /* s/g list */ - } PACKED raw; /* raw service cmd. struct. */ + } __attribute__((packed)) raw; /* raw service cmd. struct. */ struct { - ushort reserved; - ulong32 direction; /* data direction */ - ulong32 mdisc_time; /* disc. time (0: no timeout)*/ - ulong32 mcon_time; /* connect time(0: no to.) */ - ulong64 sdata; /* dest. addr. (if s/g: -1) */ - ulong32 sdlen; /* data length (bytes) */ - ulong32 clen; /* SCSI cmd. length(6,..,16) */ - unchar cmd[16]; /* SCSI command */ - unchar target; /* target ID */ - unchar lun; /* LUN */ - unchar bus; /* SCSI bus number */ - unchar priority; /* only 0 used */ - ulong32 sense_len; /* sense data length */ - ulong64 sense_data; /* sense data addr. */ - ulong32 sg_ranz; /* s/g element count */ + u16 reserved; + u32 direction; /* data direction */ + u32 mdisc_time; /* disc. time (0: no timeout)*/ + u32 mcon_time; /* connect time(0: no to.) */ + u64 sdata; /* dest. addr. (if s/g: -1) */ + u32 sdlen; /* data length (bytes) */ + u32 clen; /* SCSI cmd. length(6,..,16) */ + u8 cmd[16]; /* SCSI command */ + u8 target; /* target ID */ + u8 lun; /* LUN */ + u8 bus; /* SCSI bus number */ + u8 priority; /* only 0 used */ + u32 sense_len; /* sense data length */ + u64 sense_data; /* sense data addr. */ + u32 sg_ranz; /* s/g element count */ gdth_sg64_str sg_lst[GDTH_MAXSG]; /* s/g list */ - } PACKED raw64; /* raw service cmd. struct. */ + } __attribute__((packed)) raw64; /* raw service cmd. struct. */ } u; /* additional variables */ - unchar Service; /* controller service */ - unchar reserved; - ushort Status; /* command result */ - ulong32 Info; /* additional information */ + u8 Service; /* controller service */ + u8 reserved; + u16 Status; /* command result */ + u32 Info; /* additional information */ void *RequestBuffer; /* request buffer */ -} PACKED gdth_cmd_str; +} __attribute__((packed)) gdth_cmd_str; /* controller event structure */ #define ES_ASYNC 1 @@ -142,129 +134,129 @@ typedef struct { #define ES_TEST 3 #define ES_SYNC 4 typedef struct { - ushort size; /* size of structure */ + u16 size; /* size of structure */ union { char stream[16]; struct { - ushort ionode; - ushort service; - ulong32 index; - } PACKED driver; + u16 ionode; + u16 service; + u32 index; + } __attribute__((packed)) driver; struct { - ushort ionode; - ushort service; - ushort status; - ulong32 info; - unchar scsi_coord[3]; - } PACKED async; + u16 ionode; + u16 service; + u16 status; + u32 info; + u8 scsi_coord[3]; + } __attribute__((packed)) async; struct { - ushort ionode; - ushort service; - ushort status; - ulong32 info; - ushort hostdrive; - unchar scsi_coord[3]; - unchar sense_key; - } PACKED sync; + u16 ionode; + u16 service; + u16 status; + u32 info; + u16 hostdrive; + u8 scsi_coord[3]; + u8 sense_key; + } __attribute__((packed)) sync; struct { - ulong32 l1, l2, l3, l4; - } PACKED test; + u32 l1, l2, l3, l4; + } __attribute__((packed)) test; } eu; - ulong32 severity; - unchar event_string[256]; -} PACKED gdth_evt_data; + u32 severity; + u8 event_string[256]; +} __attribute__((packed)) gdth_evt_data; typedef struct { - ulong32 first_stamp; - ulong32 last_stamp; - ushort same_count; - ushort event_source; - ushort event_idx; - unchar application; - unchar reserved; + u32 first_stamp; + u32 last_stamp; + u16 same_count; + u16 event_source; + u16 event_idx; + u8 application; + u8 reserved; gdth_evt_data event_data; -} PACKED gdth_evt_str; +} __attribute__((packed)) gdth_evt_str; #ifdef GDTH_IOCTL_PROC /* IOCTL structure (write) */ typedef struct { - ulong32 magic; /* IOCTL magic */ - ushort ioctl; /* IOCTL */ - ushort ionode; /* controller number */ - ushort service; /* controller service */ - ushort timeout; /* timeout */ + u32 magic; /* IOCTL magic */ + u16 ioctl; /* IOCTL */ + u16 ionode; /* controller number */ + u16 service; /* controller service */ + u16 timeout; /* timeout */ union { struct { - unchar command[512]; /* controller command */ - unchar data[1]; /* add. data */ + u8 command[512]; /* controller command */ + u8 data[1]; /* add. data */ } general; struct { - unchar lock; /* lock/unlock */ - unchar drive_cnt; /* drive count */ - ushort drives[MAX_HDRIVES];/* drives */ + u8 lock; /* lock/unlock */ + u8 drive_cnt; /* drive count */ + u16 drives[MAX_HDRIVES];/* drives */ } lockdrv; struct { - unchar lock; /* lock/unlock */ - unchar channel; /* channel */ + u8 lock; /* lock/unlock */ + u8 channel; /* channel */ } lockchn; struct { int erase; /* erase event ? */ int handle; - unchar evt[EVENT_SIZE]; /* event structure */ + u8 evt[EVENT_SIZE]; /* event structure */ } event; struct { - unchar bus; /* SCSI bus */ - unchar target; /* target ID */ - unchar lun; /* LUN */ - unchar cmd_len; /* command length */ - unchar cmd[12]; /* SCSI command */ + u8 bus; /* SCSI bus */ + u8 target; /* target ID */ + u8 lun; /* LUN */ + u8 cmd_len; /* command length */ + u8 cmd[12]; /* SCSI command */ } scsi; struct { - ushort hdr_no; /* host drive number */ - unchar flag; /* old meth./add/remove */ + u16 hdr_no; /* host drive number */ + u8 flag; /* old meth./add/remove */ } rescan; } iu; } gdth_iowr_str; /* IOCTL structure (read) */ typedef struct { - ulong32 size; /* buffer size */ - ulong32 status; /* IOCTL error code */ + u32 size; /* buffer size */ + u32 status; /* IOCTL error code */ union { struct { - unchar data[1]; /* data */ + u8 data[1]; /* data */ } general; struct { - ushort version; /* driver version */ + u16 version; /* driver version */ } drvers; struct { - unchar type; /* controller type */ - ushort info; /* slot etc. */ - ushort oem_id; /* OEM ID */ - ushort bios_ver; /* not used */ - ushort access; /* not used */ - ushort ext_type; /* extended type */ - ushort device_id; /* device ID */ - ushort sub_device_id; /* sub device ID */ + u8 type; /* controller type */ + u16 info; /* slot etc. */ + u16 oem_id; /* OEM ID */ + u16 bios_ver; /* not used */ + u16 access; /* not used */ + u16 ext_type; /* extended type */ + u16 device_id; /* device ID */ + u16 sub_device_id; /* sub device ID */ } ctrtype; struct { - unchar version; /* OS version */ - unchar subversion; /* OS subversion */ - ushort revision; /* revision */ + u8 version; /* OS version */ + u8 subversion; /* OS subversion */ + u16 revision; /* revision */ } osvers; struct { - ushort count; /* controller count */ + u16 count; /* controller count */ } ctrcnt; struct { int handle; - unchar evt[EVENT_SIZE]; /* event structure */ + u8 evt[EVENT_SIZE]; /* event structure */ } event; struct { - unchar bus; /* SCSI bus, 0xff: invalid */ - unchar target; /* target ID */ - unchar lun; /* LUN */ - unchar cluster_type; /* cluster properties */ + u8 bus; /* SCSI bus, 0xff: invalid */ + u8 target; /* target ID */ + u8 lun; /* LUN */ + u8 cluster_type; /* cluster properties */ } hdr_list[MAX_HDRIVES]; /* index is host drive number */ } iu; } gdth_iord_str; @@ -272,53 +264,53 @@ typedef struct { /* GDTIOCTL_GENERAL */ typedef struct { - ushort ionode; /* controller number */ - ushort timeout; /* timeout */ - ulong32 info; /* error info */ - ushort status; /* status */ - ulong data_len; /* data buffer size */ - ulong sense_len; /* sense buffer size */ + u16 ionode; /* controller number */ + u16 timeout; /* timeout */ + u32 info; /* error info */ + u16 status; /* status */ + unsigned long data_len; /* data buffer size */ + unsigned long sense_len; /* sense buffer size */ gdth_cmd_str command; /* command */ } gdth_ioctl_general; /* GDTIOCTL_LOCKDRV */ typedef struct { - ushort ionode; /* controller number */ - unchar lock; /* lock/unlock */ - unchar drive_cnt; /* drive count */ - ushort drives[MAX_HDRIVES]; /* drives */ + u16 ionode; /* controller number */ + u8 lock; /* lock/unlock */ + u8 drive_cnt; /* drive count */ + u16 drives[MAX_HDRIVES]; /* drives */ } gdth_ioctl_lockdrv; /* GDTIOCTL_LOCKCHN */ typedef struct { - ushort ionode; /* controller number */ - unchar lock; /* lock/unlock */ - unchar channel; /* channel */ + u16 ionode; /* controller number */ + u8 lock; /* lock/unlock */ + u8 channel; /* channel */ } gdth_ioctl_lockchn; /* GDTIOCTL_OSVERS */ typedef struct { - unchar version; /* OS version */ - unchar subversion; /* OS subversion */ - ushort revision; /* revision */ + u8 version; /* OS version */ + u8 subversion; /* OS subversion */ + u16 revision; /* revision */ } gdth_ioctl_osvers; /* GDTIOCTL_CTRTYPE */ typedef struct { - ushort ionode; /* controller number */ - unchar type; /* controller type */ - ushort info; /* slot etc. */ - ushort oem_id; /* OEM ID */ - ushort bios_ver; /* not used */ - ushort access; /* not used */ - ushort ext_type; /* extended type */ - ushort device_id; /* device ID */ - ushort sub_device_id; /* sub device ID */ + u16 ionode; /* controller number */ + u8 type; /* controller type */ + u16 info; /* slot etc. */ + u16 oem_id; /* OEM ID */ + u16 bios_ver; /* not used */ + u16 access; /* not used */ + u16 ext_type; /* extended type */ + u16 device_id; /* device ID */ + u16 sub_device_id; /* sub device ID */ } gdth_ioctl_ctrtype; /* GDTIOCTL_EVENT */ typedef struct { - ushort ionode; + u16 ionode; int erase; /* erase event? */ int handle; /* event handle */ gdth_evt_str event; @@ -326,22 +318,22 @@ typedef struct { /* GDTIOCTL_RESCAN/GDTIOCTL_HDRLIST */ typedef struct { - ushort ionode; /* controller number */ - unchar flag; /* add/remove */ - ushort hdr_no; /* drive no. */ + u16 ionode; /* controller number */ + u8 flag; /* add/remove */ + u16 hdr_no; /* drive no. */ struct { - unchar bus; /* SCSI bus */ - unchar target; /* target ID */ - unchar lun; /* LUN */ - unchar cluster_type; /* cluster properties */ + u8 bus; /* SCSI bus */ + u8 target; /* target ID */ + u8 lun; /* LUN */ + u8 cluster_type; /* cluster properties */ } hdr_list[MAX_HDRIVES]; /* index is host drive number */ } gdth_ioctl_rescan; /* GDTIOCTL_RESET_BUS/GDTIOCTL_RESET_DRV */ typedef struct { - ushort ionode; /* controller number */ - ushort number; /* bus/host drive number */ - ushort status; /* status */ + u16 ionode; /* controller number */ + u16 number; /* bus/host drive number */ + u16 status; /* status */ } gdth_ioctl_reset; #endif diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c index 1258da34fbc2..ffb2b21992ba 100644 --- a/drivers/scsi/gdth_proc.c +++ b/drivers/scsi/gdth_proc.c @@ -43,7 +43,7 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer, int i, found; gdth_cmd_str gdtcmd; gdth_cpar_str *pcpar; - ulong64 paddr; + u64 paddr; char cmnd[MAX_COMMAND_SIZE]; memset(cmnd, 0xff, 12); @@ -156,8 +156,8 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, off_t begin = 0,pos = 0; int id, i, j, k, sec, flag; int no_mdrv = 0, drv_no, is_mirr; - ulong32 cnt; - ulong64 paddr; + u32 cnt; + u64 paddr; int rc = -ENOMEM; gdth_cmd_str *gdtcmd; @@ -220,14 +220,14 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, if (ha->more_proc) sprintf(hrec, "%d.%02d.%02d-%c%03X", - (unchar)(ha->binfo.upd_fw_ver>>24), - (unchar)(ha->binfo.upd_fw_ver>>16), - (unchar)(ha->binfo.upd_fw_ver), + (u8)(ha->binfo.upd_fw_ver>>24), + (u8)(ha->binfo.upd_fw_ver>>16), + (u8)(ha->binfo.upd_fw_ver), ha->bfeat.raid ? 'R':'N', ha->binfo.upd_revision); else - sprintf(hrec, "%d.%02d", (unchar)(ha->cpar.version>>8), - (unchar)(ha->cpar.version)); + sprintf(hrec, "%d.%02d", (u8)(ha->cpar.version>>8), + (u8)(ha->cpar.version)); size = sprintf(buffer+len, " Driver Ver.: \t%-10s\tFirmware Ver.: \t%s\n", @@ -281,7 +281,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, pds->bid = ha->raw[i].local_no; pds->first = 0; pds->entries = ha->raw[i].pdev_cnt; - cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(ulong32)) / + cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(u32)) / sizeof(pds->list[0]); if (pds->entries > cnt) pds->entries = cnt; @@ -604,7 +604,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, size = sprintf(buffer+len, " Capacity [MB]:\t%-6d \tStart Sector: \t%d\n", - (ulong32)(ha->hdr[i].size/2048), ha->hdr[i].start_sec); + (u32)(ha->hdr[i].size/2048), ha->hdr[i].start_sec); len += size; pos = begin + len; if (pos < offset) { len = 0; @@ -664,9 +664,9 @@ free_fail: } static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch, - ulong64 *paddr) + u64 *paddr) { - ulong flags; + unsigned long flags; char *ret_val; if (size == 0) @@ -691,9 +691,9 @@ static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch, return ret_val; } -static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr) +static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, u64 paddr) { - ulong flags; + unsigned long flags; if (buf == ha->pscratch) { spin_lock_irqsave(&ha->smp_lock, flags); @@ -705,16 +705,16 @@ static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr) } #ifdef GDTH_IOCTL_PROC -static int gdth_ioctl_check_bin(gdth_ha_str *ha, ushort size) +static int gdth_ioctl_check_bin(gdth_ha_str *ha, u16 size) { - ulong flags; + unsigned long flags; int ret_val; spin_lock_irqsave(&ha->smp_lock, flags); ret_val = FALSE; if (ha->scratch_busy) { - if (((gdth_iord_str *)ha->pscratch)->size == (ulong32)size) + if (((gdth_iord_str *)ha->pscratch)->size == (u32)size) ret_val = TRUE; } spin_unlock_irqrestore(&ha->smp_lock, flags); @@ -724,11 +724,11 @@ static int gdth_ioctl_check_bin(gdth_ha_str *ha, ushort size) static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id) { - ulong flags; + unsigned long flags; int i; Scsi_Cmnd *scp; struct gdth_cmndinfo *cmndinfo; - unchar b, t; + u8 b, t; spin_lock_irqsave(&ha->smp_lock, flags); @@ -738,8 +738,8 @@ static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id) b = scp->device->channel; t = scp->device->id; - if (!SPECIAL_SCP(scp) && t == (unchar)id && - b == (unchar)busnum) { + if (!SPECIAL_SCP(scp) && t == (u8)id && + b == (u8)busnum) { cmndinfo->wait_for_completion = 0; spin_unlock_irqrestore(&ha->smp_lock, flags); while (!cmndinfo->wait_for_completion) diff --git a/drivers/scsi/gdth_proc.h b/drivers/scsi/gdth_proc.h index 9b900cc9ebe8..dab15f59f2cc 100644 --- a/drivers/scsi/gdth_proc.h +++ b/drivers/scsi/gdth_proc.h @@ -17,8 +17,8 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer, int length, gdth_ha_str *ha); static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch, - ulong64 *paddr); -static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr); + u64 *paddr); +static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, u64 paddr); static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id); #endif -- cgit v1.2.2 From 7da5087971b1a187f92be4efb74a991ac9ccb0a3 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:04:12 +0530 Subject: [SCSI] be2iscsi: Use start cid and number of cid and icd from FW This patch enablesi be2iscsi to use the start number and number of cids/icd provided by FW rather than hard coded values. Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_iscsi.c | 7 +-- drivers/scsi/be2iscsi/be_main.c | 106 ++++++++++++++++++++++----------------- drivers/scsi/be2iscsi/be_main.h | 10 +--- drivers/scsi/be2iscsi/be_mgmt.c | 11 +++- 4 files changed, 75 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index d587b0362f18..2b3c58bd6529 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -431,9 +431,10 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, } SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn, ep_cid=%d ", beiscsi_ep->ep_cid); - phba->ep_array[beiscsi_ep->ep_cid] = ep; - if (beiscsi_ep->ep_cid > - (phba->fw_config.iscsi_cid_start + phba->params.cxns_per_ctrl)) { + phba->ep_array[beiscsi_ep->ep_cid - + phba->fw_config.iscsi_cid_start] = ep; + if (beiscsi_ep->ep_cid > (phba->fw_config.iscsi_cid_start + + phba->params.cxns_per_ctrl * 2)) { SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n"); return ret; } diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 1a557fa77888..6c512b6416c2 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -230,29 +230,27 @@ static int be_ctrl_init(struct beiscsi_hba *phba, struct pci_dev *pdev) static void beiscsi_get_params(struct beiscsi_hba *phba) { - phba->params.ios_per_ctrl = BE2_IO_DEPTH; - phba->params.cxns_per_ctrl = BE2_MAX_SESSIONS; - phba->params.asyncpdus_per_ctrl = BE2_ASYNCPDUS; - phba->params.icds_per_ctrl = BE2_MAX_ICDS / 2; + phba->params.ios_per_ctrl = (phba->fw_config.iscsi_icd_count + - (phba->fw_config.iscsi_cid_count + + BE2_TMFS + + BE2_NOPOUT_REQ)); + phba->params.cxns_per_ctrl = phba->fw_config.iscsi_cid_count; + phba->params.asyncpdus_per_ctrl = phba->fw_config.iscsi_cid_count;; + phba->params.icds_per_ctrl = phba->fw_config.iscsi_icd_count;; phba->params.num_sge_per_io = BE2_SGE; phba->params.defpdu_hdr_sz = BE2_DEFPDU_HDR_SZ; phba->params.defpdu_data_sz = BE2_DEFPDU_DATA_SZ; phba->params.eq_timer = 64; phba->params.num_eq_entries = - (((BE2_CMDS_PER_CXN * 2 + BE2_LOGOUTS + BE2_TMFS + BE2_ASYNCPDUS) / - 512) + 1) * 512; + (((BE2_CMDS_PER_CXN * 2 + phba->fw_config.iscsi_cid_count * 2 + + BE2_TMFS) / 512) + 1) * 512; phba->params.num_eq_entries = (phba->params.num_eq_entries < 1024) ? 1024 : phba->params.num_eq_entries; SE_DEBUG(DBG_LVL_8, "phba->params.num_eq_entries=%d \n", - phba->params.num_eq_entries); + phba->params.num_eq_entries); phba->params.num_cq_entries = - (((BE2_CMDS_PER_CXN * 2 + BE2_LOGOUTS + BE2_TMFS + BE2_ASYNCPDUS) / - 512) + 1) * 512; - SE_DEBUG(DBG_LVL_8, - "phba->params.num_cq_entries=%d BE2_CMDS_PER_CXN=%d" - "BE2_LOGOUTS=%d BE2_TMFS=%d BE2_ASYNCPDUS=%d \n", - phba->params.num_cq_entries, BE2_CMDS_PER_CXN, - BE2_LOGOUTS, BE2_TMFS, BE2_ASYNCPDUS); + (((BE2_CMDS_PER_CXN * 2 + phba->fw_config.iscsi_cid_count * 2 + + BE2_TMFS) / 512) + 1) * 512; phba->params.wrbs_per_cxn = 256; } @@ -877,7 +875,8 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, } else { pwrb_context = &phwi_ctrlr->wrb_context[((psol-> dw[offsetof(struct amap_sol_cqe, cid) / 32] & - SOL_CID_MASK) >> 6)]; + SOL_CID_MASK) >> 6) - + phba->fw_config.iscsi_cid_start]; pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> dw[offsetof(struct amap_sol_cqe, wrb_index) / 32] & SOL_WRB_INDEX_MASK) >> 16)]; @@ -939,7 +938,8 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, pwrb_context = &phwi_ctrlr-> wrb_context[((psol->dw[offsetof (struct amap_sol_cqe, cid) / 32] - & SOL_CID_MASK) >> 6)]; + & SOL_CID_MASK) >> 6) - + phba->fw_config.iscsi_cid_start]; pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> dw[offsetof(struct amap_sol_cqe, wrb_index) / 32] & SOL_WRB_INDEX_MASK) >> 16)]; @@ -1077,7 +1077,8 @@ hwi_get_async_handle(struct beiscsi_hba *phba, WARN_ON(!pasync_handle); - pasync_handle->cri = (unsigned short)beiscsi_conn->beiscsi_conn_cid; + pasync_handle->cri = (unsigned short)beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start; pasync_handle->is_header = is_header; pasync_handle->buffer_len = ((pdpdu_cqe-> dw[offsetof(struct amap_i_t_dpdu_cqe, dpl) / 32] @@ -1327,9 +1328,10 @@ hwi_fwd_async_msg(struct beiscsi_conn *beiscsi_conn, } status = beiscsi_process_async_pdu(beiscsi_conn, phba, - beiscsi_conn->beiscsi_conn_cid, - phdr, hdr_len, pfirst_buffer, - buf_len); + (beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start), + phdr, hdr_len, pfirst_buffer, + buf_len); if (status == 0) hwi_free_async_msg(phba, cri); @@ -1456,10 +1458,10 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) } } else { - beiscsi_conn = phba->conn_table[(u32) (sol-> + beiscsi_conn = phba->conn_table[(u32) ((sol-> dw[offsetof(struct amap_sol_cqe, cid) / 32] & - SOL_CID_MASK) >> 6]; - + SOL_CID_MASK) >> 6) - + phba->fw_config.iscsi_cid_start]; if (!beiscsi_conn || !beiscsi_conn->ep) { shost_printk(KERN_WARNING, phba->shost, "Connection table empty for cid = %d\n", @@ -1557,8 +1559,8 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) "0x%x...\n", sol->dw[offsetof(struct amap_sol_cqe, code) / 32] & CQE_CODE_MASK, - sol->dw[offsetof(struct amap_sol_cqe, cid) / - 32] & CQE_CID_MASK); + (sol->dw[offsetof(struct amap_sol_cqe, cid) / + 32] & CQE_CID_MASK)); } iscsi_conn_failure(beiscsi_conn->conn, ISCSI_ERR_CONN_FAILED); @@ -1575,8 +1577,8 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) "received/sent on CID 0x%x...\n", sol->dw[offsetof(struct amap_sol_cqe, code) / 32] & CQE_CODE_MASK, - sol->dw[offsetof(struct amap_sol_cqe, cid) / - 32] & CQE_CID_MASK); + (sol->dw[offsetof(struct amap_sol_cqe, cid) / + 32] & CQE_CID_MASK)); } iscsi_conn_failure(beiscsi_conn->conn, ISCSI_ERR_CONN_FAILED); @@ -1586,8 +1588,8 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) "received on CID 0x%x...\n", sol->dw[offsetof(struct amap_sol_cqe, code) / 32] & CQE_CODE_MASK, - sol->dw[offsetof(struct amap_sol_cqe, cid) / - 32] & CQE_CID_MASK); + (sol->dw[offsetof(struct amap_sol_cqe, cid) / + 32] & CQE_CID_MASK)); break; } @@ -2383,7 +2385,7 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba, &paddr); if (!cq_vaddress) goto create_cq_error; - ret = be_fill_queue(cq, phba->params.icds_per_ctrl / 2, + ret = be_fill_queue(cq, phba->params.num_cq_entries, sizeof(struct sol_cqe), cq_vaddress); if (ret) { shost_printk(KERN_ERR, phba->shost, @@ -2634,7 +2636,8 @@ beiscsi_create_wrb_rings(struct beiscsi_hba *phba, "wrbq create failed."); return status; } - phwi_ctrlr->wrb_context[i].cid = phwi_context->be_wrbq[i].id; + phwi_ctrlr->wrb_context[i * 2].cid = phwi_context->be_wrbq[i]. + id; } kfree(pwrb_arr); return 0; @@ -2807,12 +2810,6 @@ static int hwi_init_port(struct beiscsi_hba *phba) ring_mode = 1; else ring_mode = 0; - status = mgmt_get_fw_config(ctrl, phba); - if (status != 0) { - shost_printk(KERN_ERR, phba->shost, - "Error getting fw config\n"); - goto error; - } status = beiscsi_create_cqs(phba, phwi_context); if (status != 0) { @@ -3032,7 +3029,7 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba) AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, pfrag, 0); pfrag += phba->params.num_sge_per_io; psgl_handle->sgl_index = - phba->fw_config.iscsi_cid_start + arr_index++; + phba->fw_config.iscsi_icd_start + arr_index++; } idx++; } @@ -3064,7 +3061,7 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) kfree(phba->cid_array); return -ENOMEM; } - new_cid = phba->fw_config.iscsi_icd_start; + new_cid = phba->fw_config.iscsi_cid_start; for (i = 0; i < phba->params.cxns_per_ctrl; i++) { phba->cid_array[i] = new_cid; new_cid += 2; @@ -3219,7 +3216,8 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, * We can always use 0 here because it is reserved by libiscsi for * login/startup related tasks. */ - pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid, 0); + pwrb_handle = alloc_wrb_handle(phba, (beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start), 0); pwrb = (struct iscsi_target_context_update_wrb *)pwrb_handle->pwrb; memset(pwrb, 0, sizeof(*pwrb)); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, @@ -3328,7 +3326,8 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) io_task->bhs_pa.u.a64.address = paddr; io_task->libiscsi_itt = (itt_t)task->itt; io_task->pwrb_handle = alloc_wrb_handle(phba, - beiscsi_conn->beiscsi_conn_cid, + beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start, task->itt); io_task->conn = beiscsi_conn; @@ -3372,10 +3371,11 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) (io_task->psgl_handle->sgl_index)); if (ring_mode) { phba->sgl_hndl_array[io_task->psgl_handle->sgl_index - - phba->fw_config.iscsi_cid_start] = + phba->fw_config.iscsi_icd_start] = io_task->psgl_handle; io_task->psgl_handle->task = task; - io_task->psgl_handle->cid = beiscsi_conn->beiscsi_conn_cid; + io_task->psgl_handle->cid = beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start; } else io_task->pwrb_handle->pio_handle = task; @@ -3384,7 +3384,9 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) free_hndls: phwi_ctrlr = phba->phwi_ctrlr; - pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid]; + pwrb_context = &phwi_ctrlr->wrb_context[ + beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start]; free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle); io_task->pwrb_handle = NULL; pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs, @@ -3404,7 +3406,8 @@ static void beiscsi_cleanup_task(struct iscsi_task *task) struct hwi_controller *phwi_ctrlr; phwi_ctrlr = phba->phwi_ctrlr; - pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid]; + pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid + - phba->fw_config.iscsi_cid_start]; if (io_task->pwrb_handle) { free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle); io_task->pwrb_handle = NULL; @@ -3561,7 +3564,8 @@ static int beiscsi_mtask(struct iscsi_task *task) session = conn->session; i = ((struct iscsi_tm *)task->hdr)->rtt; phwi_ctrlr = phba->phwi_ctrlr; - pwrb_context = &phwi_ctrlr->wrb_context[cid]; + pwrb_context = &phwi_ctrlr->wrb_context[cid - + phba->fw_config.iscsi_cid_start]; pwrb_handle = pwrb_context->pwrb_handle_basestd[be32_to_cpu(i) >> 16]; aborted_task = pwrb_handle->pio_handle; @@ -3754,6 +3758,14 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, spin_lock_init(&phba->io_sgl_lock); spin_lock_init(&phba->mgmt_sgl_lock); spin_lock_init(&phba->isr_lock); + ret = mgmt_get_fw_config(&phba->ctrl, phba); + if (ret != 0) { + shost_printk(KERN_ERR, phba->shost, + "Error getting fw config\n"); + goto free_port; + } + phba->shost->max_id = phba->fw_config.iscsi_cid_count; + phba->shost->can_queue = phba->params.ios_per_ctrl; beiscsi_get_params(phba); ret = beiscsi_init_port(phba); if (ret < 0) { @@ -3859,7 +3871,7 @@ struct iscsi_transport beiscsi_iscsi_transport = { ISCSI_USERNAME | ISCSI_PASSWORD | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | - ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO | + ISCSI_LU_RESET_TMO | ISCSI_PING_TMO | ISCSI_RECV_TMO | ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME, .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 25e6b208b771..0e2eac627bee 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -46,23 +46,18 @@ #define OC_DEVICE_ID3 0x712 #define OC_DEVICE_ID4 0x222 -#define BE2_MAX_SESSIONS 64 +#define BE2_IO_DEPTH 1024 +#define BE2_MAX_SESSIONS 256 #define BE2_CMDS_PER_CXN 128 -#define BE2_LOGOUTS BE2_MAX_SESSIONS #define BE2_TMFS 16 #define BE2_NOPOUT_REQ 16 -#define BE2_ASYNCPDUS BE2_MAX_SESSIONS -#define BE2_MAX_ICDS 2048 #define BE2_SGE 32 #define BE2_DEFPDU_HDR_SZ 64 #define BE2_DEFPDU_DATA_SZ 8192 -#define BE2_IO_DEPTH \ - (BE2_MAX_ICDS / 2 - (BE2_LOGOUTS + BE2_TMFS + BE2_NOPOUT_REQ)) #define MAX_CPUS 31 #define BEISCSI_SGLIST_ELEMENTS BE2_SGE -#define BEISCSI_MAX_CMNDS 1024 /* Max IO's per Ctrlr sht->can_queue */ #define BEISCSI_CMD_PER_LUN 128 /* scsi_host->cmd_per_lun */ #define BEISCSI_MAX_SECTORS 2048 /* scsi_host->max_sectors */ @@ -802,7 +797,6 @@ struct hwi_controller { struct be_ring default_pdu_hdr; struct be_ring default_pdu_data; struct hwi_context_memory *phwi_ctxt; - unsigned short cq_errors[CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN]; }; enum hwh_type_enum { diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 79c2bd525a84..df1b327fe17b 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -48,6 +48,14 @@ unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl, pfw_cfg->ulp[0].sq_base; phba->fw_config.iscsi_cid_count = pfw_cfg->ulp[0].sq_count; + if (phba->fw_config.iscsi_cid_count > (BE2_MAX_SESSIONS / 2)) { + status = 1; + shost_printk(KERN_WARNING, phba->shost, + "FW reported MAX CXNS as %d \t" + "Max Supported = %d. Failing to load \n", + phba->fw_config.iscsi_cid_count, + BE2_MAX_SESSIONS); + } } else { shost_printk(KERN_WARNING, phba->shost, "Failed in mgmt_get_fw_config \n"); @@ -317,7 +325,8 @@ int mgmt_open_connection(struct beiscsi_hba *phba, struct tcp_connect_and_offload_out *ptcpcnct_out = embedded_payload(wrb); - ep = phba->ep_array[ptcpcnct_out->cid]; + ep = phba->ep_array[ptcpcnct_out->cid - + phba->fw_config.iscsi_cid_start]; beiscsi_ep = ep->dd_data; beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle; beiscsi_ep->cid_vld = 1; -- cgit v1.2.2 From c24622886fb934313a2a43ea1f516cbf1ddd947b Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:05:34 +0530 Subject: [SCSI] be2iscsi: Move freeing of resources to stop_conn We need to hold on to ep resources untill invalidate and close connection are completed Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_iscsi.c | 23 ++++++++++------------- drivers/scsi/be2iscsi/be_main.c | 31 ++++++++++--------------------- drivers/scsi/be2iscsi/be_mgmt.h | 1 + 3 files changed, 21 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 2b3c58bd6529..f22918427a2e 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -460,14 +460,12 @@ static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid) * beiscsi_free_ep - free endpoint * @ep: pointer to iscsi endpoint structure */ -static void beiscsi_free_ep(struct iscsi_endpoint *ep) +static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep) { - struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; struct beiscsi_hba *phba = beiscsi_ep->phba; beiscsi_put_cid(phba, beiscsi_ep->ep_cid); beiscsi_ep->phba = NULL; - iscsi_destroy_endpoint(ep); } /** @@ -498,7 +496,7 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, if (phba->state) { ret = -EBUSY; - SE_DEBUG(DBG_LVL_1, "The Adapet state is Not UP \n"); + SE_DEBUG(DBG_LVL_1, "The Adapter state is Not UP \n"); return ERR_PTR(ret); } @@ -510,9 +508,10 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, beiscsi_ep = ep->dd_data; beiscsi_ep->phba = phba; + beiscsi_ep->openiscsi_ep = ep; if (beiscsi_open_conn(ep, NULL, dst_addr, non_blocking)) { - SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n"); + SE_DEBUG(DBG_LVL_1, "Failed in beiscsi_open_conn \n"); ret = -ENOMEM; goto free_ep; } @@ -520,7 +519,7 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, return ep; free_ep: - beiscsi_free_ep(ep); + beiscsi_free_ep(beiscsi_ep); return ERR_PTR(ret); } @@ -547,15 +546,14 @@ int beiscsi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) * @ep: The iscsi endpoint * @flag: The type of connection closure */ -static int beiscsi_close_conn(struct iscsi_endpoint *ep, int flag) +static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag) { int ret = 0; - struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; struct beiscsi_hba *phba = beiscsi_ep->phba; if (MGMT_STATUS_SUCCESS != mgmt_upload_connection(phba, beiscsi_ep->ep_cid, - CONNECTION_UPLOAD_GRACEFUL)) { + flag)) { SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x", beiscsi_ep->ep_cid); ret = -1; @@ -575,19 +573,15 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) struct beiscsi_conn *beiscsi_conn; struct beiscsi_endpoint *beiscsi_ep; struct beiscsi_hba *phba; - int flag = 0; beiscsi_ep = ep->dd_data; phba = beiscsi_ep->phba; - SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect\n"); if (beiscsi_ep->conn) { beiscsi_conn = beiscsi_ep->conn; iscsi_suspend_queue(beiscsi_conn->conn); - beiscsi_close_conn(ep, flag); } - beiscsi_free_ep(ep); } /** @@ -637,6 +631,9 @@ void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) "mgmt_invalidate_connection Failed for cid=%d \n", beiscsi_ep->ep_cid); } + beiscsi_close_conn(beiscsi_ep, CONNECTION_UPLOAD_GRACEFUL); + beiscsi_free_ep(beiscsi_ep); + iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep); beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid); iscsi_conn_stop(cls_conn, flag); } diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 6c512b6416c2..139002395d99 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1434,6 +1434,8 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) unsigned int tot_nump = 0; struct beiscsi_conn *beiscsi_conn; struct sgl_handle *psgl_handle = NULL; + struct beiscsi_endpoint *beiscsi_ep; + struct iscsi_endpoint *ep; struct beiscsi_hba *phba; cq = pbe_eq->cq; @@ -1449,28 +1451,15 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) dw[offsetof(struct amap_sol_cqe_ring, icd_index) / 32] & SOL_ICD_INDEX_MASK) >> 6)]; - beiscsi_conn = phba->conn_table[psgl_handle->cid]; - if (!beiscsi_conn || !beiscsi_conn->ep) { - shost_printk(KERN_WARNING, phba->shost, - "Connection table empty for cid = %d\n", - psgl_handle->cid); - return 0; - } - + ep = phba->ep_array[psgl_handle->cid]; } else { - beiscsi_conn = phba->conn_table[(u32) ((sol-> - dw[offsetof(struct amap_sol_cqe, cid) / 32] & - SOL_CID_MASK) >> 6) - + ep = phba->ep_array[(u32) ((sol-> + dw[offsetof(struct amap_sol_cqe, cid) / 32] & + SOL_CID_MASK) >> 6) - phba->fw_config.iscsi_cid_start]; - if (!beiscsi_conn || !beiscsi_conn->ep) { - shost_printk(KERN_WARNING, phba->shost, - "Connection table empty for cid = %d\n", - (u32)(sol->dw[offsetof(struct amap_sol_cqe, - cid) / 32] & SOL_CID_MASK) >> 6); - return 0; - } } - + beiscsi_ep = ep->dd_data; + beiscsi_conn = beiscsi_ep->conn; if (num_processed >= 32) { hwi_ring_cq_db(phba, cq->id, num_processed, 0, 0); @@ -3044,7 +3033,7 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) { int i, new_cid; - phba->cid_array = kmalloc(sizeof(void *) * phba->params.cxns_per_ctrl, + phba->cid_array = kzalloc(sizeof(void *) * phba->params.cxns_per_ctrl, GFP_KERNEL); if (!phba->cid_array) { shost_printk(KERN_ERR, phba->shost, @@ -3052,7 +3041,7 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) "hba_setup_cid_tbls\n"); return -ENOMEM; } - phba->ep_array = kmalloc(sizeof(struct iscsi_endpoint *) * + phba->ep_array = kzalloc(sizeof(struct iscsi_endpoint *) * phba->params.cxns_per_ctrl * 2, GFP_KERNEL); if (!phba->ep_array) { shost_printk(KERN_ERR, phba->shost, diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index 24eaff923f85..6bc59e8e1fe5 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -231,6 +231,7 @@ struct beiscsi_endpoint { struct beiscsi_hba *phba; struct beiscsi_sess *sess; struct beiscsi_conn *conn; + struct iscsi_endpoint *openiscsi_ep; unsigned short ip_type; char dst6_addr[ISCSI_ADDRESS_BUF_LEN]; unsigned long dst_addr; -- cgit v1.2.2 From d543148883f65c34e6cd54c5e9ed0592dfbb6acb Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:06:21 +0530 Subject: [SCSI] be2iscsi: Link Wrb with next Wrb This patch will link the current allocated wrb with the next wrb that will be allocated. This is a requirement from the chip. Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 19 ++++++++++--------- drivers/scsi/be2iscsi/be_main.h | 3 +-- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 139002395d99..ac76b14ec4c1 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -629,29 +629,30 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) * alloc_wrb_handle - To allocate a wrb handle * @phba: The hba pointer * @cid: The cid to use for allocation - * @index: index allocation and wrb index * * This happens under session_lock until submission to chip */ -struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid, - int index) +struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid) { struct hwi_wrb_context *pwrb_context; struct hwi_controller *phwi_ctrlr; - struct wrb_handle *pwrb_handle; + struct wrb_handle *pwrb_handle, *pwrb_handle_tmp; phwi_ctrlr = phba->phwi_ctrlr; pwrb_context = &phwi_ctrlr->wrb_context[cid]; - if (pwrb_context->wrb_handles_available) { + if (pwrb_context->wrb_handles_available >= 2) { pwrb_handle = pwrb_context->pwrb_handle_base[ pwrb_context->alloc_index]; pwrb_context->wrb_handles_available--; - pwrb_handle->nxt_wrb_index = pwrb_handle->wrb_index; if (pwrb_context->alloc_index == (phba->params.wrbs_per_cxn - 1)) pwrb_context->alloc_index = 0; else pwrb_context->alloc_index++; + + pwrb_handle_tmp = pwrb_context->pwrb_handle_base[ + pwrb_context->alloc_index]; + pwrb_handle->nxt_wrb_index = pwrb_handle_tmp->wrb_index; } else pwrb_handle = NULL; return pwrb_handle; @@ -3206,7 +3207,7 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, * login/startup related tasks. */ pwrb_handle = alloc_wrb_handle(phba, (beiscsi_conn->beiscsi_conn_cid - - phba->fw_config.iscsi_cid_start), 0); + phba->fw_config.iscsi_cid_start)); pwrb = (struct iscsi_target_context_update_wrb *)pwrb_handle->pwrb; memset(pwrb, 0, sizeof(*pwrb)); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, @@ -3316,8 +3317,8 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) io_task->libiscsi_itt = (itt_t)task->itt; io_task->pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid - - phba->fw_config.iscsi_cid_start, - task->itt); + phba->fw_config.iscsi_cid_start + ); io_task->conn = beiscsi_conn; task->hdr = (struct iscsi_hdr *)&io_task->cmd_bhs->iscsi_hdr; diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 0e2eac627bee..0553f49db9be 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -651,8 +651,7 @@ struct amap_iscsi_wrb { } __packed; -struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid, - int index); +struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid); void free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle); -- cgit v1.2.2 From 7bd6e25cdbee7d4f6bc4946dc914310220e637b8 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:07:02 +0530 Subject: [SCSI] be2iscsi: Added opcode for LOGOUT_RSP, TEXT_RESP, TMFUNC_RSP This patch adds opcodes in thecompletion path that were missed out earlier Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index ac76b14ec4c1..4a855a9c7126 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -559,6 +559,7 @@ beiscsi_process_async_pdu(struct beiscsi_conn *beiscsi_conn, SE_DEBUG(DBG_LVL_1, "In ISCSI_OP_REJECT\n"); break; case ISCSI_OP_LOGIN_RSP: + case ISCSI_OP_TEXT_RSP: task = conn->login_task; io_task = task->dd_data; login_hdr = (struct iscsi_hdr *)ppdu; @@ -810,6 +811,7 @@ be_complete_logout(struct beiscsi_conn *beiscsi_conn, struct iscsi_conn *conn = beiscsi_conn->conn; hdr = (struct iscsi_logout_rsp *)task->hdr; + hdr->opcode = ISCSI_OP_LOGOUT_RSP; hdr->t2wait = 5; hdr->t2retain = 0; hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32] @@ -824,6 +826,9 @@ be_complete_logout(struct beiscsi_conn *beiscsi_conn, & SOL_EXP_CMD_SN_MASK) + ((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd) / 32] & SOL_CMD_WND_MASK) >> 24) - 1); + hdr->dlength[0] = 0; + hdr->dlength[1] = 0; + hdr->dlength[2] = 0; hdr->hlength = 0; hdr->itt = io_task->libiscsi_itt; __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); @@ -838,6 +843,7 @@ be_complete_tmf(struct beiscsi_conn *beiscsi_conn, struct beiscsi_io_task *io_task = task->dd_data; hdr = (struct iscsi_tm_rsp *)task->hdr; + hdr->opcode = ISCSI_OP_SCSI_TMFUNC_RSP; hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32] & SOL_FLAGS_MASK) >> 24) | 0x80; hdr->response = (psol->dw[offsetof(struct amap_sol_cqe, i_resp) / -- cgit v1.2.2 From 2807afb7411b97834fc7338f3735f3d152443551 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:07:49 +0530 Subject: [SCSI] be2iscsi:moved pci_set_drvdata to inside beiscsi_hba_alloc This patch moves pci_set_drvdata to inside beiscsi_hba_alloc Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 4a855a9c7126..18471ede7f80 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -112,6 +112,7 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev) memset(phba, 0, sizeof(*phba)); phba->shost = shost; phba->pcidev = pci_dev_get(pcidev); + pci_set_drvdata(pcidev, phba); if (iscsi_host_add(shost, &phba->pcidev->dev)) goto free_devices; @@ -3734,7 +3735,6 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, } SE_DEBUG(DBG_LVL_8, " phba = %p \n", phba); - pci_set_drvdata(pcidev, phba); if (enable_msix) num_cpus = find_num_cpus(); else -- cgit v1.2.2 From d7aea67b8a7665fe5e53cdf59ba76c9b8d67b751 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:08:39 +0530 Subject: [SCSI] be2iscsi: Use of opcode in beiscsi_alloc_pdu This patch enables use of opcode that is passed in Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 18471ede7f80..0fae26468a09 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3339,7 +3339,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) goto free_hndls; } else { io_task->scsi_cmnd = NULL; - if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) { + if ((opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) { if (!beiscsi_conn->login_in_progress) { spin_lock(&phba->mgmt_sgl_lock); io_task->psgl_handle = (struct sgl_handle *) -- cgit v1.2.2 From 0ecb0b45f22df911c564070b64af21db36934f0f Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:09:19 +0530 Subject: [SCSI] be2iscsi: decide which requests need completion This patch decides whether ack based completion is required or not Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 0fae26468a09..26d7016492da 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3546,6 +3546,11 @@ static int beiscsi_mtask(struct iscsi_task *task) else AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_RD_CMD); + if (task->hdr->ttt == ISCSI_RESERVED_TAG) + AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); + else + AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 1); + hwi_write_buffer(pwrb, task); break; case ISCSI_OP_TEXT: @@ -3554,6 +3559,7 @@ static int beiscsi_mtask(struct iscsi_task *task) else AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_WR_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1); hwi_write_buffer(pwrb, task); break; -- cgit v1.2.2 From 51a462500fbed4a1e8110dc60a421a3f12b9580b Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:10:01 +0530 Subject: [SCSI] be2iscsi: No requirement for endianess change for data_count This patch removes the endianess change that was wrongly added for data_count Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 26d7016492da..6170548a5289 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3607,7 +3607,7 @@ static int beiscsi_mtask(struct iscsi_task *task) } AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb, - be32_to_cpu(task->data_count)); + task->data_count); AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb, io_task->pwrb_handle->nxt_wrb_index); be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb)); -- cgit v1.2.2 From 756d29c8c7ed8887ed7d752371ce2f6d12399267 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:10:46 +0530 Subject: [SCSI] be2iscsi: Enable async mode for mcc rings This patches enables async mode for mcc rings so that multiple requests can be queued. Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be.h | 16 ++++- drivers/scsi/be2iscsi/be_cmds.c | 82 ++++++++++++++++++++++--- drivers/scsi/be2iscsi/be_cmds.h | 12 +++- drivers/scsi/be2iscsi/be_iscsi.c | 100 ++++++++++++++++++++++++++---- drivers/scsi/be2iscsi/be_main.c | 83 ++++++++++++++++++++++--- drivers/scsi/be2iscsi/be_main.h | 2 + drivers/scsi/be2iscsi/be_mgmt.c | 128 +++++++++++++++++++++------------------ drivers/scsi/be2iscsi/be_mgmt.h | 3 - 8 files changed, 330 insertions(+), 96 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h index a93a5040f087..3861cf44dc15 100644 --- a/drivers/scsi/be2iscsi/be.h +++ b/drivers/scsi/be2iscsi/be.h @@ -24,6 +24,7 @@ #define FW_VER_LEN 32 #define MCC_Q_LEN 128 #define MCC_CQ_LEN 256 +#define MAX_MCC_CMD 16 struct be_dma_mem { void *va; @@ -57,6 +58,11 @@ static inline void *queue_head_node(struct be_queue_info *q) return q->dma_mem.va + q->head * q->entry_size; } +static inline void *queue_get_wrb(struct be_queue_info *q, unsigned int wrb_num) +{ + return q->dma_mem.va + wrb_num * q->entry_size; +} + static inline void *queue_tail_node(struct be_queue_info *q) { return q->dma_mem.va + q->tail * q->entry_size; @@ -104,15 +110,19 @@ struct be_ctrl_info { spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */ spinlock_t mcc_cq_lock; - /* MCC Async callback */ - void (*async_cb) (void *adapter, bool link_up); - void *adapter_ctxt; + wait_queue_head_t mcc_wait[MAX_MCC_CMD + 1]; + unsigned int mcc_tag[MAX_MCC_CMD]; + unsigned int mcc_numtag[MAX_MCC_CMD + 1]; + unsigned short mcc_alloc_index; + unsigned short mcc_free_index; + unsigned int mcc_tag_available; }; #include "be_cmds.h" #define PAGE_SHIFT_4K 12 #define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K) +#define mcc_timeout 120000 /* 5s timeout */ /* Returns number of pages spanned by the data starting at the given addr */ #define PAGES_4K_SPANNED(_address, size) \ diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index f008708f1b08..d4a0d1da4875 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -19,7 +19,7 @@ #include "be_mgmt.h" #include "be_main.h" -static void be_mcc_notify(struct beiscsi_hba *phba) +void be_mcc_notify(struct beiscsi_hba *phba) { struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; u32 val = 0; @@ -29,6 +29,52 @@ static void be_mcc_notify(struct beiscsi_hba *phba) iowrite32(val, phba->db_va + DB_MCCQ_OFFSET); } +unsigned int alloc_mcc_tag(struct beiscsi_hba *phba) +{ + unsigned int tag = 0; + unsigned int num = 0; + +mcc_tag_rdy: + if (phba->ctrl.mcc_tag_available) { + tag = phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index]; + phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index] = 0; + phba->ctrl.mcc_numtag[tag] = 0; + } else { + udelay(100); + num++; + if (num < mcc_timeout) + goto mcc_tag_rdy; + } + if (tag) { + phba->ctrl.mcc_tag_available--; + if (phba->ctrl.mcc_alloc_index == (MAX_MCC_CMD - 1)) + phba->ctrl.mcc_alloc_index = 0; + else + phba->ctrl.mcc_alloc_index++; + } + return tag; +} + +void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag) +{ + spin_lock(&ctrl->mbox_lock); + tag = tag & 0x000000FF; + ctrl->mcc_tag[ctrl->mcc_free_index] = tag; + if (ctrl->mcc_free_index == (MAX_MCC_CMD - 1)) + ctrl->mcc_free_index = 0; + else + ctrl->mcc_free_index++; + ctrl->mcc_tag_available++; + spin_unlock(&ctrl->mbox_lock); +} + +bool is_link_state_evt(u32 trailer) +{ + return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) & + ASYNC_TRAILER_EVENT_CODE_MASK) == + ASYNC_EVENT_CODE_LINK_STATE); +} + static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl) { if (compl->flags != 0) { @@ -64,12 +110,30 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl, return 0; } - -static inline bool is_link_state_evt(u32 trailer) +int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl, + struct be_mcc_compl *compl) { - return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) & - ASYNC_TRAILER_EVENT_CODE_MASK) == - ASYNC_EVENT_CODE_LINK_STATE); + u16 compl_status, extd_status; + unsigned short tag; + + be_dws_le_to_cpu(compl, 4); + + compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) & + CQE_STATUS_COMPL_MASK; + /* The ctrl.mcc_numtag[tag] is filled with + * [31] = valid, [30:24] = Rsvd, [23:16] = wrb, [15:8] = extd_status, + * [7:0] = compl_status + */ + tag = (compl->tag0 & 0x000000FF); + extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) & + CQE_STATUS_EXTD_MASK; + + ctrl->mcc_numtag[tag] = 0x80000000; + ctrl->mcc_numtag[tag] |= (compl->tag0 & 0x00FF0000); + ctrl->mcc_numtag[tag] |= (extd_status & 0x000000FF) << 8; + ctrl->mcc_numtag[tag] |= (compl_status & 0x000000FF); + wake_up_interruptible(&ctrl->mcc_wait[tag]); + return 0; } static struct be_mcc_compl *be_mcc_compl_get(struct beiscsi_hba *phba) @@ -89,7 +153,7 @@ static void be2iscsi_fail_session(struct iscsi_cls_session *cls_session) iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED); } -static void beiscsi_async_link_state_process(struct beiscsi_hba *phba, +void beiscsi_async_link_state_process(struct beiscsi_hba *phba, struct be_async_event_link_state *evt) { switch (evt->port_link_status) { @@ -162,7 +226,6 @@ int beiscsi_process_mcc(struct beiscsi_hba *phba) /* Wait till no more pending mcc requests are present */ static int be_mcc_wait_compl(struct beiscsi_hba *phba) { -#define mcc_timeout 120000 /* 5s timeout */ int i, status; for (i = 0; i < mcc_timeout; i++) { status = beiscsi_process_mcc(phba); @@ -372,9 +435,10 @@ struct be_mcc_wrb *wrb_from_mccq(struct beiscsi_hba *phba) BUG_ON(atomic_read(&mccq->used) >= mccq->len); wrb = queue_head_node(mccq); + memset(wrb, 0, sizeof(*wrb)); + wrb->tag0 = (mccq->head & 0x000000FF) << 16; queue_head_inc(mccq); atomic_inc(&mccq->used); - memset(wrb, 0, sizeof(*wrb)); return wrb; } diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index 5de8acb924cb..69dddfaebe59 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -425,14 +425,20 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba, int be_poll_mcc(struct be_ctrl_info *ctrl); unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba); -int be_cmd_get_mac_addr(struct beiscsi_hba *phba, u8 *mac_addr); - +unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba); +void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag); /*ISCSI Functuions */ int be_cmd_fw_initialize(struct be_ctrl_info *ctrl); struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem); struct be_mcc_wrb *wrb_from_mccq(struct beiscsi_hba *phba); int be_mcc_notify_wait(struct beiscsi_hba *phba); +void be_mcc_notify(struct beiscsi_hba *phba); +unsigned int alloc_mcc_tag(struct beiscsi_hba *phba); +void beiscsi_async_link_state_process(struct beiscsi_hba *phba, + struct be_async_event_link_state *evt); +int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl, + struct be_mcc_compl *compl); int be_mbox_notify(struct be_ctrl_info *ctrl); @@ -448,6 +454,8 @@ int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl, int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem, struct be_queue_info *wrbq); +bool is_link_state_evt(u32 trailer); + struct be_default_pdu_context { u32 dw[4]; } __packed; diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index f22918427a2e..95694d3d2089 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -101,6 +101,7 @@ void beiscsi_session_destroy(struct iscsi_cls_session *cls_session) struct iscsi_session *sess = cls_session->dd_data; struct beiscsi_session *beiscsi_sess = sess->dd_data; + SE_DEBUG(DBG_LVL_8, "In beiscsi_session_destroy\n"); pci_pool_destroy(beiscsi_sess->bhs_pool); iscsi_session_teardown(cls_session); } @@ -224,6 +225,7 @@ int beiscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, struct beiscsi_conn *beiscsi_conn = conn->dd_data; int len = 0; + SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_get_param, param= %d\n", param); beiscsi_ep = beiscsi_conn->ep; if (!beiscsi_ep) { SE_DEBUG(DBG_LVL_1, @@ -254,6 +256,7 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn, struct iscsi_session *session = conn->session; int ret; + SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_set_param, param= %d\n", param); ret = iscsi_set_param(cls_conn, param, buf, buflen); if (ret) return ret; @@ -293,12 +296,41 @@ int beiscsi_get_host_param(struct Scsi_Host *shost, enum iscsi_host_param param, char *buf) { struct beiscsi_hba *phba = (struct beiscsi_hba *)iscsi_host_priv(shost); + struct be_cmd_resp_get_mac_addr *resp; + struct be_mcc_wrb *wrb; + unsigned int tag, wrb_num; int len = 0; + unsigned short status, extd_status; + struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; + SE_DEBUG(DBG_LVL_8, "In beiscsi_get_host_param, param= %d\n", param); switch (param) { case ISCSI_HOST_PARAM_HWADDRESS: - be_cmd_get_mac_addr(phba, phba->mac_address); - len = sysfs_format_mac(buf, phba->mac_address, ETH_ALEN); + tag = be_cmd_get_mac_addr(phba); + if (!tag) { + SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed \n"); + return -1; + } else + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + + wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16; + extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; + status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; + if (status || extd_status) { + SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed" + " status = %d extd_status = %d \n", + status, extd_status); + free_mcc_tag(&phba->ctrl, tag); + return -1; + } else { + wrb = queue_get_wrb(mccq, wrb_num); + free_mcc_tag(&phba->ctrl, tag); + resp = embedded_payload(wrb); + memcpy(phba->mac_address, resp->mac_address, ETH_ALEN); + len = sysfs_format_mac(buf, phba->mac_address, + ETH_ALEN); + } break; default: return iscsi_host_get_param(shost, param, buf); @@ -378,6 +410,7 @@ int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn) struct beiscsi_endpoint *beiscsi_ep; struct beiscsi_offload_params params; + SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_start\n"); memset(¶ms, 0, sizeof(struct beiscsi_offload_params)); beiscsi_ep = beiscsi_conn->ep; if (!beiscsi_ep) @@ -422,8 +455,14 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, { struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; struct beiscsi_hba *phba = beiscsi_ep->phba; + struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; + struct be_mcc_wrb *wrb; + struct tcp_connect_and_offload_out *ptcpcnct_out; + unsigned short status, extd_status; + unsigned int tag, wrb_num; int ret = -1; + SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn\n"); beiscsi_ep->ep_cid = beiscsi_get_cid(phba); if (beiscsi_ep->ep_cid == 0xFFFF) { SE_DEBUG(DBG_LVL_1, "No free cid available\n"); @@ -440,7 +479,35 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, } beiscsi_ep->cid_vld = 0; - return mgmt_open_connection(phba, dst_addr, beiscsi_ep); + tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep); + if (!tag) { + SE_DEBUG(DBG_LVL_1, + "mgmt_invalidate_connection Failed for cid=%d \n", + beiscsi_ep->ep_cid); + } else { + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + } + wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16; + extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; + status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; + if (status || extd_status) { + SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed" + " status = %d extd_status = %d \n", + status, extd_status); + free_mcc_tag(&phba->ctrl, tag); + return -1; + } else { + wrb = queue_get_wrb(mccq, wrb_num); + free_mcc_tag(&phba->ctrl, tag); + + ptcpcnct_out = embedded_payload(wrb); + beiscsi_ep = ep->dd_data; + beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle; + beiscsi_ep->cid_vld = 1; + SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n"); + } + return 0; } /** @@ -509,7 +576,6 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, beiscsi_ep = ep->dd_data; beiscsi_ep->phba = phba; beiscsi_ep->openiscsi_ep = ep; - if (beiscsi_open_conn(ep, NULL, dst_addr, non_blocking)) { SE_DEBUG(DBG_LVL_1, "Failed in beiscsi_open_conn \n"); ret = -ENOMEM; @@ -549,16 +615,19 @@ int beiscsi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag) { int ret = 0; + unsigned int tag; struct beiscsi_hba *phba = beiscsi_ep->phba; - if (MGMT_STATUS_SUCCESS != - mgmt_upload_connection(phba, beiscsi_ep->ep_cid, - flag)) { + tag = mgmt_upload_connection(phba, beiscsi_ep->ep_cid, flag); + if (!tag) { SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x", beiscsi_ep->ep_cid); ret = -1; + } else { + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + free_mcc_tag(&phba->ctrl, tag); } - return ret; } @@ -576,6 +645,8 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) beiscsi_ep = ep->dd_data; phba = beiscsi_ep->phba; + SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect for ep_cid = %d\n", + beiscsi_ep->ep_cid); if (beiscsi_ep->conn) { beiscsi_conn = beiscsi_ep->conn; @@ -614,22 +685,27 @@ void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) struct iscsi_session *session = conn->session; struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session); struct beiscsi_hba *phba = iscsi_host_priv(shost); - unsigned int status; + unsigned int tag; unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH; - SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop\n"); beiscsi_ep = beiscsi_conn->ep; if (!beiscsi_ep) { SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop , no beiscsi_ep\n"); return; } - status = mgmt_invalidate_connection(phba, beiscsi_ep, + SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop ep_cid = %d\n", + beiscsi_ep->ep_cid); + tag = mgmt_invalidate_connection(phba, beiscsi_ep, beiscsi_ep->ep_cid, 1, savecfg_flag); - if (status != MGMT_STATUS_SUCCESS) { + if (!tag) { SE_DEBUG(DBG_LVL_1, "mgmt_invalidate_connection Failed for cid=%d \n", beiscsi_ep->ep_cid); + } else { + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + free_mcc_tag(&phba->ctrl, tag); } beiscsi_close_conn(beiscsi_ep, CONNECTION_UPLOAD_GRACEFUL); beiscsi_free_ep(beiscsi_ep); diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 6170548a5289..a6a2c6469677 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -442,7 +442,7 @@ static irqreturn_t be_isr(int irq, void *dev_id) if (phba->todo_mcc_cq) queue_work(phba->wq, &phba->work_cqs); - if ((num_mcceq_processed) && (!num_ioeq_processed)) + if ((num_mcceq_processed) && (!num_ioeq_processed)) hwi_ring_eq_db(phba, eq->id, 0, (num_ioeq_processed + num_mcceq_processed) , 1, 1); @@ -651,7 +651,6 @@ struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid) pwrb_context->alloc_index = 0; else pwrb_context->alloc_index++; - pwrb_handle_tmp = pwrb_context->pwrb_handle_base[ pwrb_context->alloc_index]; pwrb_handle->nxt_wrb_index = pwrb_handle_tmp->wrb_index; @@ -791,6 +790,7 @@ be_complete_io(struct beiscsi_conn *beiscsi_conn, memcpy(task->sc->sense_buffer, sense, min_t(u16, sense_len, SCSI_SENSE_BUFFERSIZE)); } + if (io_task->cmd_bhs->iscsi_hdr.flags & ISCSI_FLAG_CMD_READ) { if (psol->dw[offsetof(struct amap_sol_cqe, i_res_cnt) / 32] & SOL_RES_CNT_MASK) @@ -1432,6 +1432,48 @@ static void hwi_process_default_pdu_ring(struct beiscsi_conn *beiscsi_conn, hwi_post_async_buffers(phba, pasync_handle->is_header); } +static void beiscsi_process_mcc_isr(struct beiscsi_hba *phba) +{ + struct be_queue_info *mcc_cq; + struct be_mcc_compl *mcc_compl; + unsigned int num_processed = 0; + + mcc_cq = &phba->ctrl.mcc_obj.cq; + mcc_compl = queue_tail_node(mcc_cq); + mcc_compl->flags = le32_to_cpu(mcc_compl->flags); + while (mcc_compl->flags & CQE_FLAGS_VALID_MASK) { + + if (num_processed >= 32) { + hwi_ring_cq_db(phba, mcc_cq->id, + num_processed, 0, 0); + num_processed = 0; + } + if (mcc_compl->flags & CQE_FLAGS_ASYNC_MASK) { + /* Interpret flags as an async trailer */ + if (is_link_state_evt(mcc_compl->flags)) + /* Interpret compl as a async link evt */ + beiscsi_async_link_state_process(phba, + (struct be_async_event_link_state *) mcc_compl); + else + SE_DEBUG(DBG_LVL_1, + " Unsupported Async Event, flags" + " = 0x%08x \n", mcc_compl->flags); + } else if (mcc_compl->flags & CQE_FLAGS_COMPLETED_MASK) { + be_mcc_compl_process_isr(&phba->ctrl, mcc_compl); + atomic_dec(&phba->ctrl.mcc_obj.q.used); + } + + mcc_compl->flags = 0; + queue_tail_inc(mcc_cq); + mcc_compl = queue_tail_node(mcc_cq); + mcc_compl->flags = le32_to_cpu(mcc_compl->flags); + num_processed++; + } + + if (num_processed > 0) + hwi_ring_cq_db(phba, mcc_cq->id, num_processed, 1, 0); + +} static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) { @@ -1468,6 +1510,7 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) } beiscsi_ep = ep->dd_data; beiscsi_conn = beiscsi_ep->conn; + if (num_processed >= 32) { hwi_ring_cq_db(phba, cq->id, num_processed, 0, 0); @@ -1603,7 +1646,7 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) return tot_nump; } -static void beiscsi_process_all_cqs(struct work_struct *work) +void beiscsi_process_all_cqs(struct work_struct *work) { unsigned long flags; struct hwi_controller *phwi_ctrlr; @@ -1623,6 +1666,7 @@ static void beiscsi_process_all_cqs(struct work_struct *work) spin_lock_irqsave(&phba->isr_lock, flags); phba->todo_mcc_cq = 0; spin_unlock_irqrestore(&phba->isr_lock, flags); + beiscsi_process_mcc_isr(phba); } if (phba->todo_cq) { @@ -3160,6 +3204,7 @@ static void hwi_purge_eq(struct beiscsi_hba *phba) struct be_queue_info *eq; struct be_eq_entry *eqe = NULL; int i, eq_msix; + unsigned int num_processed; phwi_ctrlr = phba->phwi_ctrlr; phwi_context = phwi_ctrlr->phwi_ctxt; @@ -3171,13 +3216,17 @@ static void hwi_purge_eq(struct beiscsi_hba *phba) for (i = 0; i < (phba->num_cpus + eq_msix); i++) { eq = &phwi_context->be_eq[i].q; eqe = queue_tail_node(eq); - + num_processed = 0; while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] & EQE_VALID_MASK) { AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); queue_tail_inc(eq); eqe = queue_tail_node(eq); + num_processed++; } + + if (num_processed) + hwi_ring_eq_db(phba, eq->id, 1, num_processed, 1, 1); } } @@ -3189,8 +3238,9 @@ static void beiscsi_clean_port(struct beiscsi_hba *phba) if (mgmt_status) shost_printk(KERN_WARNING, phba->shost, "mgmt_epfw_cleanup FAILED \n"); - hwi_cleanup(phba); + hwi_purge_eq(phba); + hwi_cleanup(phba); if (ring_mode) kfree(phba->sgl_hndl_array); kfree(phba->io_sgl_hndl_base); @@ -3519,6 +3569,7 @@ static int beiscsi_mtask(struct iscsi_task *task) unsigned int doorbell = 0; unsigned int i, cid; struct iscsi_task *aborted_task; + unsigned int tag; cid = beiscsi_conn->beiscsi_conn_cid; pwrb = io_task->pwrb_handle->pwrb; @@ -3550,7 +3601,6 @@ static int beiscsi_mtask(struct iscsi_task *task) AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); else AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 1); - hwi_write_buffer(pwrb, task); break; case ISCSI_OP_TEXT: @@ -3579,9 +3629,18 @@ static int beiscsi_mtask(struct iscsi_task *task) if (!aborted_io_task->scsi_cmnd) return 0; - mgmt_invalidate_icds(phba, + tag = mgmt_invalidate_icds(phba, aborted_io_task->psgl_handle->sgl_index, cid); + if (!tag) { + shost_printk(KERN_WARNING, phba->shost, + "mgmt_invalidate_icds could not be" + " submitted\n"); + } else { + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + free_mcc_tag(&phba->ctrl, tag); + } if (ring_mode) io_task->psgl_handle->type = INI_TMF_CMD; else @@ -3656,7 +3715,6 @@ static int beiscsi_task_xmit(struct iscsi_task *task) return beiscsi_iotask(task, sg, num_sg, xferlen, writedir); } - static void beiscsi_remove(struct pci_dev *pcidev) { struct beiscsi_hba *phba = NULL; @@ -3776,6 +3834,15 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, goto free_port; } + for (i = 0; i < MAX_MCC_CMD ; i++) { + init_waitqueue_head(&phba->ctrl.mcc_wait[i + 1]); + phba->ctrl.mcc_tag[i] = i + 1; + phba->ctrl.mcc_numtag[i + 1] = 0; + phba->ctrl.mcc_tag_available++; + } + + phba->ctrl.mcc_alloc_index = phba->ctrl.mcc_free_index = 0; + snprintf(phba->wq_name, sizeof(phba->wq_name), "beiscsi_q_irq%u", phba->shost->host_no); phba->wq = create_workqueue(phba->wq_name); diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 0553f49db9be..4cde8f6eb5bc 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -655,6 +655,8 @@ struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid); void free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle); +void beiscsi_process_all_cqs(struct work_struct *work); + struct pdu_nop_out { u32 dw[12]; }; diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index df1b327fe17b..18f80411aef6 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -148,10 +148,17 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba, { struct be_dma_mem nonemb_cmd; struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mccq(phba); - struct be_sge *sge = nonembedded_sgl(wrb); + struct be_mcc_wrb *wrb; + struct be_sge *sge; struct invalidate_commands_params_in *req; - int status = 0; + unsigned int tag = 0; + + spin_lock(&ctrl->mbox_lock); + tag = alloc_mcc_tag(phba); + if (!tag) { + spin_unlock(&ctrl->mbox_lock); + return tag; + } nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev, sizeof(struct invalidate_commands_params_in), @@ -164,8 +171,9 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba, } nonemb_cmd.size = sizeof(struct invalidate_commands_params_in); req = nonemb_cmd.va; - spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); + wrb = wrb_from_mccq(phba); + sge = nonembedded_sgl(wrb); + wrb->tag0 |= tag; be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, @@ -180,14 +188,12 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba, sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF); sge->len = cpu_to_le32(nonemb_cmd.size); - status = be_mcc_notify_wait(phba); - if (status) - SE_DEBUG(DBG_LVL_1, "ICDS Invalidation Failed\n"); + be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); if (nonemb_cmd.va) pci_free_consistent(ctrl->pdev, nonemb_cmd.size, nonemb_cmd.va, nonemb_cmd.dma); - return status; + return tag; } unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba, @@ -197,13 +203,19 @@ unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba, unsigned short savecfg_flag) { struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mccq(phba); - struct iscsi_invalidate_connection_params_in *req = - embedded_payload(wrb); - int status = 0; + struct be_mcc_wrb *wrb; + struct iscsi_invalidate_connection_params_in *req; + unsigned int tag = 0; spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); + tag = alloc_mcc_tag(phba); + if (!tag) { + spin_unlock(&ctrl->mbox_lock); + return tag; + } + wrb = wrb_from_mccq(phba); + wrb->tag0 |= tag; + req = embedded_payload(wrb); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, @@ -216,35 +228,37 @@ unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba, else req->cleanup_type = CMD_ISCSI_CONNECTION_INVALIDATE; req->save_cfg = savecfg_flag; - status = be_mcc_notify_wait(phba); - if (status) - SE_DEBUG(DBG_LVL_1, "Invalidation Failed\n"); - + be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); - return status; + return tag; } unsigned char mgmt_upload_connection(struct beiscsi_hba *phba, unsigned short cid, unsigned int upload_flag) { struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mccq(phba); - struct tcp_upload_params_in *req = embedded_payload(wrb); - int status = 0; + struct be_mcc_wrb *wrb; + struct tcp_upload_params_in *req; + unsigned int tag = 0; spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); + tag = alloc_mcc_tag(phba); + if (!tag) { + spin_unlock(&ctrl->mbox_lock); + return tag; + } + wrb = wrb_from_mccq(phba); + req = embedded_payload(wrb); + wrb->tag0 |= tag; be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); be_cmd_hdr_prepare(&req->hdr, CMD_COMMON_TCP_UPLOAD, OPCODE_COMMON_TCP_UPLOAD, sizeof(*req)); req->id = (unsigned short)cid; req->upload_type = (unsigned char)upload_flag; - status = be_mcc_notify_wait(phba); - if (status) - SE_DEBUG(DBG_LVL_1, "mgmt_upload_connection Failed\n"); + be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); - return status; + return tag; } int mgmt_open_connection(struct beiscsi_hba *phba, @@ -256,13 +270,13 @@ int mgmt_open_connection(struct beiscsi_hba *phba, struct sockaddr_in *daddr_in = (struct sockaddr_in *)dst_addr; struct sockaddr_in6 *daddr_in6 = (struct sockaddr_in6 *)dst_addr; struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mccq(phba); - struct tcp_connect_and_offload_in *req = embedded_payload(wrb); + struct be_mcc_wrb *wrb; + struct tcp_connect_and_offload_in *req; unsigned short def_hdr_id; unsigned short def_data_id; struct phys_addr template_address = { 0, 0 }; struct phys_addr *ptemplate_address; - int status = 0; + unsigned int tag = 0; unsigned int i; unsigned short cid = beiscsi_ep->ep_cid; @@ -274,7 +288,14 @@ int mgmt_open_connection(struct beiscsi_hba *phba, ptemplate_address = &template_address; ISCSI_GET_PDU_TEMPLATE_ADDRESS(phba, ptemplate_address); spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); + tag = alloc_mcc_tag(phba); + if (!tag) { + spin_unlock(&ctrl->mbox_lock); + return tag; + } + wrb = wrb_from_mccq(phba); + req = embedded_payload(wrb); + wrb->tag0 |= tag; be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, @@ -319,47 +340,36 @@ int mgmt_open_connection(struct beiscsi_hba *phba, req->do_offload = 1; req->dataout_template_pa.lo = ptemplate_address->lo; req->dataout_template_pa.hi = ptemplate_address->hi; - status = be_mcc_notify_wait(phba); - if (!status) { - struct iscsi_endpoint *ep; - struct tcp_connect_and_offload_out *ptcpcnct_out = - embedded_payload(wrb); - - ep = phba->ep_array[ptcpcnct_out->cid - - phba->fw_config.iscsi_cid_start]; - beiscsi_ep = ep->dd_data; - beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle; - beiscsi_ep->cid_vld = 1; - SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n"); - } else - SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed\n"); + be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); - return status; + return tag; } -int be_cmd_get_mac_addr(struct beiscsi_hba *phba, u8 *mac_addr) +unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba) { struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mccq(phba); - struct be_cmd_req_get_mac_addr *req = embedded_payload(wrb); - int status; + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_mac_addr *req; + unsigned int tag = 0; SE_DEBUG(DBG_LVL_8, "In be_cmd_get_mac_addr\n"); spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); + tag = alloc_mcc_tag(phba); + if (!tag) { + spin_unlock(&ctrl->mbox_lock); + return tag; + } + + wrb = wrb_from_mccq(phba); + req = embedded_payload(wrb); + wrb->tag0 |= tag; be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG, sizeof(*req)); - status = be_mcc_notify_wait(phba); - if (!status) { - struct be_cmd_resp_get_mac_addr *resp = embedded_payload(wrb); - - memcpy(mac_addr, resp->mac_address, ETH_ALEN); - } - + be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); - return status; + return tag; } diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index 6bc59e8e1fe5..f873a66cd48f 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -250,7 +250,4 @@ unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba, unsigned short issue_reset, unsigned short savecfg_flag); -unsigned char mgmt_fw_cmd(struct be_ctrl_info *ctrl, - struct beiscsi_hba *phba, - char *buf, unsigned int len); #endif -- cgit v1.2.2 From da7408c800e3ae293275f52497d0ef7a9b09c9e4 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:11:23 +0530 Subject: [SCSI] be2iscsi: The session failure only when Link Goes down This fixes a situation where the sessions were being killed whenever LinkUP is notified rather than LinkDown Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_cmds.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index d4a0d1da4875..44e69bdf359a 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -161,13 +161,13 @@ void beiscsi_async_link_state_process(struct beiscsi_hba *phba, SE_DEBUG(DBG_LVL_1, "Link Down on Physical Port %d \n", evt->physical_port); phba->state |= BE_ADAPTER_LINK_DOWN; + iscsi_host_for_each_session(phba->shost, + be2iscsi_fail_session); break; case ASYNC_EVENT_LINK_UP: phba->state = BE_ADAPTER_UP; SE_DEBUG(DBG_LVL_1, "Link UP on Physical Port %d \n", evt->physical_port); - iscsi_host_for_each_session(phba->shost, - be2iscsi_fail_session); break; default: SE_DEBUG(DBG_LVL_1, "Unexpected Async Notification %d on" -- cgit v1.2.2 From aa874f0738ecac7e5ac13b4d808a1026dcb5367d Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:12:03 +0530 Subject: [SCSI] be2iscsi: Fixing initialization of can_queue This patch fixes can_queue being uninitiallized since it was done before beiscsi_get_params was called. Thanks to Mike Christie for identifying this Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index a6a2c6469677..b1c897528300 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3825,8 +3825,8 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, goto free_port; } phba->shost->max_id = phba->fw_config.iscsi_cid_count; - phba->shost->can_queue = phba->params.ios_per_ctrl; beiscsi_get_params(phba); + phba->shost->can_queue = phba->params.ios_per_ctrl; ret = beiscsi_init_port(phba); if (ret < 0) { shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" -- cgit v1.2.2 From 9db0fb3aa4cc4e42241e194ef64931321fa72196 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:12:43 +0530 Subject: [SCSI] be2iscsi: Enable TEXT req resp This patch enables TEXT Request / Response for the driver Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index b1c897528300..9fc4446b21e0 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3917,7 +3917,7 @@ disable_pci: struct iscsi_transport beiscsi_iscsi_transport = { .owner = THIS_MODULE, .name = DRV_NAME, - .caps = CAP_RECOVERY_L0 | CAP_HDRDGST | + .caps = CAP_RECOVERY_L0 | CAP_HDRDGST | CAP_TEXT_NEGO | CAP_MULTI_R2T | CAP_DATADGST | CAP_DATA_PATH_OFFLOAD, .param_mask = ISCSI_MAX_RECV_DLENGTH | ISCSI_MAX_XMIT_DLENGTH | -- cgit v1.2.2 From 90a86fc05ffefe48581c88106d0b9cc37f6e060c Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Tue, 12 Jan 2010 13:02:46 -0800 Subject: [SCSI] qla2xxx: Enhance EEH support and enable AER support. qla2xxx: EEH added call to pci_restore_state. qla2xxx: EEH added delay in slot reset routine. qla2xxx: EEH moved call to pci_save_state(), see (1). qla2xxx: EEH additional changes for RHEL5.5. qla2xxx: EEH added function call, removed function call, see (2). (1) In qla2xxx_probe_one the call to pci_save_state() has been moved to after the call to qla2xxx_request_irqs(). (2) Add call to pci_disable_pcie_error_reporting() in remove_one. Delete call to pci_cleanup_aer_uncorrect_error_status() in pci_resume. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_isr.c | 5 +++-- drivers/scsi/qla2xxx/qla_os.c | 40 ++++++++++++++++++++++++---------------- 2 files changed, 27 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index ffd0efdff40e..5613456dbbb1 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2252,10 +2252,11 @@ qla2x00_free_irqs(scsi_qla_host_t *vha) if (ha->flags.msix_enabled) qla24xx_disable_msix(ha); - else if (ha->flags.inta_enabled) { + else if (ha->flags.msi_enabled) { free_irq(ha->pdev->irq, rsp); pci_disable_msi(ha->pdev); - } + } else + free_irq(ha->pdev->irq, rsp); } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 8529eb1f3cd4..fe34b7f9dee6 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1818,7 +1818,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) /* Set EEH reset type to fundamental if required by hba */ if ( IS_QLA24XX(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha)) { pdev->needs_freset = 1; - pci_save_state(pdev); } /* Configure PCI I/O space */ @@ -1975,6 +1974,9 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ret = qla2x00_request_irqs(ha, rsp); if (ret) goto probe_init_failed; + + pci_save_state(pdev); + /* Alloc arrays of request and response ring ptrs */ que_init: if (!qla2x00_alloc_queues(ha)) { @@ -2176,6 +2178,8 @@ qla2x00_remove_one(struct pci_dev *pdev) kfree(ha); ha = NULL; + pci_disable_pcie_error_reporting(pdev); + pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } @@ -3310,6 +3314,7 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) return PCI_ERS_RESULT_CAN_RECOVER; case pci_channel_io_frozen: ha->flags.eeh_busy = 1; + qla2x00_free_irqs(vha); pci_disable_device(pdev); return PCI_ERS_RESULT_NEED_RESET; case pci_channel_io_perm_failure: @@ -3363,10 +3368,19 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT; scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); struct qla_hw_data *ha = base_vha->hw; - int rc; + struct rsp_que *rsp; + int rc, retries = 10; DEBUG17(qla_printk(KERN_WARNING, ha, "slot_reset\n")); + /* Workaround: qla2xxx driver which access hardware earlier + * needs error state to be pci_channel_io_online. + * Otherwise mailbox command timesout. + */ + pdev->error_state = pci_channel_io_normal; + + pci_restore_state(pdev); + if (ha->mem_only) rc = pci_enable_device_mem(pdev); else @@ -3378,27 +3392,23 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) return ret; } + rsp = ha->rsp_q_map[0]; + if (qla2x00_request_irqs(ha, rsp)) + return ret; + if (ha->isp_ops->pci_config(base_vha)) return ret; -#ifdef QL_DEBUG_LEVEL_17 - { - uint8_t b; - uint32_t i; + while (ha->flags.mbox_busy && retries--) + msleep(1000); - printk("slot_reset_1: "); - for (i = 0; i < 256; i++) { - pci_read_config_byte(ha->pdev, i, &b); - printk("%s%02x", (i%16) ? " " : "\n", b); - } - printk("\n"); - } -#endif set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); if (qla2x00_abort_isp(base_vha) == QLA_SUCCESS) ret = PCI_ERS_RESULT_RECOVERED; clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); + pci_cleanup_aer_uncorrect_error_status(pdev); + DEBUG17(qla_printk(KERN_WARNING, ha, "slot_reset-return:ret=%x\n", ret)); @@ -3422,8 +3432,6 @@ qla2xxx_pci_resume(struct pci_dev *pdev) } ha->flags.eeh_busy = 0; - - pci_cleanup_aer_uncorrect_error_status(pdev); } static struct pci_error_handlers qla2xxx_err_handler = { -- cgit v1.2.2 From 9a069e196767d7b87184fd8d8211d22bb5b9c0b8 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Tue, 12 Jan 2010 13:02:47 -0800 Subject: [SCSI] qla2xxx: Add BSG support for FC ELS/CT passthrough and vendor commands. [jejb: fixed printk casting issues] Signed-off-by: Sarang Radke Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 746 +++++++++++++++++++++++++++++++++++++++- drivers/scsi/qla2xxx/qla_def.h | 155 +++++++++ drivers/scsi/qla2xxx/qla_fw.h | 33 ++ drivers/scsi/qla2xxx/qla_gbl.h | 5 + drivers/scsi/qla2xxx/qla_init.c | 14 +- drivers/scsi/qla2xxx/qla_iocb.c | 120 +++++++ drivers/scsi/qla2xxx/qla_isr.c | 105 +++++- drivers/scsi/qla2xxx/qla_mbx.c | 151 ++++++++ drivers/scsi/qla2xxx/qla_os.c | 1 + 9 files changed, 1326 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 3a9f5b288aee..5a19aea17022 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -11,7 +11,9 @@ #include static int qla24xx_vport_disable(struct fc_vport *, bool); - +static int qla84xx_reset(scsi_qla_host_t *, struct msg_echo_lb *, struct fc_bsg_job *); +int qla84xx_reset_chip(scsi_qla_host_t *, uint16_t, uint16_t *); +static int qla84xx_mgmt_cmd(scsi_qla_host_t *, struct msg_echo_lb *, struct fc_bsg_job *); /* SYSFS attributes --------------------------------------------------------- */ static ssize_t @@ -1167,6 +1169,28 @@ qla2x00_total_isp_aborts_show(struct device *dev, ha->qla_stats.total_isp_aborts); } +static ssize_t +qla24xx_84xx_fw_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int rval = QLA_SUCCESS; + uint16_t status[2] = {0, 0}; + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + struct qla_hw_data *ha = vha->hw; + + if (IS_QLA84XX(ha) && ha->cs84xx) { + if (ha->cs84xx->op_fw_version == 0) { + rval = qla84xx_verify_chip(vha, status); + } + + if ((rval == QLA_SUCCESS) && (status[0] == 0)) + return snprintf(buf, PAGE_SIZE, "%u\n", + (uint32_t)ha->cs84xx->op_fw_version); + } + + return snprintf(buf, PAGE_SIZE, "\n"); +} + static ssize_t qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1281,6 +1305,8 @@ static DEVICE_ATTR(optrom_fcode_version, S_IRUGO, qla2x00_optrom_fcode_version_show, NULL); static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show, NULL); +static DEVICE_ATTR(84xx_fw_version, S_IRUGO, qla24xx_84xx_fw_version_show, + NULL); static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show, NULL); static DEVICE_ATTR(mpi_version, S_IRUGO, qla2x00_mpi_version_show, NULL); @@ -1310,6 +1336,7 @@ struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_optrom_efi_version, &dev_attr_optrom_fcode_version, &dev_attr_optrom_fw_version, + &dev_attr_84xx_fw_version, &dev_attr_total_isp_aborts, &dev_attr_mpi_version, &dev_attr_phy_version, @@ -1795,6 +1822,597 @@ qla24xx_vport_disable(struct fc_vport *fc_vport, bool disable) return 0; } +/* BSG support for ELS/CT pass through */ +inline srb_t * +qla2x00_get_ctx_bsg_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size) +{ + srb_t *sp; + struct qla_hw_data *ha = vha->hw; + struct srb_bsg_ctx *ctx; + + sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL); + if (!sp) + goto done; + ctx = kzalloc(size, GFP_KERNEL); + if (!ctx) { + mempool_free(sp, ha->srb_mempool); + goto done; + } + + memset(sp, 0, sizeof(*sp)); + sp->fcport = fcport; + sp->ctx = ctx; +done: + return sp; +} + +static int +qla2x00_process_els(struct fc_bsg_job *bsg_job) +{ + struct fc_rport *rport; + fc_port_t *fcport; + struct Scsi_Host *host; + scsi_qla_host_t *vha; + struct qla_hw_data *ha; + srb_t *sp; + const char *type; + int req_sg_cnt, rsp_sg_cnt; + int rval = (DRIVER_ERROR << 16); + uint16_t nextlid = 0; + struct srb_bsg *els; + + /* Multiple SG's are not supported for ELS requests */ + if (bsg_job->request_payload.sg_cnt > 1 || + bsg_job->reply_payload.sg_cnt > 1) { + DEBUG2(printk(KERN_INFO + "multiple SG's are not supported for ELS requests" + " [request_sg_cnt: %x reply_sg_cnt: %x]\n", + bsg_job->request_payload.sg_cnt, + bsg_job->reply_payload.sg_cnt)); + rval = -EPERM; + goto done; + } + + /* ELS request for rport */ + if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) { + rport = bsg_job->rport; + fcport = *(fc_port_t **) rport->dd_data; + host = rport_to_shost(rport); + vha = shost_priv(host); + ha = vha->hw; + type = "FC_BSG_RPT_ELS"; + + DEBUG2(printk(KERN_INFO + "scsi(%ld): loop-id=%x portid=%02x%02x%02x.\n", + fcport->vha->host_no, fcport->loop_id, + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa)); + + /* make sure the rport is logged in, + * if not perform fabric login + */ + if (qla2x00_fabric_login(vha, fcport, &nextlid)) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "failed to login port %06X for ELS passthru\n", + fcport->d_id.b24)); + rval = -EIO; + goto done; + } + } else { + host = bsg_job->shost; + vha = shost_priv(host); + ha = vha->hw; + type = "FC_BSG_HST_ELS_NOLOGIN"; + + DEBUG2(printk(KERN_INFO + "scsi(%ld): loop-id=%x portid=%02x%02x%02x.\n", + vha->host_no, vha->loop_id, + vha->d_id.b.domain, vha->d_id.b.area, vha->d_id.b.al_pa)); + + /* Allocate a dummy fcport structure, since functions + * preparing the IOCB and mailbox command retrieves port + * specific information from fcport structure. For Host based + * ELS commands there will be no fcport structure allocated + */ + fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); + if (!fcport) { + rval = -ENOMEM; + goto done; + } + + /* Initialize all required fields of fcport */ + fcport->vha = vha; + fcport->vp_idx = vha->vp_idx; + fcport->d_id.b.al_pa = + bsg_job->request->rqst_data.h_els.port_id[0]; + fcport->d_id.b.area = + bsg_job->request->rqst_data.h_els.port_id[1]; + fcport->d_id.b.domain = + bsg_job->request->rqst_data.h_els.port_id[2]; + fcport->loop_id = + (fcport->d_id.b.al_pa == 0xFD) ? + NPH_FABRIC_CONTROLLER : NPH_F_PORT; + } + + DEBUG2(printk(KERN_INFO + "scsi(%ld): vendor-id = %llu\n", + vha->host_no, host->hostt->vendor_id)); + + req_sg_cnt = + dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); + if (!req_sg_cnt) { + rval = -ENOMEM; + goto done_free_fcport; + } + rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + if (!rsp_sg_cnt) { + rval = -ENOMEM; + goto done_free_fcport; + } + + if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) || + (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) + { + DEBUG2(printk(KERN_INFO + "dma mapping resulted in different sg counts \ + [request_sg_cnt: %x dma_request_sg_cnt: %x\ + reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", + bsg_job->request_payload.sg_cnt, req_sg_cnt, + bsg_job->reply_payload.sg_cnt, rsp_sg_cnt)); + rval = -EAGAIN; + goto done_unmap_sg; + } + + /* Alloc SRB structure */ + sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_bsg)); + if (!sp) { + rval = -ENOMEM; + goto done_unmap_sg; + } + + els = sp->ctx; + els->ctx.type = + (bsg_job->request->msgcode == FC_BSG_RPT_ELS ? + SRB_ELS_CMD_RPT : SRB_ELS_CMD_HST); + els->bsg_job = bsg_job; + + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x " + "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type, + bsg_job->request->rqst_data.h_els.command_code, + fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa)); + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) { + kfree(sp->ctx); + mempool_free(sp, ha->srb_mempool); + rval = -EIO; + goto done_unmap_sg; + } + return rval; + +done_unmap_sg: + dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); + dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + goto done_free_fcport; + +done_free_fcport: + if (bsg_job->request->msgcode == FC_BSG_HST_ELS_NOLOGIN) + kfree(fcport); +done: + return rval; +} + +static int +qla2x00_process_ct(struct fc_bsg_job *bsg_job) +{ + srb_t *sp; + struct Scsi_Host *host = bsg_job->shost; + scsi_qla_host_t *vha = shost_priv(host); + struct qla_hw_data *ha = vha->hw; + int rval = (DRIVER_ERROR << 16); + int req_sg_cnt, rsp_sg_cnt; + uint16_t loop_id; + struct fc_port *fcport; + char *type = "FC_BSG_HST_CT"; + struct srb_bsg *ct; + + /* pass through is supported only for ISP 4Gb or higher */ + if (!IS_FWI2_CAPABLE(ha)) { + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld):Firmware is not capable to support FC " + "CT pass thru\n", vha->host_no)); + rval = -EPERM; + goto done; + } + + req_sg_cnt = + dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); + if (!req_sg_cnt) { + rval = -ENOMEM; + goto done; + } + + rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + if (!rsp_sg_cnt) { + rval = -ENOMEM; + goto done; + } + + if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) || + (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) + { + DEBUG2(qla_printk(KERN_WARNING, ha, + "dma mapping resulted in different sg counts \ + [request_sg_cnt: %x dma_request_sg_cnt: %x\ + reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", + bsg_job->request_payload.sg_cnt, req_sg_cnt, + bsg_job->reply_payload.sg_cnt, rsp_sg_cnt)); + rval = -EAGAIN; + goto done_unmap_sg; + } + + loop_id = + (bsg_job->request->rqst_data.h_ct.preamble_word1 & 0xFF000000) + >> 24; + switch (loop_id) { + case 0xFC: + loop_id = cpu_to_le16(NPH_SNS); + break; + case 0xFA: + loop_id = vha->mgmt_svr_loop_id; + break; + default: + DEBUG2(qla_printk(KERN_INFO, ha, + "Unknown loop id: %x\n", loop_id)); + rval = -EINVAL; + goto done_unmap_sg; + } + + /* Allocate a dummy fcport structure, since functions preparing the + * IOCB and mailbox command retrieves port specific information + * from fcport structure. For Host based ELS commands there will be + * no fcport structure allocated + */ + fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); + if (!fcport) + { + rval = -ENOMEM; + goto done_unmap_sg; + } + + /* Initialize all required fields of fcport */ + fcport->vha = vha; + fcport->vp_idx = vha->vp_idx; + fcport->d_id.b.al_pa = bsg_job->request->rqst_data.h_ct.port_id[0]; + fcport->d_id.b.area = bsg_job->request->rqst_data.h_ct.port_id[1]; + fcport->d_id.b.domain = bsg_job->request->rqst_data.h_ct.port_id[2]; + fcport->loop_id = loop_id; + + /* Alloc SRB structure */ + sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_bsg)); + if (!sp) { + rval = -ENOMEM; + goto done_free_fcport; + } + + ct = sp->ctx; + ct->ctx.type = SRB_CT_CMD; + ct->bsg_job = bsg_job; + + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x " + "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type, + (bsg_job->request->rqst_data.h_ct.preamble_word2 >> 16), + fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa)); + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) { + kfree(sp->ctx); + mempool_free(sp, ha->srb_mempool); + rval = -EIO; + goto done_free_fcport; + } + return rval; + +done_free_fcport: + kfree(fcport); +done_unmap_sg: + dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); + dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); +done: + return rval; +} + +static int +qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job) +{ + struct Scsi_Host *host = bsg_job->shost; + scsi_qla_host_t *vha = shost_priv(host); + struct qla_hw_data *ha = vha->hw; + int rval; + uint8_t command_sent; + uint32_t vendor_cmd; + char *type; + struct msg_echo_lb elreq; + uint16_t response[MAILBOX_REGISTER_COUNT]; + uint8_t* fw_sts_ptr; + uint8_t *req_data; + dma_addr_t req_data_dma; + uint32_t req_data_len; + uint8_t *rsp_data; + dma_addr_t rsp_data_dma; + uint32_t rsp_data_len; + + if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || + test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || + test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { + rval = -EBUSY; + goto done; + } + + elreq.req_sg_cnt = + dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); + if (!elreq.req_sg_cnt) { + rval = -ENOMEM; + goto done; + } + elreq.rsp_sg_cnt = + dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + if (!elreq.rsp_sg_cnt) { + rval = -ENOMEM; + goto done; + } + + if ((elreq.req_sg_cnt != bsg_job->request_payload.sg_cnt) || + (elreq.rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) + { + DEBUG2(printk(KERN_INFO + "dma mapping resulted in different sg counts \ + [request_sg_cnt: %x dma_request_sg_cnt: %x\ + reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", + bsg_job->request_payload.sg_cnt, elreq.req_sg_cnt, + bsg_job->reply_payload.sg_cnt, elreq.rsp_sg_cnt)); + rval = -EAGAIN; + goto done_unmap_sg; + } + req_data_len = rsp_data_len = bsg_job->request_payload.payload_len; + req_data = dma_alloc_coherent(&ha->pdev->dev, req_data_len, + &req_data_dma, GFP_KERNEL); + + rsp_data = dma_alloc_coherent(&ha->pdev->dev, rsp_data_len, + &rsp_data_dma, GFP_KERNEL); + + /* Copy the request buffer in req_data now */ + sg_copy_to_buffer(bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, req_data, + req_data_len); + + elreq.send_dma = req_data_dma; + elreq.rcv_dma = rsp_data_dma; + elreq.transfer_size = req_data_len; + + /* Vendor cmd : loopback or ECHO diagnostic + * Options: + * Loopback : Either internal or external loopback + * ECHO: ECHO ELS or Vendor specific FC4 link data + */ + vendor_cmd = bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]; + elreq.options = + *(((uint32_t *)bsg_job->request->rqst_data.h_vendor.vendor_cmd) + + 1); + + switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) { + case QL_VND_LOOPBACK: + if (ha->current_topology != ISP_CFG_F) { + type = "FC_BSG_HST_VENDOR_LOOPBACK"; + + if ((IS_QLA81XX(ha)) && + ((elreq.options == 0) || (elreq.options == 2))) { + DEBUG2(qla_printk(KERN_INFO, ha, "scsi(%ld)" + "loopback option:0x%x not supported\n", vha->host_no, elreq.options)); + rval = -EINVAL; + goto done_unmap_sg; + } + + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld) bsg rqst type: %s vendor rqst type: %x options: %x.\n", + vha->host_no, type, vendor_cmd, elreq.options)); + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld) tx_addr: 0x%llx rx_addr: 0x%llx tx_sg_cnt: %x rx_sg_cnt: %x\n", + vha->host_no, (unsigned long long)elreq.send_dma, (unsigned long long)elreq.rcv_dma, elreq.req_sg_cnt, elreq.rsp_sg_cnt)); + command_sent = INT_DEF_LB_LOOPBACK_CMD; + rval = qla2x00_loopback_test(vha, &elreq, response); + if (IS_QLA81XX(ha)) { + if (response[0] == MBS_COMMAND_ERROR && response[1] == MBS_LB_RESET) { + DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing " + "ISP\n", __func__, vha->host_no)); + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + } + } + } else { + type = "FC_BSG_HST_VENDOR_ECHO_DIAG"; + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld) bsg rqst type: %s vendor rqst type: %x options: %x.\n", + vha->host_no, type, vendor_cmd, elreq.options)); + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld) tx_addr: 0x%llx rx_addr: 0x%llx tx_sg_cnt: %x rx_sg_cnt: %x\n", + vha->host_no, (unsigned long long)elreq.send_dma, (unsigned long long)elreq.rcv_dma, elreq.req_sg_cnt, elreq.rsp_sg_cnt)); + command_sent = INT_DEF_LB_ECHO_CMD; + rval = qla2x00_echo_test(vha, &elreq, response); + } + break; + case QLA84_RESET: + if (!IS_QLA84XX(vha->hw)) { + rval = -EINVAL; + DEBUG16(printk( + "%s(%ld): 8xxx exiting.\n", + __func__, vha->host_no)); + return rval; + } + rval = qla84xx_reset(vha, &elreq, bsg_job); + break; + case QLA84_MGMT_CMD: + if (!IS_QLA84XX(vha->hw)) { + rval = -EINVAL; + DEBUG16(printk( + "%s(%ld): 8xxx exiting.\n", + __func__, vha->host_no)); + return rval; + } + rval = qla84xx_mgmt_cmd(vha, &elreq, bsg_job); + break; + default: + rval = -ENOSYS; + } + + if (rval != QLA_SUCCESS) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "scsi(%ld) Vendor request %s failed\n", vha->host_no, type)); + rval = 0; + bsg_job->reply->result = (DID_ERROR << 16); + fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); + memcpy( fw_sts_ptr, response, sizeof(response)); + fw_sts_ptr += sizeof(response); + *fw_sts_ptr = command_sent; + } else { + DEBUG2(qla_printk(KERN_WARNING, ha, + "scsi(%ld) Vendor request %s completed\n", vha->host_no, type)); + rval = bsg_job->reply->result = 0; + bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(response) + sizeof(uint8_t); + bsg_job->reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len; + fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); + memcpy(fw_sts_ptr, response, sizeof(response)); + fw_sts_ptr += sizeof(response); + *fw_sts_ptr = command_sent; + sg_copy_from_buffer(bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, rsp_data, + rsp_data_len); + } + bsg_job->job_done(bsg_job); + +done_unmap_sg: + + if(req_data) + dma_free_coherent(&ha->pdev->dev, req_data_len, + req_data, req_data_dma); + dma_unmap_sg(&ha->pdev->dev, + bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); + dma_unmap_sg(&ha->pdev->dev, + bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + +done: + return rval; +} + +static int +qla24xx_bsg_request(struct fc_bsg_job *bsg_job) +{ + int ret = -EINVAL; + + switch (bsg_job->request->msgcode) { + case FC_BSG_RPT_ELS: + case FC_BSG_HST_ELS_NOLOGIN: + ret = qla2x00_process_els(bsg_job); + break; + case FC_BSG_HST_CT: + ret = qla2x00_process_ct(bsg_job); + break; + case FC_BSG_HST_VENDOR: + ret = qla2x00_process_vendor_specific(bsg_job); + break; + case FC_BSG_HST_ADD_RPORT: + case FC_BSG_HST_DEL_RPORT: + case FC_BSG_RPT_CT: + default: + DEBUG2(printk("qla2xxx: unsupported BSG request\n")); + break; + } + return ret; +} + +static int +qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job) +{ + scsi_qla_host_t *vha = shost_priv(bsg_job->shost); + struct qla_hw_data *ha = vha->hw; + srb_t *sp; + int i; + unsigned long flags; + uint16_t que_id; + struct req_que *req; + struct rsp_que *rsp; + int found = 0; + struct srb_bsg *sp_bsg; + + /* find the bsg job from the active list of commands */ + spin_lock_irqsave(&ha->hardware_lock, flags); + req = ha->req_q_map[0]; + que_id = req->id; + if (req->rsp) + rsp = req->rsp; + else + rsp = ha->rsp_q_map[que_id]; + + for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++ ) { + sp = req->outstanding_cmds[i]; + + if (sp == NULL) + continue; + + sp_bsg = (struct srb_bsg*)sp->ctx; + + if (((sp_bsg->ctx.type == SRB_CT_CMD) || + (sp_bsg->ctx.type == SRB_ELS_CMD_RPT) + || ( sp_bsg->ctx.type == SRB_ELS_CMD_HST)) && + (sp_bsg->bsg_job == bsg_job)) { + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld) req_q: %p rsp_q: %p que_id: %x sp: %p\n", + vha->host_no, req, rsp, que_id, sp)); + found = 1; + break; + } + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (!found) { + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld) SRB not found to abort\n", vha->host_no)); + bsg_job->req->errors = bsg_job->reply->result = -ENXIO; + return 0; + } + + if (ha->isp_ops->abort_command(sp)) { + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld): mbx abort_command failed\n", vha->host_no)); + bsg_job->req->errors = bsg_job->reply->result = -EIO; + } else { + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld): mbx abort_command success\n", vha->host_no)); + bsg_job->req->errors = bsg_job->reply->result = 0; + } + + if (bsg_job->request->msgcode == FC_BSG_HST_CT) + kfree(sp->fcport); + kfree(sp->ctx); + mempool_free(sp, ha->srb_mempool); + return 0; +} + struct fc_function_template qla2xxx_transport_functions = { .show_host_node_name = 1, @@ -1838,6 +2456,8 @@ struct fc_function_template qla2xxx_transport_functions = { .vport_create = qla24xx_vport_create, .vport_disable = qla24xx_vport_disable, .vport_delete = qla24xx_vport_delete, + .bsg_request = qla24xx_bsg_request, + .bsg_timeout = qla24xx_bsg_timeout, }; struct fc_function_template qla2xxx_transport_vport_functions = { @@ -1878,6 +2498,8 @@ struct fc_function_template qla2xxx_transport_vport_functions = { .dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk, .terminate_rport_io = qla2x00_terminate_rport_io, .get_fc_host_stats = qla2x00_get_fc_host_stats, + .bsg_request = qla24xx_bsg_request, + .bsg_timeout = qla24xx_bsg_timeout, }; void @@ -1906,3 +2528,125 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha) speed = FC_PORTSPEED_1GBIT; fc_host_supported_speeds(vha->host) = speed; } +static int +qla84xx_reset(scsi_qla_host_t *ha, struct msg_echo_lb *mreq, struct fc_bsg_job *bsg_job) +{ + int ret = 0; + int cmd; + uint16_t cmd_status; + + DEBUG16(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + cmd = (*((bsg_job->request->rqst_data.h_vendor.vendor_cmd) + 2)) + == A84_RESET_FLAG_ENABLE_DIAG_FW ? + A84_ISSUE_RESET_DIAG_FW : A84_ISSUE_RESET_OP_FW; + ret = qla84xx_reset_chip(ha, cmd == A84_ISSUE_RESET_DIAG_FW, + &cmd_status); + return ret; +} + +static int +qla84xx_mgmt_cmd(scsi_qla_host_t *ha, struct msg_echo_lb *mreq, struct fc_bsg_job *bsg_job) +{ + struct access_chip_84xx *mn; + dma_addr_t mn_dma, mgmt_dma; + void *mgmt_b = NULL; + int ret = 0; + int rsp_hdr_len, len = 0; + struct qla84_msg_mgmt *ql84_mgmt; + + ql84_mgmt = (struct qla84_msg_mgmt *) vmalloc(sizeof(struct qla84_msg_mgmt)); + ql84_mgmt->cmd = + *((uint16_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 2)); + ql84_mgmt->mgmtp.u.mem.start_addr = + *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 3)); + ql84_mgmt->len = + *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 4)); + ql84_mgmt->mgmtp.u.config.id = + *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 5)); + ql84_mgmt->mgmtp.u.config.param0 = + *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 6)); + ql84_mgmt->mgmtp.u.config.param1 = + *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 7)); + ql84_mgmt->mgmtp.u.info.type = + *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 8)); + ql84_mgmt->mgmtp.u.info.context = + *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 9)); + + rsp_hdr_len = bsg_job->request_payload.payload_len; + + mn = dma_pool_alloc(ha->hw->s_dma_pool, GFP_KERNEL, &mn_dma); + if (mn == NULL) { + DEBUG2(printk(KERN_ERR "%s: dma alloc for fw buffer " + "failed%lu\n", __func__, ha->host_no)); + return -ENOMEM; + } + + memset(mn, 0, sizeof (struct access_chip_84xx)); + + mn->entry_type = ACCESS_CHIP_IOCB_TYPE; + mn->entry_count = 1; + + switch (ql84_mgmt->cmd) { + case QLA84_MGMT_READ_MEM: + mn->options = cpu_to_le16(ACO_DUMP_MEMORY); + mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr); + break; + case QLA84_MGMT_WRITE_MEM: + mn->options = cpu_to_le16(ACO_LOAD_MEMORY); + mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr); + break; + case QLA84_MGMT_CHNG_CONFIG: + mn->options = cpu_to_le16(ACO_CHANGE_CONFIG_PARAM); + mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.id); + mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param0); + mn->parameter3 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param1); + break; + case QLA84_MGMT_GET_INFO: + mn->options = cpu_to_le16(ACO_REQUEST_INFO); + mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.type); + mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.context); + break; + default: + ret = -EIO; + goto exit_mgmt0; + } + + if ((len == ql84_mgmt->len) && + ql84_mgmt->cmd != QLA84_MGMT_CHNG_CONFIG) { + mgmt_b = dma_alloc_coherent(&ha->hw->pdev->dev, len, + &mgmt_dma, GFP_KERNEL); + if (mgmt_b == NULL) { + DEBUG2(printk(KERN_ERR "%s: dma alloc mgmt_b " + "failed%lu\n", __func__, ha->host_no)); + ret = -ENOMEM; + goto exit_mgmt0; + } + mn->total_byte_cnt = cpu_to_le32(ql84_mgmt->len); + mn->dseg_count = cpu_to_le16(1); + mn->dseg_address[0] = cpu_to_le32(LSD(mgmt_dma)); + mn->dseg_address[1] = cpu_to_le32(MSD(mgmt_dma)); + mn->dseg_length = cpu_to_le32(len); + + if (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM) { + memcpy(mgmt_b, ql84_mgmt->payload, len); + } + } + + ret = qla2x00_issue_iocb(ha, mn, mn_dma, 0); + if ((ret != QLA_SUCCESS) || (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM) + || (ql84_mgmt->cmd == QLA84_MGMT_CHNG_CONFIG)) { + if (ret != QLA_SUCCESS) + DEBUG2(printk(KERN_ERR "%s(%lu): failed\n", + __func__, ha->host_no)); + } else if ((ql84_mgmt->cmd == QLA84_MGMT_READ_MEM) || + (ql84_mgmt->cmd == QLA84_MGMT_GET_INFO)) { + } + + if (mgmt_b) + dma_free_coherent(&ha->hw->pdev->dev, len, mgmt_b, mgmt_dma); + +exit_mgmt0: + dma_pool_free(ha->hw->s_dma_pool, mn, mn_dma); + return ret; +} diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 1263d9796e89..afa95614aaf8 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -31,6 +31,7 @@ #include #include #include +#include #define QLA2XXX_DRIVER_NAME "qla2xxx" @@ -228,6 +229,27 @@ struct srb_logio { uint16_t flags; }; +struct srb_bsg_ctx { +#define SRB_ELS_CMD_RPT 3 +#define SRB_ELS_CMD_HST 4 +#define SRB_CT_CMD 5 + uint16_t type; +}; + +struct srb_bsg { + struct srb_bsg_ctx ctx; + struct fc_bsg_job *bsg_job; +}; + +struct msg_echo_lb { + dma_addr_t send_dma; + dma_addr_t rcv_dma; + uint16_t req_sg_cnt; + uint16_t rsp_sg_cnt; + uint16_t options; + uint32_t transfer_size; +}; + /* * ISP I/O Register Set structure definitions. */ @@ -522,6 +544,8 @@ typedef struct { #define MBA_DISCARD_RND_FRAME 0x8048 /* discard RND frame due to error. */ #define MBA_REJECTED_FCP_CMD 0x8049 /* rejected FCP_CMD. */ +/* ISP mailbox loopback echo diagnostic error code */ +#define MBS_LB_RESET 0x17 /* * Firmware options 1, 2, 3. */ @@ -2230,6 +2254,13 @@ struct req_que { int max_q_depth; }; +/* Place holder for FW buffer parameters */ +struct qlfc_fw { + void *fw_buf; + dma_addr_t fw_dma; + uint32_t len; +}; + /* * Qlogic host adapter specific data structure. */ @@ -2594,6 +2625,7 @@ struct qla_hw_data { struct qla_statistics qla_stats; struct isp_operations *isp_ops; struct workqueue_struct *wq; + struct qlfc_fw fw_buf; }; /* @@ -2766,4 +2798,127 @@ typedef struct scsi_qla_host { #define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr) +/* + * BSG Vendor specific commands + */ + +#define QL_VND_LOOPBACK 0x01 +#define QLA84_RESET 0x02 +#define QLA84_UPDATE_FW 0x03 +#define QLA84_MGMT_CMD 0x04 + +/* BSG definations for interpreting CommandSent field */ +#define INT_DEF_LB_LOOPBACK_CMD 0 +#define INT_DEF_LB_ECHO_CMD 1 + +/* BSG Vendor specific definations */ +typedef struct _A84_RESET { + uint16_t Flags; + uint16_t Reserved; +#define A84_RESET_FLAG_ENABLE_DIAG_FW 1 +} __attribute__((packed)) A84_RESET, *PA84_RESET; + +#define A84_ISSUE_WRITE_TYPE_CMD 0 +#define A84_ISSUE_READ_TYPE_CMD 1 +#define A84_CLEANUP_CMD 2 +#define A84_ISSUE_RESET_OP_FW 3 +#define A84_ISSUE_RESET_DIAG_FW 4 +#define A84_ISSUE_UPDATE_OPFW_CMD 5 +#define A84_ISSUE_UPDATE_DIAGFW_CMD 6 + +struct qla84_mgmt_param { + union { + struct { + uint32_t start_addr; + } mem; /* for QLA84_MGMT_READ/WRITE_MEM */ + struct { + uint32_t id; +#define QLA84_MGMT_CONFIG_ID_UIF 1 +#define QLA84_MGMT_CONFIG_ID_FCOE_COS 2 +#define QLA84_MGMT_CONFIG_ID_PAUSE 3 +#define QLA84_MGMT_CONFIG_ID_TIMEOUTS 4 + + uint32_t param0; + uint32_t param1; + } config; /* for QLA84_MGMT_CHNG_CONFIG */ + + struct { + uint32_t type; +#define QLA84_MGMT_INFO_CONFIG_LOG_DATA 1 /* Get Config Log Data */ +#define QLA84_MGMT_INFO_LOG_DATA 2 /* Get Log Data */ +#define QLA84_MGMT_INFO_PORT_STAT 3 /* Get Port Statistics */ +#define QLA84_MGMT_INFO_LIF_STAT 4 /* Get LIF Statistics */ +#define QLA84_MGMT_INFO_ASIC_STAT 5 /* Get ASIC Statistics */ +#define QLA84_MGMT_INFO_CONFIG_PARAMS 6 /* Get Config Parameters */ +#define QLA84_MGMT_INFO_PANIC_LOG 7 /* Get Panic Log */ + + uint32_t context; +/* +* context definitions for QLA84_MGMT_INFO_CONFIG_LOG_DATA +*/ +#define IC_LOG_DATA_LOG_ID_DEBUG_LOG 0 +#define IC_LOG_DATA_LOG_ID_LEARN_LOG 1 +#define IC_LOG_DATA_LOG_ID_FC_ACL_INGRESS_LOG 2 +#define IC_LOG_DATA_LOG_ID_FC_ACL_EGRESS_LOG 3 +#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_INGRESS_LOG 4 +#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_EGRESS_LOG 5 +#define IC_LOG_DATA_LOG_ID_MESSAGE_TRANSMIT_LOG 6 +#define IC_LOG_DATA_LOG_ID_MESSAGE_RECEIVE_LOG 7 +#define IC_LOG_DATA_LOG_ID_LINK_EVENT_LOG 8 +#define IC_LOG_DATA_LOG_ID_DCX_LOG 9 + +/* +* context definitions for QLA84_MGMT_INFO_PORT_STAT +*/ +#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT0 0 +#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT1 1 +#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT0 2 +#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT1 3 +#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT0 4 +#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT1 5 + + +/* +* context definitions for QLA84_MGMT_INFO_LIF_STAT +*/ +#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT0 0 +#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT1 1 +#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT0 2 +#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT1 3 +#define IC_LIF_STATISTICS_LIF_NUMBER_CPU 6 + + } info; /* for QLA84_MGMT_GET_INFO */ + } u; +}; + +struct qla84_msg_mgmt { + uint16_t cmd; +#define QLA84_MGMT_READ_MEM 0x00 +#define QLA84_MGMT_WRITE_MEM 0x01 +#define QLA84_MGMT_CHNG_CONFIG 0x02 +#define QLA84_MGMT_GET_INFO 0x03 + uint16_t rsrvd; + struct qla84_mgmt_param mgmtp;/* parameters for cmd */ + uint32_t len; /* bytes in payload following this struct */ + uint8_t payload[0]; /* payload for cmd */ +}; + +struct msg_update_fw { + /* + * diag_fw = 0 operational fw + * otherwise diagnostic fw + * offset, len, fw_len are present to overcome the current limitation + * of 128Kb xfer size. The fw is sent in smaller chunks. Each chunk + * specifies the byte "offset" where it fits in the fw buffer. The + * number of bytes in each chunk is specified in "len". "fw_len" + * is the total size of fw. The first chunk should start at offset = 0. + * When offset+len == fw_len, the fw is written to the HBA. + */ + uint32_t diag_fw; + uint32_t offset;/* start offset */ + uint32_t len; /* num bytes in cur xfer */ + uint32_t fw_len; /* size of fw in bytes */ + uint8_t fw_bytes[0]; +}; + #endif diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 66a8da5d7d08..cebf4f1bb7d9 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -627,6 +627,39 @@ struct els_entry_24xx { uint32_t rx_len; /* Data segment 1 length. */ }; +struct els_sts_entry_24xx { + uint8_t entry_type; /* Entry type. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System Defined. */ + uint8_t entry_status; /* Entry Status. */ + + uint32_t handle; /* System handle. */ + + uint16_t comp_status; + + uint16_t nport_handle; /* N_PORT handle. */ + + uint16_t reserved_1; + + uint8_t vp_index; + uint8_t sof_type; + + uint32_t rx_xchg_address; /* Receive exchange address. */ + uint16_t reserved_2; + + uint8_t opcode; + uint8_t reserved_3; + + uint8_t port_id[3]; + uint8_t reserved_4; + + uint16_t reserved_5; + + uint16_t control_flags; /* Control flags. */ + uint32_t total_byte_count; + uint32_t error_subcode_1; + uint32_t error_subcode_2; +}; /* * ISP queue - Mailbox Command entry structure definition. */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index f61fb8d01330..b42e704bdca9 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -60,6 +60,8 @@ extern int qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *, extern int qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *, uint16_t *); +extern fc_port_t * +qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t ); /* * Global Data in qla_os.c source file. */ @@ -154,6 +156,7 @@ int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *, int __qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *, uint16_t, uint16_t, uint8_t); extern int qla2x00_start_sp(srb_t *); +extern void qla2x00_ctx_sp_free(srb_t *); /* * Global Function Prototypes in qla_mbx.c source file. @@ -426,6 +429,8 @@ extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *); extern void qla2x00_init_host_attr(scsi_qla_host_t *); extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *); extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *); +extern int qla2x00_loopback_test(scsi_qla_host_t *, struct msg_echo_lb *, uint16_t *); +extern int qla2x00_echo_test(scsi_qla_host_t *, struct msg_echo_lb *, uint16_t *); /* * Global Function Prototypes in qla_dfs.c source file. diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 3f8e8495b743..1128c8d5771b 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -62,7 +62,7 @@ qla2x00_ctx_sp_timeout(unsigned long __data) ctx->free(sp); } -static void +void qla2x00_ctx_sp_free(srb_t *sp) { struct srb_ctx *ctx = sp->ctx; @@ -338,6 +338,16 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) rval = qla2x00_init_rings(vha); ha->flags.chip_reset_done = 1; + if (rval == QLA_SUCCESS && IS_QLA84XX(ha)) { + /* Issue verify 84xx FW IOCB to complete 84xx initialization */ + rval = qla84xx_init_chip(vha); + if (rval != QLA_SUCCESS) { + qla_printk(KERN_ERR, ha, + "Unable to initialize ISP84XX.\n"); + qla84xx_put_chip(vha); + } + } + return (rval); } @@ -2216,7 +2226,7 @@ qla2x00_rport_del(void *data) * * Returns a pointer to the allocated fcport, or NULL, if none available. */ -static fc_port_t * +fc_port_t * qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags) { fc_port_t *fcport; diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index c5ccac0bef76..8299a9891bfe 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -1025,6 +1025,119 @@ qla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx) /* Implicit: mbx->mbx10 = 0. */ } +static void +qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) +{ + struct fc_bsg_job *bsg_job = ((struct srb_bsg*)sp->ctx)->bsg_job; + + els_iocb->entry_type = ELS_IOCB_TYPE; + els_iocb->entry_count = 1; + els_iocb->sys_define = 0; + els_iocb->entry_status = 0; + els_iocb->handle = sp->handle; + els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); + els_iocb->tx_dsd_count = __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt); + els_iocb->vp_index = sp->fcport->vp_idx; + els_iocb->sof_type = EST_SOFI3; + els_iocb->rx_dsd_count = __constant_cpu_to_le16(bsg_job->reply_payload.sg_cnt); + + els_iocb->opcode =(((struct srb_bsg*)sp->ctx)->ctx.type == SRB_ELS_CMD_RPT) ? + bsg_job->request->rqst_data.r_els.els_code : bsg_job->request->rqst_data.h_els.command_code; + els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; + els_iocb->port_id[1] = sp->fcport->d_id.b.area; + els_iocb->port_id[2] = sp->fcport->d_id.b.domain; + els_iocb->control_flags = 0; + els_iocb->rx_byte_count = + cpu_to_le32(bsg_job->reply_payload.payload_len); + els_iocb->tx_byte_count = + cpu_to_le32(bsg_job->request_payload.payload_len); + + els_iocb->tx_address[0] = cpu_to_le32(LSD(sg_dma_address + (bsg_job->request_payload.sg_list))); + els_iocb->tx_address[1] = cpu_to_le32(MSD(sg_dma_address + (bsg_job->request_payload.sg_list))); + els_iocb->tx_len = cpu_to_le32(sg_dma_len + (bsg_job->request_payload.sg_list)); + + els_iocb->rx_address[0] = cpu_to_le32(LSD(sg_dma_address + (bsg_job->reply_payload.sg_list))); + els_iocb->rx_address[1] = cpu_to_le32(MSD(sg_dma_address + (bsg_job->reply_payload.sg_list))); + els_iocb->rx_len = cpu_to_le32(sg_dma_len + (bsg_job->reply_payload.sg_list)); +} + +static void +qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) +{ + uint16_t avail_dsds; + uint32_t *cur_dsd; + struct scatterlist *sg; + int index; + uint16_t tot_dsds; + scsi_qla_host_t *vha = sp->fcport->vha; + struct fc_bsg_job *bsg_job = ((struct srb_bsg*)sp->ctx)->bsg_job; + int loop_iterartion = 0; + int cont_iocb_prsnt = 0; + int entry_count = 1; + + ct_iocb->entry_type = CT_IOCB_TYPE; + ct_iocb->entry_status = 0; + ct_iocb->sys_define = 0; + ct_iocb->handle = sp->handle; + + ct_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); + ct_iocb->vp_index = sp->fcport->vp_idx; + ct_iocb->comp_status = __constant_cpu_to_le16(0); + + ct_iocb->cmd_dsd_count = + __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt); + ct_iocb->timeout = 0; + ct_iocb->rsp_dsd_count = + __constant_cpu_to_le16(bsg_job->reply_payload.sg_cnt); + ct_iocb->rsp_byte_count = + cpu_to_le32(bsg_job->reply_payload.payload_len); + ct_iocb->cmd_byte_count = + cpu_to_le32(bsg_job->request_payload.payload_len); + ct_iocb->dseg_0_address[0] = cpu_to_le32(LSD(sg_dma_address + (bsg_job->request_payload.sg_list))); + ct_iocb->dseg_0_address[1] = cpu_to_le32(MSD(sg_dma_address + (bsg_job->request_payload.sg_list))); + ct_iocb->dseg_0_len = cpu_to_le32(sg_dma_len + (bsg_job->request_payload.sg_list)); + + avail_dsds = 1; + cur_dsd = (uint32_t *)ct_iocb->dseg_1_address; + index = 0; + tot_dsds = bsg_job->reply_payload.sg_cnt; + + for_each_sg(bsg_job->reply_payload.sg_list, sg, tot_dsds, index) { + dma_addr_t sle_dma; + cont_a64_entry_t *cont_pkt; + + /* Allocate additional continuation packets? */ + if (avail_dsds == 0) { + /* + * Five DSDs are available in the Cont. + * Type 1 IOCB. + */ + cont_pkt = qla2x00_prep_cont_type1_iocb(vha); + cur_dsd = (uint32_t *) cont_pkt->dseg_0_address; + avail_dsds = 5; + cont_iocb_prsnt = 1; + entry_count++; + } + + sle_dma = sg_dma_address(sg); + *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + loop_iterartion++; + avail_dsds--; + } + ct_iocb->entry_count = entry_count; +} + int qla2x00_start_sp(srb_t *sp) { @@ -1052,6 +1165,13 @@ qla2x00_start_sp(srb_t *sp) qla24xx_logout_iocb(sp, pkt): qla2x00_logout_iocb(sp, pkt); break; + case SRB_ELS_CMD_RPT: + case SRB_ELS_CMD_HST: + qla24xx_els_iocb(sp, pkt); + break; + case SRB_CT_CMD: + qla24xx_ct_iocb(sp, pkt); + break; default: break; } diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 5613456dbbb1..09ba26bc230c 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -8,6 +8,7 @@ #include #include +#include static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t); static void qla2x00_process_completed_request(struct scsi_qla_host *, @@ -881,7 +882,9 @@ qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func, index); return NULL; } + req->outstanding_cmds[index] = NULL; + done: return sp; } @@ -981,6 +984,100 @@ done_post_logio_done_work: lio->ctx.free(sp); } +static void +qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, + struct sts_entry_24xx *pkt, int iocb_type) +{ + const char func[] = "ELS_CT_IOCB"; + const char *type; + struct qla_hw_data *ha = vha->hw; + srb_t *sp; + struct srb_bsg *sp_bsg; + struct fc_bsg_job *bsg_job; + uint16_t comp_status; + uint32_t fw_status[3]; + uint8_t* fw_sts_ptr; + + sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); + if (!sp) + return; + sp_bsg = (struct srb_bsg*)sp->ctx; + bsg_job = sp_bsg->bsg_job; + + type = NULL; + switch (sp_bsg->ctx.type) { + case SRB_ELS_CMD_RPT: + case SRB_ELS_CMD_HST: + type = "els"; + break; + case SRB_CT_CMD: + type = "ct pass-through"; + break; + default: + qla_printk(KERN_WARNING, ha, + "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp, + sp_bsg->ctx.type); + return; + } + + comp_status = fw_status[0] = le16_to_cpu(pkt->comp_status); + fw_status[1] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1); + fw_status[2] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2); + + /* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT + * fc payload to the caller + */ + bsg_job->reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK; + bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(fw_status); + + if (comp_status != CS_COMPLETE) { + if (comp_status == CS_DATA_UNDERRUN) { + bsg_job->reply->result = DID_OK << 16; + bsg_job->reply->reply_payload_rcv_len = + le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count); + + DEBUG2(qla_printk(KERN_WARNING, ha, + "scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x " + "error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n", + vha->host_no, sp->handle, type, comp_status, fw_status[1], fw_status[2], + le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count))); + fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); + memcpy( fw_sts_ptr, fw_status, sizeof(fw_status)); + } + else { + DEBUG2(qla_printk(KERN_WARNING, ha, + "scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x " + "error subcode 1=0x%x error subcode 2=0x%x.\n", + vha->host_no, sp->handle, type, comp_status, + le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1), + le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2))); + bsg_job->reply->result = DID_ERROR << 16; + bsg_job->reply->reply_payload_rcv_len = 0; + fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); + memcpy( fw_sts_ptr, fw_status, sizeof(fw_status)); + } + DEBUG2(qla2x00_dump_buffer((uint8_t *)pkt, sizeof(*pkt))); + } + else { + bsg_job->reply->result = DID_OK << 16;; + bsg_job->reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len; + bsg_job->reply_len = 0; + } + + dma_unmap_sg(&ha->pdev->dev, + bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); + dma_unmap_sg(&ha->pdev->dev, + bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + if ((sp_bsg->ctx.type == SRB_ELS_CMD_HST) || + (sp_bsg->ctx.type == SRB_CT_CMD)) + kfree(sp->fcport); + kfree(sp->ctx); + mempool_free(sp, ha->srb_mempool); + bsg_job->job_done(bsg_job); +} + static void qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, struct logio_entry_24xx *logio) @@ -1749,6 +1846,13 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, qla24xx_logio_entry(vha, rsp->req, (struct logio_entry_24xx *)pkt); break; + case CT_IOCB_TYPE: + qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE); + clear_bit(MBX_INTERRUPT, &vha->hw->mbx_cmd_flags); + break; + case ELS_IOCB_TYPE: + qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE); + break; default: /* Type Not Supported. */ DEBUG4(printk(KERN_WARNING @@ -2046,7 +2150,6 @@ qla24xx_msix_default(int irq, void *dev_id) set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); complete(&ha->mbx_intr_comp); } - return IRQ_HANDLED; } diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 056e4d4505f3..6e53bdbb1da8 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -3635,6 +3635,157 @@ qla2x00_read_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t *data) return rval; } +int +qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *mresp) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + uint32_t iter_cnt = 0x1; + + DEBUG11(printk("scsi(%ld): entered.\n", vha->host_no)); + + memset(mcp->mb, 0 , sizeof(mcp->mb)); + mcp->mb[0] = MBC_DIAGNOSTIC_LOOP_BACK; + mcp->mb[1] = mreq->options | BIT_6; // BIT_6 specifies 64 bit addressing + + /* transfer count */ + mcp->mb[10] = LSW(mreq->transfer_size); + mcp->mb[11] = MSW(mreq->transfer_size); + + /* send data address */ + mcp->mb[14] = LSW(mreq->send_dma); + mcp->mb[15] = MSW(mreq->send_dma); + mcp->mb[20] = LSW(MSD(mreq->send_dma)); + mcp->mb[21] = MSW(MSD(mreq->send_dma)); + + /* recieve data address */ + mcp->mb[16] = LSW(mreq->rcv_dma); + mcp->mb[17] = MSW(mreq->rcv_dma); + mcp->mb[6] = LSW(MSD(mreq->rcv_dma)); + mcp->mb[7] = MSW(MSD(mreq->rcv_dma)); + + /* Iteration count */ + mcp->mb[18] = LSW(iter_cnt); + mcp->mb[19] = MSW(iter_cnt); + + mcp->out_mb = MBX_21|MBX_20|MBX_19|MBX_18|MBX_17|MBX_16|MBX_15| + MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_7|MBX_6|MBX_1|MBX_0; + if (IS_QLA81XX(vha->hw)) + mcp->out_mb |= MBX_2; + mcp->in_mb = MBX_19|MBX_18|MBX_3|MBX_2|MBX_1|MBX_0; + + mcp->buf_size = mreq->transfer_size; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD; + + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2(printk(KERN_WARNING + "(%ld): failed=%x mb[0]=0x%x " + "mb[1]=0x%x mb[2]=0x%x mb[3]=0x%x mb[18]=0x%x mb[19]=0x%x. \n", vha->host_no, rval, + mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3], mcp->mb[18], mcp->mb[19])); + } else { + DEBUG2(printk(KERN_WARNING + "scsi(%ld): done.\n", vha->host_no)); + } + + /* Copy mailbox information */ + memcpy( mresp, mcp->mb, 64); + mresp[3] = mcp->mb[18]; + mresp[4] = mcp->mb[19]; + return rval; +} + +int +qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *mresp) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + struct qla_hw_data *ha = vha->hw; + + DEBUG11(printk("scsi(%ld): entered.\n", vha->host_no)); + + memset(mcp->mb, 0 , sizeof(mcp->mb)); + mcp->mb[0] = MBC_DIAGNOSTIC_ECHO; + mcp->mb[1] = mreq->options | BIT_6; /* BIT_6 specifies 64bit address */ + if (IS_QLA81XX(ha)) + mcp->mb[1] |= BIT_15; + mcp->mb[2] = IS_QLA81XX(ha) ? vha->fcoe_fcf_idx : 0; + mcp->mb[16] = LSW(mreq->rcv_dma); + mcp->mb[17] = MSW(mreq->rcv_dma); + mcp->mb[6] = LSW(MSD(mreq->rcv_dma)); + mcp->mb[7] = MSW(MSD(mreq->rcv_dma)); + + mcp->mb[10] = LSW(mreq->transfer_size); + + mcp->mb[14] = LSW(mreq->send_dma); + mcp->mb[15] = MSW(mreq->send_dma); + mcp->mb[20] = LSW(MSD(mreq->send_dma)); + mcp->mb[21] = MSW(MSD(mreq->send_dma)); + + mcp->out_mb = MBX_21|MBX_20|MBX_17|MBX_16|MBX_15| + MBX_14|MBX_10|MBX_7|MBX_6|MBX_1|MBX_0; + if (IS_QLA81XX(ha)) + mcp->out_mb |= MBX_2; + + mcp->in_mb = MBX_0; + if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha)) + mcp->in_mb |= MBX_1; + if (IS_QLA81XX(ha)) + mcp->in_mb |= MBX_3; + + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD; + mcp->buf_size = mreq->transfer_size; + + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2(printk(KERN_WARNING + "(%ld): failed=%x mb[0]=0x%x mb[1]=0x%x.\n", + vha->host_no, rval, mcp->mb[0], mcp->mb[1])); + } else { + DEBUG2(printk(KERN_WARNING + "scsi(%ld): done.\n", vha->host_no)); + } + + /* Copy mailbox information */ + memcpy( mresp, mcp->mb, 32); + return rval; +} +int +qla84xx_reset_chip(scsi_qla_host_t *ha, uint16_t enable_diagnostic, + uint16_t *cmd_status) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG16(printk("%s(%ld): enable_diag=%d entered.\n", __func__, + ha->host_no, enable_diagnostic)); + + mcp->mb[0] = MBC_ISP84XX_RESET; + mcp->mb[1] = enable_diagnostic; + mcp->out_mb = MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD; + rval = qla2x00_mailbox_command(ha, mcp); + + /* Return mailbox statuses. */ + *cmd_status = mcp->mb[0]; + if (rval != QLA_SUCCESS) + DEBUG16(printk("%s(%ld): failed=%x.\n", __func__, ha->host_no, + rval)); + else + DEBUG16(printk("%s(%ld): done.\n", __func__, ha->host_no)); + + return rval; +} + int qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data) { diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index fe34b7f9dee6..15ddfc435ea8 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1969,6 +1969,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) host->max_channel = MAX_BUSES - 1; host->max_lun = MAX_LUNS; host->transportt = qla2xxx_transport_template; + sht->vendor_id = (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC); /* Set up the irqs */ ret = qla2x00_request_irqs(ha, rsp); -- cgit v1.2.2 From f8ac60855ebfa239319a4a9945799995feda3b06 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Tue, 12 Jan 2010 13:02:48 -0800 Subject: [SCSI] qla2xxx: Remove firmware hint for 81xx parts. Firmware is loaded from flash for these ISP types. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 15ddfc435ea8..ddc1d3def36c 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3545,4 +3545,3 @@ MODULE_FIRMWARE(FW_FILE_ISP2300); MODULE_FIRMWARE(FW_FILE_ISP2322); MODULE_FIRMWARE(FW_FILE_ISP24XX); MODULE_FIRMWARE(FW_FILE_ISP25XX); -MODULE_FIRMWARE(FW_FILE_ISP81XX); -- cgit v1.2.2 From e8a392444d338d3ce77d157bcbe4975828536efa Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Tue, 12 Jan 2010 13:02:49 -0800 Subject: [SCSI] qla2xxx: Update version number to 8.03.02-k0. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index ed36279a33c1..082394b1ec07 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,9 +7,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.03.01-k10" +#define QLA2XXX_VERSION "8.03.02-k0" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 3 -#define QLA_DRIVER_PATCH_VER 1 +#define QLA_DRIVER_PATCH_VER 2 #define QLA_DRIVER_BETA_VER 0 -- cgit v1.2.2 From 8605c46c171f02859fb3a32655fa226ce446c6ec Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sun, 17 Jan 2010 21:19:31 +0200 Subject: [SCSI] lpfc: restore MSI-X/MSI support A Gentoo bug report [1] showed that as of 2.6.31 lpfc only uses INTx interrupts. This patch restores lpfc's ability to support MSI-X/MSI interrupts that the "Addition of SLI4 Interface - Base Support" patch [2] broke. It reestablishes MSI-X as the default interrupt method and in case MSI-X is not supported lpfc_sli{4,}_enable_intr fallbacks to MSI and then to INTx. [1]: http://bugs.gentoo.org/show_bug.cgi?id=296319 [2]: commit da0436e915a5c17ee79e72c1bf978a4ebb1cbf4d [James Smart: Background: Nothing Broke. This was intended. We had originally enabled MSI-X by default, but in qualification within the last 12 months, we encountered a major catch-22: There were at least 4 platforms, from 2 major OEMs, that : - Say they support MSI-X - platform routines work and act as if they do. - We enable it, generate a test interrupt to check they really do deliver it, and it works. - But shortly after attachment, the system hangs or loses interrupts, resulting in a bad system behavior. Given the distro's picking up the 2.6.32 kernel, we had to stick with a default of MSI-X off, with user-enabled MSI-X as these platforms couldn't get fixed. However, we're also now encountering platforms that require MSI-X and never INTx, so we must change. It's desired also for also for performance reasons. So - now (2.6.33) is the right time to re-enable MSI-X by default. ] [jejb: fix up comment on default values] Signed-off-by: George Kadianakis Acked-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_attr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 91542f786edf..a8908e7c368a 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -3114,12 +3114,12 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255, /* # lpfc_use_msi: Use MSI (Message Signaled Interrupts) in systems that # support this feature -# 0 = MSI disabled (default) +# 0 = MSI disabled # 1 = MSI enabled -# 2 = MSI-X enabled -# Value range is [0,2]. Default value is 0. +# 2 = MSI-X enabled (default) +# Value range is [0,2]. Default value is 2. */ -LPFC_ATTR_R(use_msi, 0, 0, 2, "Use Message Signaled Interrupts (1) or " +LPFC_ATTR_R(use_msi, 2, 0, 2, "Use Message Signaled Interrupts (1) or " "MSI-X (2), if possible"); /* -- cgit v1.2.2 From 50dd3145a58b5cef03a95c1b98765bcc847a72d0 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 19 Jan 2010 13:52:28 +0000 Subject: sh: update PFC to allow any enum in MARK lists This patch updates the PFC code with some clarifying comments together with a functional change. The change allows function type of GPIO to select any type of enum in their MARK lists. Without this patch only function type of enums are allowed in MARK lists. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/sh/pfc.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/sh/pfc.c b/drivers/sh/pfc.c index 082604edc4c2..cf0303acab8e 100644 --- a/drivers/sh/pfc.c +++ b/drivers/sh/pfc.c @@ -337,12 +337,39 @@ static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio, if (!enum_id) break; + /* first check if this is a function enum */ in_range = enum_in_range(enum_id, &gpioc->function); - if (!in_range && range) { - in_range = enum_in_range(enum_id, range); - - if (in_range && enum_id == range->force) - continue; + if (!in_range) { + /* not a function enum */ + if (range) { + /* + * other range exists, so this pin is + * a regular GPIO pin that now is being + * bound to a specific direction. + * + * for this case we only allow function enums + * and the enums that match the other range. + */ + in_range = enum_in_range(enum_id, range); + + /* + * special case pass through for fixed + * input-only or output-only pins without + * function enum register association. + */ + if (in_range && enum_id == range->force) + continue; + } else { + /* + * no other range exists, so this pin + * must then be of the function type. + * + * allow function type pins to select + * any combination of function/in/out + * in their MARK lists. + */ + in_range = 1; + } } if (!in_range) -- cgit v1.2.2 From 358934a60d2180dcd1ed20691dbb66d4fb977ab2 Mon Sep 17 00:00:00 2001 From: Sandeep Paulraj Date: Wed, 16 Dec 2009 22:02:18 +0000 Subject: spi: Add SPI master driver for DaVinci/DA8xx This patch adds support for a SPI master driver for the DaVinci series of SOCs Signed-off-by: Sandeep Paulraj Signed-off-by: Mark A. Greer Signed-off-by: Philby John Signed-off-by: Sudhakar Rajashekhara Signed-off-by: Kevin Hilman Signed-off-by: Grant Likely --- drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/davinci_spi.c | 1255 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1263 insertions(+) create mode 100644 drivers/spi/davinci_spi.c (limited to 'drivers') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index f55eb0107336..82dabbca00c1 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -100,6 +100,13 @@ config SPI_BUTTERFLY inexpensive battery powered microcontroller evaluation board. This same cable can be used to flash new firmware. +config SPI_DAVINCI + tristate "SPI controller driver for DaVinci/DA8xx SoC's" + depends on SPI_MASTER && ARCH_DAVINCI + select SPI_BITBANG + help + SPI master controller for DaVinci and DA8xx SPI modules. + config SPI_GPIO tristate "GPIO-based bitbanging SPI Master" depends on GENERIC_GPIO diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index f3d2810ba11c..84b490fb7f8a 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o obj-$(CONFIG_SPI_AU1550) += au1550_spi.o obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o +obj-$(CONFIG_SPI_DAVINCI) += davinci_spi.o obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.o obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o obj-$(CONFIG_SPI_GPIO) += spi_gpio.o diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c new file mode 100644 index 000000000000..225ab60b02c4 --- /dev/null +++ b/drivers/spi/davinci_spi.c @@ -0,0 +1,1255 @@ +/* + * Copyright (C) 2009 Texas Instruments. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define SPI_NO_RESOURCE ((resource_size_t)-1) + +#define SPI_MAX_CHIPSELECT 2 + +#define CS_DEFAULT 0xFF + +#define SPI_BUFSIZ (SMP_CACHE_BYTES + 1) +#define DAVINCI_DMA_DATA_TYPE_S8 0x01 +#define DAVINCI_DMA_DATA_TYPE_S16 0x02 +#define DAVINCI_DMA_DATA_TYPE_S32 0x04 + +#define SPIFMT_PHASE_MASK BIT(16) +#define SPIFMT_POLARITY_MASK BIT(17) +#define SPIFMT_DISTIMER_MASK BIT(18) +#define SPIFMT_SHIFTDIR_MASK BIT(20) +#define SPIFMT_WAITENA_MASK BIT(21) +#define SPIFMT_PARITYENA_MASK BIT(22) +#define SPIFMT_ODD_PARITY_MASK BIT(23) +#define SPIFMT_WDELAY_MASK 0x3f000000u +#define SPIFMT_WDELAY_SHIFT 24 +#define SPIFMT_CHARLEN_MASK 0x0000001Fu + +/* SPIGCR1 */ +#define SPIGCR1_SPIENA_MASK 0x01000000u + +/* SPIPC0 */ +#define SPIPC0_DIFUN_MASK BIT(11) /* MISO */ +#define SPIPC0_DOFUN_MASK BIT(10) /* MOSI */ +#define SPIPC0_CLKFUN_MASK BIT(9) /* CLK */ +#define SPIPC0_SPIENA_MASK BIT(8) /* nREADY */ +#define SPIPC0_EN1FUN_MASK BIT(1) +#define SPIPC0_EN0FUN_MASK BIT(0) + +#define SPIINT_MASKALL 0x0101035F +#define SPI_INTLVL_1 0x000001FFu +#define SPI_INTLVL_0 0x00000000u + +/* SPIDAT1 */ +#define SPIDAT1_CSHOLD_SHIFT 28 +#define SPIDAT1_CSNR_SHIFT 16 +#define SPIGCR1_CLKMOD_MASK BIT(1) +#define SPIGCR1_MASTER_MASK BIT(0) +#define SPIGCR1_LOOPBACK_MASK BIT(16) + +/* SPIBUF */ +#define SPIBUF_TXFULL_MASK BIT(29) +#define SPIBUF_RXEMPTY_MASK BIT(31) + +/* Error Masks */ +#define SPIFLG_DLEN_ERR_MASK BIT(0) +#define SPIFLG_TIMEOUT_MASK BIT(1) +#define SPIFLG_PARERR_MASK BIT(2) +#define SPIFLG_DESYNC_MASK BIT(3) +#define SPIFLG_BITERR_MASK BIT(4) +#define SPIFLG_OVRRUN_MASK BIT(6) +#define SPIFLG_RX_INTR_MASK BIT(8) +#define SPIFLG_TX_INTR_MASK BIT(9) +#define SPIFLG_BUF_INIT_ACTIVE_MASK BIT(24) +#define SPIFLG_MASK (SPIFLG_DLEN_ERR_MASK \ + | SPIFLG_TIMEOUT_MASK | SPIFLG_PARERR_MASK \ + | SPIFLG_DESYNC_MASK | SPIFLG_BITERR_MASK \ + | SPIFLG_OVRRUN_MASK | SPIFLG_RX_INTR_MASK \ + | SPIFLG_TX_INTR_MASK \ + | SPIFLG_BUF_INIT_ACTIVE_MASK) + +#define SPIINT_DLEN_ERR_INTR BIT(0) +#define SPIINT_TIMEOUT_INTR BIT(1) +#define SPIINT_PARERR_INTR BIT(2) +#define SPIINT_DESYNC_INTR BIT(3) +#define SPIINT_BITERR_INTR BIT(4) +#define SPIINT_OVRRUN_INTR BIT(6) +#define SPIINT_RX_INTR BIT(8) +#define SPIINT_TX_INTR BIT(9) +#define SPIINT_DMA_REQ_EN BIT(16) +#define SPIINT_ENABLE_HIGHZ BIT(24) + +#define SPI_T2CDELAY_SHIFT 16 +#define SPI_C2TDELAY_SHIFT 24 + +/* SPI Controller registers */ +#define SPIGCR0 0x00 +#define SPIGCR1 0x04 +#define SPIINT 0x08 +#define SPILVL 0x0c +#define SPIFLG 0x10 +#define SPIPC0 0x14 +#define SPIPC1 0x18 +#define SPIPC2 0x1c +#define SPIPC3 0x20 +#define SPIPC4 0x24 +#define SPIPC5 0x28 +#define SPIPC6 0x2c +#define SPIPC7 0x30 +#define SPIPC8 0x34 +#define SPIDAT0 0x38 +#define SPIDAT1 0x3c +#define SPIBUF 0x40 +#define SPIEMU 0x44 +#define SPIDELAY 0x48 +#define SPIDEF 0x4c +#define SPIFMT0 0x50 +#define SPIFMT1 0x54 +#define SPIFMT2 0x58 +#define SPIFMT3 0x5c +#define TGINTVEC0 0x60 +#define TGINTVEC1 0x64 + +struct davinci_spi_slave { + u32 cmd_to_write; + u32 clk_ctrl_to_write; + u32 bytes_per_word; + u8 active_cs; +}; + +/* We have 2 DMA channels per CS, one for RX and one for TX */ +struct davinci_spi_dma { + int dma_tx_channel; + int dma_rx_channel; + int dma_tx_sync_dev; + int dma_rx_sync_dev; + enum dma_event_q eventq; + + struct completion dma_tx_completion; + struct completion dma_rx_completion; +}; + +/* SPI Controller driver's private data. */ +struct davinci_spi { + struct spi_bitbang bitbang; + struct clk *clk; + + u8 version; + resource_size_t pbase; + void __iomem *base; + size_t region_size; + u32 irq; + struct completion done; + + const void *tx; + void *rx; + u8 *tmp_buf; + int count; + struct davinci_spi_dma *dma_channels; + struct davinci_spi_platform_data *pdata; + + void (*get_rx)(u32 rx_data, struct davinci_spi *); + u32 (*get_tx)(struct davinci_spi *); + + struct davinci_spi_slave slave[SPI_MAX_CHIPSELECT]; +}; + +static unsigned use_dma; + +static void davinci_spi_rx_buf_u8(u32 data, struct davinci_spi *davinci_spi) +{ + u8 *rx = davinci_spi->rx; + + *rx++ = (u8)data; + davinci_spi->rx = rx; +} + +static void davinci_spi_rx_buf_u16(u32 data, struct davinci_spi *davinci_spi) +{ + u16 *rx = davinci_spi->rx; + + *rx++ = (u16)data; + davinci_spi->rx = rx; +} + +static u32 davinci_spi_tx_buf_u8(struct davinci_spi *davinci_spi) +{ + u32 data; + const u8 *tx = davinci_spi->tx; + + data = *tx++; + davinci_spi->tx = tx; + return data; +} + +static u32 davinci_spi_tx_buf_u16(struct davinci_spi *davinci_spi) +{ + u32 data; + const u16 *tx = davinci_spi->tx; + + data = *tx++; + davinci_spi->tx = tx; + return data; +} + +static inline void set_io_bits(void __iomem *addr, u32 bits) +{ + u32 v = ioread32(addr); + + v |= bits; + iowrite32(v, addr); +} + +static inline void clear_io_bits(void __iomem *addr, u32 bits) +{ + u32 v = ioread32(addr); + + v &= ~bits; + iowrite32(v, addr); +} + +static inline void set_fmt_bits(void __iomem *addr, u32 bits, int cs_num) +{ + set_io_bits(addr + SPIFMT0 + (0x4 * cs_num), bits); +} + +static inline void clear_fmt_bits(void __iomem *addr, u32 bits, int cs_num) +{ + clear_io_bits(addr + SPIFMT0 + (0x4 * cs_num), bits); +} + +static void davinci_spi_set_dma_req(const struct spi_device *spi, int enable) +{ + struct davinci_spi *davinci_spi = spi_master_get_devdata(spi->master); + + if (enable) + set_io_bits(davinci_spi->base + SPIINT, SPIINT_DMA_REQ_EN); + else + clear_io_bits(davinci_spi->base + SPIINT, SPIINT_DMA_REQ_EN); +} + +/* + * Interface to control the chip select signal + */ +static void davinci_spi_chipselect(struct spi_device *spi, int value) +{ + struct davinci_spi *davinci_spi; + struct davinci_spi_platform_data *pdata; + u32 data1_reg_val = 0; + + davinci_spi = spi_master_get_devdata(spi->master); + pdata = davinci_spi->pdata; + + /* + * Board specific chip select logic decides the polarity and cs + * line for the controller + */ + if (value == BITBANG_CS_INACTIVE) { + set_io_bits(davinci_spi->base + SPIDEF, CS_DEFAULT); + + data1_reg_val |= CS_DEFAULT << SPIDAT1_CSNR_SHIFT; + iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1); + + while ((ioread32(davinci_spi->base + SPIBUF) + & SPIBUF_RXEMPTY_MASK) == 0) + cpu_relax(); + } +} + +/** + * davinci_spi_setup_transfer - This functions will determine transfer method + * @spi: spi device on which data transfer to be done + * @t: spi transfer in which transfer info is filled + * + * This function determines data transfer method (8/16/32 bit transfer). + * It will also set the SPI Clock Control register according to + * SPI slave device freq. + */ +static int davinci_spi_setup_transfer(struct spi_device *spi, + struct spi_transfer *t) +{ + + struct davinci_spi *davinci_spi; + struct davinci_spi_platform_data *pdata; + u8 bits_per_word = 0; + u32 hz = 0, prescale; + + davinci_spi = spi_master_get_devdata(spi->master); + pdata = davinci_spi->pdata; + + if (t) { + bits_per_word = t->bits_per_word; + hz = t->speed_hz; + } + + /* if bits_per_word is not set then set it default */ + if (!bits_per_word) + bits_per_word = spi->bits_per_word; + + /* + * Assign function pointer to appropriate transfer method + * 8bit, 16bit or 32bit transfer + */ + if (bits_per_word <= 8 && bits_per_word >= 2) { + davinci_spi->get_rx = davinci_spi_rx_buf_u8; + davinci_spi->get_tx = davinci_spi_tx_buf_u8; + davinci_spi->slave[spi->chip_select].bytes_per_word = 1; + } else if (bits_per_word <= 16 && bits_per_word >= 2) { + davinci_spi->get_rx = davinci_spi_rx_buf_u16; + davinci_spi->get_tx = davinci_spi_tx_buf_u16; + davinci_spi->slave[spi->chip_select].bytes_per_word = 2; + } else + return -EINVAL; + + if (!hz) + hz = spi->max_speed_hz; + + clear_fmt_bits(davinci_spi->base, SPIFMT_CHARLEN_MASK, + spi->chip_select); + set_fmt_bits(davinci_spi->base, bits_per_word & 0x1f, + spi->chip_select); + + prescale = ((clk_get_rate(davinci_spi->clk) / hz) - 1) & 0xff; + + clear_fmt_bits(davinci_spi->base, 0x0000ff00, spi->chip_select); + set_fmt_bits(davinci_spi->base, prescale << 8, spi->chip_select); + + return 0; +} + +static void davinci_spi_dma_rx_callback(unsigned lch, u16 ch_status, void *data) +{ + struct spi_device *spi = (struct spi_device *)data; + struct davinci_spi *davinci_spi; + struct davinci_spi_dma *davinci_spi_dma; + struct davinci_spi_platform_data *pdata; + + davinci_spi = spi_master_get_devdata(spi->master); + davinci_spi_dma = &(davinci_spi->dma_channels[spi->chip_select]); + pdata = davinci_spi->pdata; + + if (ch_status == DMA_COMPLETE) + edma_stop(davinci_spi_dma->dma_rx_channel); + else + edma_clean_channel(davinci_spi_dma->dma_rx_channel); + + complete(&davinci_spi_dma->dma_rx_completion); + /* We must disable the DMA RX request */ + davinci_spi_set_dma_req(spi, 0); +} + +static void davinci_spi_dma_tx_callback(unsigned lch, u16 ch_status, void *data) +{ + struct spi_device *spi = (struct spi_device *)data; + struct davinci_spi *davinci_spi; + struct davinci_spi_dma *davinci_spi_dma; + struct davinci_spi_platform_data *pdata; + + davinci_spi = spi_master_get_devdata(spi->master); + davinci_spi_dma = &(davinci_spi->dma_channels[spi->chip_select]); + pdata = davinci_spi->pdata; + + if (ch_status == DMA_COMPLETE) + edma_stop(davinci_spi_dma->dma_tx_channel); + else + edma_clean_channel(davinci_spi_dma->dma_tx_channel); + + complete(&davinci_spi_dma->dma_tx_completion); + /* We must disable the DMA TX request */ + davinci_spi_set_dma_req(spi, 0); +} + +static int davinci_spi_request_dma(struct spi_device *spi) +{ + struct davinci_spi *davinci_spi; + struct davinci_spi_dma *davinci_spi_dma; + struct davinci_spi_platform_data *pdata; + struct device *sdev; + int r; + + davinci_spi = spi_master_get_devdata(spi->master); + davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select]; + pdata = davinci_spi->pdata; + sdev = davinci_spi->bitbang.master->dev.parent; + + r = edma_alloc_channel(davinci_spi_dma->dma_rx_sync_dev, + davinci_spi_dma_rx_callback, spi, + davinci_spi_dma->eventq); + if (r < 0) { + dev_dbg(sdev, "Unable to request DMA channel for SPI RX\n"); + return -EAGAIN; + } + davinci_spi_dma->dma_rx_channel = r; + r = edma_alloc_channel(davinci_spi_dma->dma_tx_sync_dev, + davinci_spi_dma_tx_callback, spi, + davinci_spi_dma->eventq); + if (r < 0) { + edma_free_channel(davinci_spi_dma->dma_rx_channel); + davinci_spi_dma->dma_rx_channel = -1; + dev_dbg(sdev, "Unable to request DMA channel for SPI TX\n"); + return -EAGAIN; + } + davinci_spi_dma->dma_tx_channel = r; + + return 0; +} + +/** + * davinci_spi_setup - This functions will set default transfer method + * @spi: spi device on which data transfer to be done + * + * This functions sets the default transfer method. + */ + +static int davinci_spi_setup(struct spi_device *spi) +{ + int retval; + struct davinci_spi *davinci_spi; + struct davinci_spi_dma *davinci_spi_dma; + struct device *sdev; + + davinci_spi = spi_master_get_devdata(spi->master); + sdev = davinci_spi->bitbang.master->dev.parent; + + /* if bits per word length is zero then set it default 8 */ + if (!spi->bits_per_word) + spi->bits_per_word = 8; + + davinci_spi->slave[spi->chip_select].cmd_to_write = 0; + + if (use_dma && davinci_spi->dma_channels) { + davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select]; + + if ((davinci_spi_dma->dma_rx_channel == -1) + || (davinci_spi_dma->dma_tx_channel == -1)) { + retval = davinci_spi_request_dma(spi); + if (retval < 0) + return retval; + } + } + + /* + * SPI in DaVinci and DA8xx operate between + * 600 KHz and 50 MHz + */ + if (spi->max_speed_hz < 600000 || spi->max_speed_hz > 50000000) { + dev_dbg(sdev, "Operating frequency is not in acceptable " + "range\n"); + return -EINVAL; + } + + /* + * Set up SPIFMTn register, unique to this chipselect. + * + * NOTE: we could do all of these with one write. Also, some + * of the "version 2" features are found in chips that don't + * support all of them... + */ + if (spi->mode & SPI_LSB_FIRST) + set_fmt_bits(davinci_spi->base, SPIFMT_SHIFTDIR_MASK, + spi->chip_select); + else + clear_fmt_bits(davinci_spi->base, SPIFMT_SHIFTDIR_MASK, + spi->chip_select); + + if (spi->mode & SPI_CPOL) + set_fmt_bits(davinci_spi->base, SPIFMT_POLARITY_MASK, + spi->chip_select); + else + clear_fmt_bits(davinci_spi->base, SPIFMT_POLARITY_MASK, + spi->chip_select); + + if (!(spi->mode & SPI_CPHA)) + set_fmt_bits(davinci_spi->base, SPIFMT_PHASE_MASK, + spi->chip_select); + else + clear_fmt_bits(davinci_spi->base, SPIFMT_PHASE_MASK, + spi->chip_select); + + /* + * Version 1 hardware supports two basic SPI modes: + * - Standard SPI mode uses 4 pins, with chipselect + * - 3 pin SPI is a 4 pin variant without CS (SPI_NO_CS) + * (distinct from SPI_3WIRE, with just one data wire; + * or similar variants without MOSI or without MISO) + * + * Version 2 hardware supports an optional handshaking signal, + * so it can support two more modes: + * - 5 pin SPI variant is standard SPI plus SPI_READY + * - 4 pin with enable is (SPI_READY | SPI_NO_CS) + */ + + if (davinci_spi->version == SPI_VERSION_2) { + clear_fmt_bits(davinci_spi->base, SPIFMT_WDELAY_MASK, + spi->chip_select); + set_fmt_bits(davinci_spi->base, + (davinci_spi->pdata->wdelay + << SPIFMT_WDELAY_SHIFT) + & SPIFMT_WDELAY_MASK, + spi->chip_select); + + if (davinci_spi->pdata->odd_parity) + set_fmt_bits(davinci_spi->base, + SPIFMT_ODD_PARITY_MASK, + spi->chip_select); + else + clear_fmt_bits(davinci_spi->base, + SPIFMT_ODD_PARITY_MASK, + spi->chip_select); + + if (davinci_spi->pdata->parity_enable) + set_fmt_bits(davinci_spi->base, + SPIFMT_PARITYENA_MASK, + spi->chip_select); + else + clear_fmt_bits(davinci_spi->base, + SPIFMT_PARITYENA_MASK, + spi->chip_select); + + if (davinci_spi->pdata->wait_enable) + set_fmt_bits(davinci_spi->base, + SPIFMT_WAITENA_MASK, + spi->chip_select); + else + clear_fmt_bits(davinci_spi->base, + SPIFMT_WAITENA_MASK, + spi->chip_select); + + if (davinci_spi->pdata->timer_disable) + set_fmt_bits(davinci_spi->base, + SPIFMT_DISTIMER_MASK, + spi->chip_select); + else + clear_fmt_bits(davinci_spi->base, + SPIFMT_DISTIMER_MASK, + spi->chip_select); + } + + retval = davinci_spi_setup_transfer(spi, NULL); + + return retval; +} + +static void davinci_spi_cleanup(struct spi_device *spi) +{ + struct davinci_spi *davinci_spi = spi_master_get_devdata(spi->master); + struct davinci_spi_dma *davinci_spi_dma; + + davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select]; + + if (use_dma && davinci_spi->dma_channels) { + davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select]; + + if ((davinci_spi_dma->dma_rx_channel != -1) + && (davinci_spi_dma->dma_tx_channel != -1)) { + edma_free_channel(davinci_spi_dma->dma_tx_channel); + edma_free_channel(davinci_spi_dma->dma_rx_channel); + } + } +} + +static int davinci_spi_bufs_prep(struct spi_device *spi, + struct davinci_spi *davinci_spi) +{ + int op_mode = 0; + + /* + * REVISIT unless devices disagree about SPI_LOOP or + * SPI_READY (SPI_NO_CS only allows one device!), this + * should not need to be done before each message... + * optimize for both flags staying cleared. + */ + + op_mode = SPIPC0_DIFUN_MASK + | SPIPC0_DOFUN_MASK + | SPIPC0_CLKFUN_MASK; + if (!(spi->mode & SPI_NO_CS)) + op_mode |= 1 << spi->chip_select; + if (spi->mode & SPI_READY) + op_mode |= SPIPC0_SPIENA_MASK; + + iowrite32(op_mode, davinci_spi->base + SPIPC0); + + if (spi->mode & SPI_LOOP) + set_io_bits(davinci_spi->base + SPIGCR1, + SPIGCR1_LOOPBACK_MASK); + else + clear_io_bits(davinci_spi->base + SPIGCR1, + SPIGCR1_LOOPBACK_MASK); + + return 0; +} + +static int davinci_spi_check_error(struct davinci_spi *davinci_spi, + int int_status) +{ + struct device *sdev = davinci_spi->bitbang.master->dev.parent; + + if (int_status & SPIFLG_TIMEOUT_MASK) { + dev_dbg(sdev, "SPI Time-out Error\n"); + return -ETIMEDOUT; + } + if (int_status & SPIFLG_DESYNC_MASK) { + dev_dbg(sdev, "SPI Desynchronization Error\n"); + return -EIO; + } + if (int_status & SPIFLG_BITERR_MASK) { + dev_dbg(sdev, "SPI Bit error\n"); + return -EIO; + } + + if (davinci_spi->version == SPI_VERSION_2) { + if (int_status & SPIFLG_DLEN_ERR_MASK) { + dev_dbg(sdev, "SPI Data Length Error\n"); + return -EIO; + } + if (int_status & SPIFLG_PARERR_MASK) { + dev_dbg(sdev, "SPI Parity Error\n"); + return -EIO; + } + if (int_status & SPIFLG_OVRRUN_MASK) { + dev_dbg(sdev, "SPI Data Overrun error\n"); + return -EIO; + } + if (int_status & SPIFLG_TX_INTR_MASK) { + dev_dbg(sdev, "SPI TX intr bit set\n"); + return -EIO; + } + if (int_status & SPIFLG_BUF_INIT_ACTIVE_MASK) { + dev_dbg(sdev, "SPI Buffer Init Active\n"); + return -EBUSY; + } + } + + return 0; +} + +/** + * davinci_spi_bufs - functions which will handle transfer data + * @spi: spi device on which data transfer to be done + * @t: spi transfer in which transfer info is filled + * + * This function will put data to be transferred into data register + * of SPI controller and then wait until the completion will be marked + * by the IRQ Handler. + */ +static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t) +{ + struct davinci_spi *davinci_spi; + int int_status, count, ret; + u8 conv, tmp; + u32 tx_data, data1_reg_val; + u32 buf_val, flg_val; + struct davinci_spi_platform_data *pdata; + + davinci_spi = spi_master_get_devdata(spi->master); + pdata = davinci_spi->pdata; + + davinci_spi->tx = t->tx_buf; + davinci_spi->rx = t->rx_buf; + + /* convert len to words based on bits_per_word */ + conv = davinci_spi->slave[spi->chip_select].bytes_per_word; + davinci_spi->count = t->len / conv; + + INIT_COMPLETION(davinci_spi->done); + + ret = davinci_spi_bufs_prep(spi, davinci_spi); + if (ret) + return ret; + + /* Enable SPI */ + set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK); + + iowrite32(0 | (pdata->c2tdelay << SPI_C2TDELAY_SHIFT) | + (pdata->t2cdelay << SPI_T2CDELAY_SHIFT), + davinci_spi->base + SPIDELAY); + + count = davinci_spi->count; + data1_reg_val = pdata->cs_hold << SPIDAT1_CSHOLD_SHIFT; + tmp = ~(0x1 << spi->chip_select); + + clear_io_bits(davinci_spi->base + SPIDEF, ~tmp); + + data1_reg_val |= tmp << SPIDAT1_CSNR_SHIFT; + + while ((ioread32(davinci_spi->base + SPIBUF) + & SPIBUF_RXEMPTY_MASK) == 0) + cpu_relax(); + + /* Determine the command to execute READ or WRITE */ + if (t->tx_buf) { + clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL); + + while (1) { + tx_data = davinci_spi->get_tx(davinci_spi); + + data1_reg_val &= ~(0xFFFF); + data1_reg_val |= (0xFFFF & tx_data); + + buf_val = ioread32(davinci_spi->base + SPIBUF); + if ((buf_val & SPIBUF_TXFULL_MASK) == 0) { + iowrite32(data1_reg_val, + davinci_spi->base + SPIDAT1); + + count--; + } + while (ioread32(davinci_spi->base + SPIBUF) + & SPIBUF_RXEMPTY_MASK) + cpu_relax(); + + /* getting the returned byte */ + if (t->rx_buf) { + buf_val = ioread32(davinci_spi->base + SPIBUF); + davinci_spi->get_rx(buf_val, davinci_spi); + } + if (count <= 0) + break; + } + } else { + if (pdata->poll_mode) { + while (1) { + /* keeps the serial clock going */ + if ((ioread32(davinci_spi->base + SPIBUF) + & SPIBUF_TXFULL_MASK) == 0) + iowrite32(data1_reg_val, + davinci_spi->base + SPIDAT1); + + while (ioread32(davinci_spi->base + SPIBUF) & + SPIBUF_RXEMPTY_MASK) + cpu_relax(); + + flg_val = ioread32(davinci_spi->base + SPIFLG); + buf_val = ioread32(davinci_spi->base + SPIBUF); + + davinci_spi->get_rx(buf_val, davinci_spi); + + count--; + if (count <= 0) + break; + } + } else { /* Receive in Interrupt mode */ + int i; + + for (i = 0; i < davinci_spi->count; i++) { + set_io_bits(davinci_spi->base + SPIINT, + SPIINT_BITERR_INTR + | SPIINT_OVRRUN_INTR + | SPIINT_RX_INTR); + + iowrite32(data1_reg_val, + davinci_spi->base + SPIDAT1); + + while (ioread32(davinci_spi->base + SPIINT) & + SPIINT_RX_INTR) + cpu_relax(); + } + iowrite32((data1_reg_val & 0x0ffcffff), + davinci_spi->base + SPIDAT1); + } + } + + /* + * Check for bit error, desync error,parity error,timeout error and + * receive overflow errors + */ + int_status = ioread32(davinci_spi->base + SPIFLG); + + ret = davinci_spi_check_error(davinci_spi, int_status); + if (ret != 0) + return ret; + + /* SPI Framework maintains the count only in bytes so convert back */ + davinci_spi->count *= conv; + + return t->len; +} + +#define DAVINCI_DMA_DATA_TYPE_S8 0x01 +#define DAVINCI_DMA_DATA_TYPE_S16 0x02 +#define DAVINCI_DMA_DATA_TYPE_S32 0x04 + +static int davinci_spi_bufs_dma(struct spi_device *spi, struct spi_transfer *t) +{ + struct davinci_spi *davinci_spi; + int int_status = 0; + int count, temp_count; + u8 conv = 1; + u8 tmp; + u32 data1_reg_val; + struct davinci_spi_dma *davinci_spi_dma; + int word_len, data_type, ret; + unsigned long tx_reg, rx_reg; + struct davinci_spi_platform_data *pdata; + struct device *sdev; + + davinci_spi = spi_master_get_devdata(spi->master); + pdata = davinci_spi->pdata; + sdev = davinci_spi->bitbang.master->dev.parent; + + davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select]; + + tx_reg = (unsigned long)davinci_spi->pbase + SPIDAT1; + rx_reg = (unsigned long)davinci_spi->pbase + SPIBUF; + + davinci_spi->tx = t->tx_buf; + davinci_spi->rx = t->rx_buf; + + /* convert len to words based on bits_per_word */ + conv = davinci_spi->slave[spi->chip_select].bytes_per_word; + davinci_spi->count = t->len / conv; + + INIT_COMPLETION(davinci_spi->done); + + init_completion(&davinci_spi_dma->dma_rx_completion); + init_completion(&davinci_spi_dma->dma_tx_completion); + + word_len = conv * 8; + + if (word_len <= 8) + data_type = DAVINCI_DMA_DATA_TYPE_S8; + else if (word_len <= 16) + data_type = DAVINCI_DMA_DATA_TYPE_S16; + else if (word_len <= 32) + data_type = DAVINCI_DMA_DATA_TYPE_S32; + else + return -EINVAL; + + ret = davinci_spi_bufs_prep(spi, davinci_spi); + if (ret) + return ret; + + /* Put delay val if required */ + iowrite32(0 | (pdata->c2tdelay << SPI_C2TDELAY_SHIFT) | + (pdata->t2cdelay << SPI_T2CDELAY_SHIFT), + davinci_spi->base + SPIDELAY); + + count = davinci_spi->count; /* the number of elements */ + data1_reg_val = pdata->cs_hold << SPIDAT1_CSHOLD_SHIFT; + + /* CS default = 0xFF */ + tmp = ~(0x1 << spi->chip_select); + + clear_io_bits(davinci_spi->base + SPIDEF, ~tmp); + + data1_reg_val |= tmp << SPIDAT1_CSNR_SHIFT; + + /* disable all interrupts for dma transfers */ + clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL); + /* Disable SPI to write configuration bits in SPIDAT */ + clear_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK); + iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1); + /* Enable SPI */ + set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK); + + while ((ioread32(davinci_spi->base + SPIBUF) + & SPIBUF_RXEMPTY_MASK) == 0) + cpu_relax(); + + + if (t->tx_buf) { + t->tx_dma = dma_map_single(&spi->dev, (void *)t->tx_buf, count, + DMA_TO_DEVICE); + if (dma_mapping_error(&spi->dev, t->tx_dma)) { + dev_dbg(sdev, "Unable to DMA map a %d bytes" + " TX buffer\n", count); + return -ENOMEM; + } + temp_count = count; + } else { + /* We need TX clocking for RX transaction */ + t->tx_dma = dma_map_single(&spi->dev, + (void *)davinci_spi->tmp_buf, count + 1, + DMA_TO_DEVICE); + if (dma_mapping_error(&spi->dev, t->tx_dma)) { + dev_dbg(sdev, "Unable to DMA map a %d bytes" + " TX tmp buffer\n", count); + return -ENOMEM; + } + temp_count = count + 1; + } + + edma_set_transfer_params(davinci_spi_dma->dma_tx_channel, + data_type, temp_count, 1, 0, ASYNC); + edma_set_dest(davinci_spi_dma->dma_tx_channel, tx_reg, INCR, W8BIT); + edma_set_src(davinci_spi_dma->dma_tx_channel, t->tx_dma, INCR, W8BIT); + edma_set_src_index(davinci_spi_dma->dma_tx_channel, data_type, 0); + edma_set_dest_index(davinci_spi_dma->dma_tx_channel, 0, 0); + + if (t->rx_buf) { + /* initiate transaction */ + iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1); + + t->rx_dma = dma_map_single(&spi->dev, (void *)t->rx_buf, count, + DMA_FROM_DEVICE); + if (dma_mapping_error(&spi->dev, t->rx_dma)) { + dev_dbg(sdev, "Couldn't DMA map a %d bytes RX buffer\n", + count); + if (t->tx_buf != NULL) + dma_unmap_single(NULL, t->tx_dma, + count, DMA_TO_DEVICE); + return -ENOMEM; + } + edma_set_transfer_params(davinci_spi_dma->dma_rx_channel, + data_type, count, 1, 0, ASYNC); + edma_set_src(davinci_spi_dma->dma_rx_channel, + rx_reg, INCR, W8BIT); + edma_set_dest(davinci_spi_dma->dma_rx_channel, + t->rx_dma, INCR, W8BIT); + edma_set_src_index(davinci_spi_dma->dma_rx_channel, 0, 0); + edma_set_dest_index(davinci_spi_dma->dma_rx_channel, + data_type, 0); + } + + if ((t->tx_buf) || (t->rx_buf)) + edma_start(davinci_spi_dma->dma_tx_channel); + + if (t->rx_buf) + edma_start(davinci_spi_dma->dma_rx_channel); + + if ((t->rx_buf) || (t->tx_buf)) + davinci_spi_set_dma_req(spi, 1); + + if (t->tx_buf) + wait_for_completion_interruptible( + &davinci_spi_dma->dma_tx_completion); + + if (t->rx_buf) + wait_for_completion_interruptible( + &davinci_spi_dma->dma_rx_completion); + + dma_unmap_single(NULL, t->tx_dma, temp_count, DMA_TO_DEVICE); + + if (t->rx_buf) + dma_unmap_single(NULL, t->rx_dma, count, DMA_FROM_DEVICE); + + /* + * Check for bit error, desync error,parity error,timeout error and + * receive overflow errors + */ + int_status = ioread32(davinci_spi->base + SPIFLG); + + ret = davinci_spi_check_error(davinci_spi, int_status); + if (ret != 0) + return ret; + + /* SPI Framework maintains the count only in bytes so convert back */ + davinci_spi->count *= conv; + + return t->len; +} + +/** + * davinci_spi_irq - IRQ handler for DaVinci SPI + * @irq: IRQ number for this SPI Master + * @context_data: structure for SPI Master controller davinci_spi + */ +static irqreturn_t davinci_spi_irq(s32 irq, void *context_data) +{ + struct davinci_spi *davinci_spi = context_data; + u32 int_status, rx_data = 0; + irqreturn_t ret = IRQ_NONE; + + int_status = ioread32(davinci_spi->base + SPIFLG); + + while ((int_status & SPIFLG_RX_INTR_MASK)) { + if (likely(int_status & SPIFLG_RX_INTR_MASK)) { + ret = IRQ_HANDLED; + + rx_data = ioread32(davinci_spi->base + SPIBUF); + davinci_spi->get_rx(rx_data, davinci_spi); + + /* Disable Receive Interrupt */ + iowrite32(~(SPIINT_RX_INTR | SPIINT_TX_INTR), + davinci_spi->base + SPIINT); + } else + (void)davinci_spi_check_error(davinci_spi, int_status); + + int_status = ioread32(davinci_spi->base + SPIFLG); + } + + return ret; +} + +/** + * davinci_spi_probe - probe function for SPI Master Controller + * @pdev: platform_device structure which contains plateform specific data + */ +static int davinci_spi_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct davinci_spi *davinci_spi; + struct davinci_spi_platform_data *pdata; + struct resource *r, *mem; + resource_size_t dma_rx_chan = SPI_NO_RESOURCE; + resource_size_t dma_tx_chan = SPI_NO_RESOURCE; + resource_size_t dma_eventq = SPI_NO_RESOURCE; + int i = 0, ret = 0; + + pdata = pdev->dev.platform_data; + if (pdata == NULL) { + ret = -ENODEV; + goto err; + } + + master = spi_alloc_master(&pdev->dev, sizeof(struct davinci_spi)); + if (master == NULL) { + ret = -ENOMEM; + goto err; + } + + dev_set_drvdata(&pdev->dev, master); + + davinci_spi = spi_master_get_devdata(master); + if (davinci_spi == NULL) { + ret = -ENOENT; + goto free_master; + } + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (r == NULL) { + ret = -ENOENT; + goto free_master; + } + + davinci_spi->pbase = r->start; + davinci_spi->region_size = resource_size(r); + davinci_spi->pdata = pdata; + + mem = request_mem_region(r->start, davinci_spi->region_size, + pdev->name); + if (mem == NULL) { + ret = -EBUSY; + goto free_master; + } + + davinci_spi->base = (struct davinci_spi_reg __iomem *) + ioremap(r->start, davinci_spi->region_size); + if (davinci_spi->base == NULL) { + ret = -ENOMEM; + goto release_region; + } + + davinci_spi->irq = platform_get_irq(pdev, 0); + if (davinci_spi->irq <= 0) { + ret = -EINVAL; + goto unmap_io; + } + + ret = request_irq(davinci_spi->irq, davinci_spi_irq, IRQF_DISABLED, + dev_name(&pdev->dev), davinci_spi); + if (ret) + goto unmap_io; + + /* Allocate tmp_buf for tx_buf */ + davinci_spi->tmp_buf = kzalloc(SPI_BUFSIZ, GFP_KERNEL); + if (davinci_spi->tmp_buf == NULL) { + ret = -ENOMEM; + goto irq_free; + } + + davinci_spi->bitbang.master = spi_master_get(master); + if (davinci_spi->bitbang.master == NULL) { + ret = -ENODEV; + goto free_tmp_buf; + } + + davinci_spi->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(davinci_spi->clk)) { + ret = -ENODEV; + goto put_master; + } + clk_enable(davinci_spi->clk); + + + master->bus_num = pdev->id; + master->num_chipselect = pdata->num_chipselect; + master->setup = davinci_spi_setup; + master->cleanup = davinci_spi_cleanup; + + davinci_spi->bitbang.chipselect = davinci_spi_chipselect; + davinci_spi->bitbang.setup_transfer = davinci_spi_setup_transfer; + + davinci_spi->version = pdata->version; + use_dma = pdata->use_dma; + + davinci_spi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP; + if (davinci_spi->version == SPI_VERSION_2) + davinci_spi->bitbang.flags |= SPI_READY; + + if (use_dma) { + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (r) + dma_rx_chan = r->start; + r = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (r) + dma_tx_chan = r->start; + r = platform_get_resource(pdev, IORESOURCE_DMA, 2); + if (r) + dma_eventq = r->start; + } + + if (!use_dma || + dma_rx_chan == SPI_NO_RESOURCE || + dma_tx_chan == SPI_NO_RESOURCE || + dma_eventq == SPI_NO_RESOURCE) { + davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_pio; + use_dma = 0; + } else { + davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_dma; + davinci_spi->dma_channels = kzalloc(master->num_chipselect + * sizeof(struct davinci_spi_dma), GFP_KERNEL); + if (davinci_spi->dma_channels == NULL) { + ret = -ENOMEM; + goto free_clk; + } + + for (i = 0; i < master->num_chipselect; i++) { + davinci_spi->dma_channels[i].dma_rx_channel = -1; + davinci_spi->dma_channels[i].dma_rx_sync_dev = + dma_rx_chan; + davinci_spi->dma_channels[i].dma_tx_channel = -1; + davinci_spi->dma_channels[i].dma_tx_sync_dev = + dma_tx_chan; + davinci_spi->dma_channels[i].eventq = dma_eventq; + } + dev_info(&pdev->dev, "DaVinci SPI driver in EDMA mode\n" + "Using RX channel = %d , TX channel = %d and " + "event queue = %d", dma_rx_chan, dma_tx_chan, + dma_eventq); + } + + davinci_spi->get_rx = davinci_spi_rx_buf_u8; + davinci_spi->get_tx = davinci_spi_tx_buf_u8; + + init_completion(&davinci_spi->done); + + /* Reset In/OUT SPI module */ + iowrite32(0, davinci_spi->base + SPIGCR0); + udelay(100); + iowrite32(1, davinci_spi->base + SPIGCR0); + + /* Clock internal */ + if (davinci_spi->pdata->clk_internal) + set_io_bits(davinci_spi->base + SPIGCR1, + SPIGCR1_CLKMOD_MASK); + else + clear_io_bits(davinci_spi->base + SPIGCR1, + SPIGCR1_CLKMOD_MASK); + + /* master mode default */ + set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_MASTER_MASK); + + if (davinci_spi->pdata->intr_level) + iowrite32(SPI_INTLVL_1, davinci_spi->base + SPILVL); + else + iowrite32(SPI_INTLVL_0, davinci_spi->base + SPILVL); + + ret = spi_bitbang_start(&davinci_spi->bitbang); + if (ret) + goto free_clk; + + dev_info(&pdev->dev, "Controller at 0x%p \n", davinci_spi->base); + + if (!pdata->poll_mode) + dev_info(&pdev->dev, "Operating in interrupt mode" + " using IRQ %d\n", davinci_spi->irq); + + return ret; + +free_clk: + clk_disable(davinci_spi->clk); + clk_put(davinci_spi->clk); +put_master: + spi_master_put(master); +free_tmp_buf: + kfree(davinci_spi->tmp_buf); +irq_free: + free_irq(davinci_spi->irq, davinci_spi); +unmap_io: + iounmap(davinci_spi->base); +release_region: + release_mem_region(davinci_spi->pbase, davinci_spi->region_size); +free_master: + kfree(master); +err: + return ret; +} + +/** + * davinci_spi_remove - remove function for SPI Master Controller + * @pdev: platform_device structure which contains plateform specific data + * + * This function will do the reverse action of davinci_spi_probe function + * It will free the IRQ and SPI controller's memory region. + * It will also call spi_bitbang_stop to destroy the work queue which was + * created by spi_bitbang_start. + */ +static int __exit davinci_spi_remove(struct platform_device *pdev) +{ + struct davinci_spi *davinci_spi; + struct spi_master *master; + + master = dev_get_drvdata(&pdev->dev); + davinci_spi = spi_master_get_devdata(master); + + spi_bitbang_stop(&davinci_spi->bitbang); + + clk_disable(davinci_spi->clk); + clk_put(davinci_spi->clk); + spi_master_put(master); + kfree(davinci_spi->tmp_buf); + free_irq(davinci_spi->irq, davinci_spi); + iounmap(davinci_spi->base); + release_mem_region(davinci_spi->pbase, davinci_spi->region_size); + + return 0; +} + +static struct platform_driver davinci_spi_driver = { + .driver.name = "spi_davinci", + .remove = __exit_p(davinci_spi_remove), +}; + +static int __init davinci_spi_init(void) +{ + return platform_driver_probe(&davinci_spi_driver, davinci_spi_probe); +} +module_init(davinci_spi_init); + +static void __exit davinci_spi_exit(void) +{ + platform_driver_unregister(&davinci_spi_driver); +} +module_exit(davinci_spi_exit); + +MODULE_DESCRIPTION("TI DaVinci SPI Master Controller Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 68ea2d82c3671d2eccb600e6871fcbec1cac7fca Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Wed, 20 Jan 2010 13:49:44 -0700 Subject: spi: Fix reversed args to time_before() in Freescale stmp driver. Signed-off-by: Robert P. J. Day Signed-off-by: Grant Likely --- drivers/spi/spi_stmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi_stmp.c b/drivers/spi/spi_stmp.c index 2552bb364005..fadff76eb7e0 100644 --- a/drivers/spi/spi_stmp.c +++ b/drivers/spi/spi_stmp.c @@ -76,7 +76,7 @@ struct stmp_spi { break; \ } \ cpu_relax(); \ - } while (time_before(end_jiffies, jiffies)); \ + } while (time_before(jiffies, end_jiffies)); \ succeeded; \ }) -- cgit v1.2.2 From 631e61b7ca12ef14c834f99f8948e410c539f585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Wed, 20 Jan 2010 13:49:44 -0700 Subject: spi: make Open Firmware device id constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The match_table field of the struct of_device_id is constant in so it is worth to make the initialization data constant. The semantic match that finds this kind of pattern is as follows: (http://coccinelle.lip6.fr/) // @r@ disable decl_init,const_decl_init; identifier I1, I2, x; @@ struct I1 { ... const struct I2 *x; ... }; @s@ identifier r.I1, y; identifier r.x, E; @@ struct I1 y = { .x = E, }; @c@ identifier r.I2; identifier s.E; @@ const struct I2 E[] = ... ; @depends on !c@ identifier r.I2; identifier s.E; @@ + const struct I2 E[] = ...; // Signed-off-by: Márton Németh Cc: Julia Lawall Cc: cocci@diku.dk Signed-off-by: Grant Likely --- drivers/spi/mpc52xx_psc_spi.c | 2 +- drivers/spi/mpc52xx_spi.c | 2 +- drivers/spi/spi_ppc4xx.c | 2 +- drivers/spi/xilinx_spi_of.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c index f50c81df336a..04747868d6c4 100644 --- a/drivers/spi/mpc52xx_psc_spi.c +++ b/drivers/spi/mpc52xx_psc_spi.c @@ -503,7 +503,7 @@ static int __exit mpc52xx_psc_spi_of_remove(struct of_device *op) return mpc52xx_psc_spi_do_remove(&op->dev); } -static struct of_device_id mpc52xx_psc_spi_of_match[] = { +static const struct of_device_id mpc52xx_psc_spi_of_match[] = { { .compatible = "fsl,mpc5200-psc-spi", }, { .compatible = "mpc5200-psc-spi", }, /* old */ {} diff --git a/drivers/spi/mpc52xx_spi.c b/drivers/spi/mpc52xx_spi.c index 45bfe6458173..6eab46537a0a 100644 --- a/drivers/spi/mpc52xx_spi.c +++ b/drivers/spi/mpc52xx_spi.c @@ -550,7 +550,7 @@ static int __devexit mpc52xx_spi_remove(struct of_device *op) return 0; } -static struct of_device_id mpc52xx_spi_match[] __devinitdata = { +static const struct of_device_id mpc52xx_spi_match[] __devinitconst = { { .compatible = "fsl,mpc5200-spi", }, {} }; diff --git a/drivers/spi/spi_ppc4xx.c b/drivers/spi/spi_ppc4xx.c index 140a18d6cf3e..6d8d4026a07a 100644 --- a/drivers/spi/spi_ppc4xx.c +++ b/drivers/spi/spi_ppc4xx.c @@ -578,7 +578,7 @@ static int __exit spi_ppc4xx_of_remove(struct of_device *op) return 0; } -static struct of_device_id spi_ppc4xx_of_match[] = { +static const struct of_device_id spi_ppc4xx_of_match[] = { { .compatible = "ibm,ppc4xx-spi", }, {}, }; diff --git a/drivers/spi/xilinx_spi_of.c b/drivers/spi/xilinx_spi_of.c index 71dc3adc0495..ed34a8d419c7 100644 --- a/drivers/spi/xilinx_spi_of.c +++ b/drivers/spi/xilinx_spi_of.c @@ -99,7 +99,7 @@ static int __exit xilinx_spi_of_remove(struct of_device *op) return xilinx_spi_remove(op); } -static struct of_device_id xilinx_spi_of_match[] = { +static const struct of_device_id xilinx_spi_of_match[] = { { .compatible = "xlnx,xps-spi-2.00.a", }, { .compatible = "xlnx,xps-spi-2.00.b", }, {} -- cgit v1.2.2 From 34b8c66173666025020e3a6f8d4a5c238b19cde5 Mon Sep 17 00:00:00 2001 From: Steven King Date: Wed, 20 Jan 2010 13:49:44 -0700 Subject: spi: Add Freescale/Motorola Coldfire QSPI driver Add support for the QSPI controller found some on Freescale/Motorola Coldfire MCUs. Full duplex, active high cs, spi modes 0-3 and word sizes 8-16 bits are supported. The hardware drives the MISO, MOSI and SCLK lines, but the chip selects are managed via GPIO and must be configured by the board code. The QSPI controller has an 80 byte buffer which allows us to transfer up to 16 words at a time. For transfers longer than 16 words, we split the buffer in half so we can update in one half while the controller is operating on the other half. Interrupt latencies then ultimately limits our sustained thru-put to something less than half the maximum speed supported by the part. Signed-off-by: Steven King Signed-off-by: Grant Likely --- drivers/spi/Kconfig | 10 + drivers/spi/Makefile | 1 + drivers/spi/coldfire_qspi.c | 640 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 651 insertions(+) create mode 100644 drivers/spi/coldfire_qspi.c (limited to 'drivers') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 82dabbca00c1..28becdd4dea9 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -100,6 +100,16 @@ config SPI_BUTTERFLY inexpensive battery powered microcontroller evaluation board. This same cable can be used to flash new firmware. +config SPI_COLDFIRE_QSPI + tristate "Freescale Coldfire QSPI controller" + depends on (M520x || M523x || M5249 || M527x || M528x || M532x) + help + This enables support for the Coldfire QSPI controller in master + mode. + + This driver can also be built as a module. If so, the module + will be called coldfire_qspi. + config SPI_DAVINCI tristate "SPI controller driver for DaVinci/DA8xx SoC's" depends on SPI_MASTER && ARCH_DAVINCI diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 84b490fb7f8a..d3a65ab8ebbf 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o obj-$(CONFIG_SPI_AU1550) += au1550_spi.o obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o +obj-$(CONFIG_SPI_COLDFIRE_QSPI) += coldfire_qspi.o obj-$(CONFIG_SPI_DAVINCI) += davinci_spi.o obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.o obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o diff --git a/drivers/spi/coldfire_qspi.c b/drivers/spi/coldfire_qspi.c new file mode 100644 index 000000000000..59be3efe0636 --- /dev/null +++ b/drivers/spi/coldfire_qspi.c @@ -0,0 +1,640 @@ +/* + * Freescale/Motorola Coldfire Queued SPI driver + * + * Copyright 2010 Steven King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA + * +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRIVER_NAME "mcfqspi" + +#define MCFQSPI_BUSCLK (MCF_BUSCLK / 2) + +#define MCFQSPI_QMR 0x00 +#define MCFQSPI_QMR_MSTR 0x8000 +#define MCFQSPI_QMR_CPOL 0x0200 +#define MCFQSPI_QMR_CPHA 0x0100 +#define MCFQSPI_QDLYR 0x04 +#define MCFQSPI_QDLYR_SPE 0x8000 +#define MCFQSPI_QWR 0x08 +#define MCFQSPI_QWR_HALT 0x8000 +#define MCFQSPI_QWR_WREN 0x4000 +#define MCFQSPI_QWR_CSIV 0x1000 +#define MCFQSPI_QIR 0x0C +#define MCFQSPI_QIR_WCEFB 0x8000 +#define MCFQSPI_QIR_ABRTB 0x4000 +#define MCFQSPI_QIR_ABRTL 0x1000 +#define MCFQSPI_QIR_WCEFE 0x0800 +#define MCFQSPI_QIR_ABRTE 0x0400 +#define MCFQSPI_QIR_SPIFE 0x0100 +#define MCFQSPI_QIR_WCEF 0x0008 +#define MCFQSPI_QIR_ABRT 0x0004 +#define MCFQSPI_QIR_SPIF 0x0001 +#define MCFQSPI_QAR 0x010 +#define MCFQSPI_QAR_TXBUF 0x00 +#define MCFQSPI_QAR_RXBUF 0x10 +#define MCFQSPI_QAR_CMDBUF 0x20 +#define MCFQSPI_QDR 0x014 +#define MCFQSPI_QCR 0x014 +#define MCFQSPI_QCR_CONT 0x8000 +#define MCFQSPI_QCR_BITSE 0x4000 +#define MCFQSPI_QCR_DT 0x2000 + +struct mcfqspi { + void __iomem *iobase; + int irq; + struct clk *clk; + struct mcfqspi_cs_control *cs_control; + + wait_queue_head_t waitq; + + struct work_struct work; + struct workqueue_struct *workq; + spinlock_t lock; + struct list_head msgq; +}; + +static void mcfqspi_wr_qmr(struct mcfqspi *mcfqspi, u16 val) +{ + writew(val, mcfqspi->iobase + MCFQSPI_QMR); +} + +static void mcfqspi_wr_qdlyr(struct mcfqspi *mcfqspi, u16 val) +{ + writew(val, mcfqspi->iobase + MCFQSPI_QDLYR); +} + +static u16 mcfqspi_rd_qdlyr(struct mcfqspi *mcfqspi) +{ + return readw(mcfqspi->iobase + MCFQSPI_QDLYR); +} + +static void mcfqspi_wr_qwr(struct mcfqspi *mcfqspi, u16 val) +{ + writew(val, mcfqspi->iobase + MCFQSPI_QWR); +} + +static void mcfqspi_wr_qir(struct mcfqspi *mcfqspi, u16 val) +{ + writew(val, mcfqspi->iobase + MCFQSPI_QIR); +} + +static void mcfqspi_wr_qar(struct mcfqspi *mcfqspi, u16 val) +{ + writew(val, mcfqspi->iobase + MCFQSPI_QAR); +} + +static void mcfqspi_wr_qdr(struct mcfqspi *mcfqspi, u16 val) +{ + writew(val, mcfqspi->iobase + MCFQSPI_QDR); +} + +static u16 mcfqspi_rd_qdr(struct mcfqspi *mcfqspi) +{ + return readw(mcfqspi->iobase + MCFQSPI_QDR); +} + +static void mcfqspi_cs_select(struct mcfqspi *mcfqspi, u8 chip_select, + bool cs_high) +{ + mcfqspi->cs_control->select(mcfqspi->cs_control, chip_select, cs_high); +} + +static void mcfqspi_cs_deselect(struct mcfqspi *mcfqspi, u8 chip_select, + bool cs_high) +{ + mcfqspi->cs_control->deselect(mcfqspi->cs_control, chip_select, cs_high); +} + +static int mcfqspi_cs_setup(struct mcfqspi *mcfqspi) +{ + return (mcfqspi->cs_control && mcfqspi->cs_control->setup) ? + mcfqspi->cs_control->setup(mcfqspi->cs_control) : 0; +} + +static void mcfqspi_cs_teardown(struct mcfqspi *mcfqspi) +{ + if (mcfqspi->cs_control && mcfqspi->cs_control->teardown) + mcfqspi->cs_control->teardown(mcfqspi->cs_control); +} + +static u8 mcfqspi_qmr_baud(u32 speed_hz) +{ + return clamp((MCFQSPI_BUSCLK + speed_hz - 1) / speed_hz, 2u, 255u); +} + +static bool mcfqspi_qdlyr_spe(struct mcfqspi *mcfqspi) +{ + return mcfqspi_rd_qdlyr(mcfqspi) & MCFQSPI_QDLYR_SPE; +} + +static irqreturn_t mcfqspi_irq_handler(int this_irq, void *dev_id) +{ + struct mcfqspi *mcfqspi = dev_id; + + /* clear interrupt */ + mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE | MCFQSPI_QIR_SPIF); + wake_up(&mcfqspi->waitq); + + return IRQ_HANDLED; +} + +static void mcfqspi_transfer_msg8(struct mcfqspi *mcfqspi, unsigned count, + const u8 *txbuf, u8 *rxbuf) +{ + unsigned i, n, offset = 0; + + n = min(count, 16u); + + mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_CMDBUF); + for (i = 0; i < n; ++i) + mcfqspi_wr_qdr(mcfqspi, MCFQSPI_QCR_BITSE); + + mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_TXBUF); + if (txbuf) + for (i = 0; i < n; ++i) + mcfqspi_wr_qdr(mcfqspi, *txbuf++); + else + for (i = 0; i < count; ++i) + mcfqspi_wr_qdr(mcfqspi, 0); + + count -= n; + if (count) { + u16 qwr = 0xf08; + mcfqspi_wr_qwr(mcfqspi, 0x700); + mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE); + + do { + wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi)); + mcfqspi_wr_qwr(mcfqspi, qwr); + mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE); + if (rxbuf) { + mcfqspi_wr_qar(mcfqspi, + MCFQSPI_QAR_RXBUF + offset); + for (i = 0; i < 8; ++i) + *rxbuf++ = mcfqspi_rd_qdr(mcfqspi); + } + n = min(count, 8u); + if (txbuf) { + mcfqspi_wr_qar(mcfqspi, + MCFQSPI_QAR_TXBUF + offset); + for (i = 0; i < n; ++i) + mcfqspi_wr_qdr(mcfqspi, *txbuf++); + } + qwr = (offset ? 0x808 : 0) + ((n - 1) << 8); + offset ^= 8; + count -= n; + } while (count); + wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi)); + mcfqspi_wr_qwr(mcfqspi, qwr); + mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE); + if (rxbuf) { + mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset); + for (i = 0; i < 8; ++i) + *rxbuf++ = mcfqspi_rd_qdr(mcfqspi); + offset ^= 8; + } + } else { + mcfqspi_wr_qwr(mcfqspi, (n - 1) << 8); + mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE); + } + wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi)); + if (rxbuf) { + mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset); + for (i = 0; i < n; ++i) + *rxbuf++ = mcfqspi_rd_qdr(mcfqspi); + } +} + +static void mcfqspi_transfer_msg16(struct mcfqspi *mcfqspi, unsigned count, + const u16 *txbuf, u16 *rxbuf) +{ + unsigned i, n, offset = 0; + + n = min(count, 16u); + + mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_CMDBUF); + for (i = 0; i < n; ++i) + mcfqspi_wr_qdr(mcfqspi, MCFQSPI_QCR_BITSE); + + mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_TXBUF); + if (txbuf) + for (i = 0; i < n; ++i) + mcfqspi_wr_qdr(mcfqspi, *txbuf++); + else + for (i = 0; i < count; ++i) + mcfqspi_wr_qdr(mcfqspi, 0); + + count -= n; + if (count) { + u16 qwr = 0xf08; + mcfqspi_wr_qwr(mcfqspi, 0x700); + mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE); + + do { + wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi)); + mcfqspi_wr_qwr(mcfqspi, qwr); + mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE); + if (rxbuf) { + mcfqspi_wr_qar(mcfqspi, + MCFQSPI_QAR_RXBUF + offset); + for (i = 0; i < 8; ++i) + *rxbuf++ = mcfqspi_rd_qdr(mcfqspi); + } + n = min(count, 8u); + if (txbuf) { + mcfqspi_wr_qar(mcfqspi, + MCFQSPI_QAR_TXBUF + offset); + for (i = 0; i < n; ++i) + mcfqspi_wr_qdr(mcfqspi, *txbuf++); + } + qwr = (offset ? 0x808 : 0x000) + ((n - 1) << 8); + offset ^= 8; + count -= n; + } while (count); + wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi)); + mcfqspi_wr_qwr(mcfqspi, qwr); + mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE); + if (rxbuf) { + mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset); + for (i = 0; i < 8; ++i) + *rxbuf++ = mcfqspi_rd_qdr(mcfqspi); + offset ^= 8; + } + } else { + mcfqspi_wr_qwr(mcfqspi, (n - 1) << 8); + mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE); + } + wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi)); + if (rxbuf) { + mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset); + for (i = 0; i < n; ++i) + *rxbuf++ = mcfqspi_rd_qdr(mcfqspi); + } +} + +static void mcfqspi_work(struct work_struct *work) +{ + struct mcfqspi *mcfqspi = container_of(work, struct mcfqspi, work); + unsigned long flags; + + spin_lock_irqsave(&mcfqspi->lock, flags); + while (!list_empty(&mcfqspi->msgq)) { + struct spi_message *msg; + struct spi_device *spi; + struct spi_transfer *xfer; + int status = 0; + + msg = container_of(mcfqspi->msgq.next, struct spi_message, + queue); + + list_del_init(&mcfqspi->msgq); + spin_unlock_irqrestore(&mcfqspi->lock, flags); + + spi = msg->spi; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + bool cs_high = spi->mode & SPI_CS_HIGH; + u16 qmr = MCFQSPI_QMR_MSTR; + + if (xfer->bits_per_word) + qmr |= xfer->bits_per_word << 10; + else + qmr |= spi->bits_per_word << 10; + if (spi->mode & SPI_CPHA) + qmr |= MCFQSPI_QMR_CPHA; + if (spi->mode & SPI_CPOL) + qmr |= MCFQSPI_QMR_CPOL; + if (xfer->speed_hz) + qmr |= mcfqspi_qmr_baud(xfer->speed_hz); + else + qmr |= mcfqspi_qmr_baud(spi->max_speed_hz); + mcfqspi_wr_qmr(mcfqspi, qmr); + + mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high); + + mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE); + if ((xfer->bits_per_word ? xfer->bits_per_word : + spi->bits_per_word) == 8) + mcfqspi_transfer_msg8(mcfqspi, xfer->len, + xfer->tx_buf, + xfer->rx_buf); + else + mcfqspi_transfer_msg16(mcfqspi, xfer->len / 2, + xfer->tx_buf, + xfer->rx_buf); + mcfqspi_wr_qir(mcfqspi, 0); + + if (xfer->delay_usecs) + udelay(xfer->delay_usecs); + if (xfer->cs_change) { + if (!list_is_last(&xfer->transfer_list, + &msg->transfers)) + mcfqspi_cs_deselect(mcfqspi, + spi->chip_select, + cs_high); + } else { + if (list_is_last(&xfer->transfer_list, + &msg->transfers)) + mcfqspi_cs_deselect(mcfqspi, + spi->chip_select, + cs_high); + } + msg->actual_length += xfer->len; + } + msg->status = status; + msg->complete(msg->context); + + spin_lock_irqsave(&mcfqspi->lock, flags); + } + spin_unlock_irqrestore(&mcfqspi->lock, flags); +} + +static int mcfqspi_transfer(struct spi_device *spi, struct spi_message *msg) +{ + struct mcfqspi *mcfqspi; + struct spi_transfer *xfer; + unsigned long flags; + + mcfqspi = spi_master_get_devdata(spi->master); + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + if (xfer->bits_per_word && ((xfer->bits_per_word < 8) + || (xfer->bits_per_word > 16))) { + dev_dbg(&spi->dev, + "%d bits per word is not supported\n", + xfer->bits_per_word); + goto fail; + } + if (xfer->speed_hz) { + u32 real_speed = MCFQSPI_BUSCLK / + mcfqspi_qmr_baud(xfer->speed_hz); + if (real_speed != xfer->speed_hz) + dev_dbg(&spi->dev, + "using speed %d instead of %d\n", + real_speed, xfer->speed_hz); + } + } + msg->status = -EINPROGRESS; + msg->actual_length = 0; + + spin_lock_irqsave(&mcfqspi->lock, flags); + list_add_tail(&msg->queue, &mcfqspi->msgq); + queue_work(mcfqspi->workq, &mcfqspi->work); + spin_unlock_irqrestore(&mcfqspi->lock, flags); + + return 0; +fail: + msg->status = -EINVAL; + return -EINVAL; +} + +static int mcfqspi_setup(struct spi_device *spi) +{ + if ((spi->bits_per_word < 8) || (spi->bits_per_word > 16)) { + dev_dbg(&spi->dev, "%d bits per word is not supported\n", + spi->bits_per_word); + return -EINVAL; + } + if (spi->chip_select >= spi->master->num_chipselect) { + dev_dbg(&spi->dev, "%d chip select is out of range\n", + spi->chip_select); + return -EINVAL; + } + + mcfqspi_cs_deselect(spi_master_get_devdata(spi->master), + spi->chip_select, spi->mode & SPI_CS_HIGH); + + dev_dbg(&spi->dev, + "bits per word %d, chip select %d, speed %d KHz\n", + spi->bits_per_word, spi->chip_select, + (MCFQSPI_BUSCLK / mcfqspi_qmr_baud(spi->max_speed_hz)) + / 1000); + + return 0; +} + +static int __devinit mcfqspi_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct mcfqspi *mcfqspi; + struct resource *res; + struct mcfqspi_platform_data *pdata; + int status; + + master = spi_alloc_master(&pdev->dev, sizeof(*mcfqspi)); + if (master == NULL) { + dev_dbg(&pdev->dev, "spi_alloc_master failed\n"); + return -ENOMEM; + } + + mcfqspi = spi_master_get_devdata(master); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_dbg(&pdev->dev, "platform_get_resource failed\n"); + status = -ENXIO; + goto fail0; + } + + if (!request_mem_region(res->start, resource_size(res), pdev->name)) { + dev_dbg(&pdev->dev, "request_mem_region failed\n"); + status = -EBUSY; + goto fail0; + } + + mcfqspi->iobase = ioremap(res->start, resource_size(res)); + if (!mcfqspi->iobase) { + dev_dbg(&pdev->dev, "ioremap failed\n"); + status = -ENOMEM; + goto fail1; + } + + mcfqspi->irq = platform_get_irq(pdev, 0); + if (mcfqspi->irq < 0) { + dev_dbg(&pdev->dev, "platform_get_irq failed\n"); + status = -ENXIO; + goto fail2; + } + + status = request_irq(mcfqspi->irq, mcfqspi_irq_handler, IRQF_DISABLED, + pdev->name, mcfqspi); + if (status) { + dev_dbg(&pdev->dev, "request_irq failed\n"); + goto fail2; + } + + mcfqspi->clk = clk_get(&pdev->dev, "qspi_clk"); + if (IS_ERR(mcfqspi->clk)) { + dev_dbg(&pdev->dev, "clk_get failed\n"); + status = PTR_ERR(mcfqspi->clk); + goto fail3; + } + clk_enable(mcfqspi->clk); + + mcfqspi->workq = create_singlethread_workqueue(dev_name(master->dev.parent)); + if (!mcfqspi->workq) { + dev_dbg(&pdev->dev, "create_workqueue failed\n"); + status = -ENOMEM; + goto fail4; + } + INIT_WORK(&mcfqspi->work, mcfqspi_work); + spin_lock_init(&mcfqspi->lock); + INIT_LIST_HEAD(&mcfqspi->msgq); + init_waitqueue_head(&mcfqspi->waitq); + + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_dbg(&pdev->dev, "platform data is missing\n"); + goto fail5; + } + master->bus_num = pdata->bus_num; + master->num_chipselect = pdata->num_chipselect; + + mcfqspi->cs_control = pdata->cs_control; + status = mcfqspi_cs_setup(mcfqspi); + if (status) { + dev_dbg(&pdev->dev, "error initializing cs_control\n"); + goto fail5; + } + + master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA; + master->setup = mcfqspi_setup; + master->transfer = mcfqspi_transfer; + + platform_set_drvdata(pdev, master); + + status = spi_register_master(master); + if (status) { + dev_dbg(&pdev->dev, "spi_register_master failed\n"); + goto fail6; + } + dev_info(&pdev->dev, "Coldfire QSPI bus driver\n"); + + return 0; + +fail6: + mcfqspi_cs_teardown(mcfqspi); +fail5: + destroy_workqueue(mcfqspi->workq); +fail4: + clk_disable(mcfqspi->clk); + clk_put(mcfqspi->clk); +fail3: + free_irq(mcfqspi->irq, mcfqspi); +fail2: + iounmap(mcfqspi->iobase); +fail1: + release_mem_region(res->start, resource_size(res)); +fail0: + spi_master_put(master); + + dev_dbg(&pdev->dev, "Coldfire QSPI probe failed\n"); + + return status; +} + +static int __devexit mcfqspi_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct mcfqspi *mcfqspi = spi_master_get_devdata(master); + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + /* disable the hardware (set the baud rate to 0) */ + mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR); + + platform_set_drvdata(pdev, NULL); + mcfqspi_cs_teardown(mcfqspi); + destroy_workqueue(mcfqspi->workq); + clk_disable(mcfqspi->clk); + clk_put(mcfqspi->clk); + free_irq(mcfqspi->irq, mcfqspi); + iounmap(mcfqspi->iobase); + release_mem_region(res->start, resource_size(res)); + spi_unregister_master(master); + spi_master_put(master); + + return 0; +} + +#ifdef CONFIG_PM + +static int mcfqspi_suspend(struct device *dev) +{ + struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev)); + + clk_disable(mcfqspi->clk); + + return 0; +} + +static int mcfqspi_resume(struct device *dev) +{ + struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev)); + + clk_enable(mcfqspi->clk); + + return 0; +} + +static struct dev_pm_ops mcfqspi_dev_pm_ops = { + .suspend = mcfqspi_suspend, + .resume = mcfqspi_resume, +}; + +#define MCFQSPI_DEV_PM_OPS (&mcfqspi_dev_pm_ops) +#else +#define MCFQSPI_DEV_PM_OPS NULL +#endif + +static struct platform_driver mcfqspi_driver = { + .driver.name = DRIVER_NAME, + .driver.owner = THIS_MODULE, + .driver.pm = MCFQSPI_DEV_PM_OPS, + .remove = __devexit_p(mcfqspi_remove), +}; + +static int __init mcfqspi_init(void) +{ + return platform_driver_probe(&mcfqspi_driver, mcfqspi_probe); +} +module_init(mcfqspi_init); + +static void __exit mcfqspi_exit(void) +{ + platform_driver_unregister(&mcfqspi_driver); +} +module_exit(mcfqspi_exit); + +MODULE_AUTHOR("Steven King "); +MODULE_DESCRIPTION("Coldfire QSPI Controller Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRIVER_NAME); -- cgit v1.2.2 From e9a172f074ba85de144e63b0786c7c5c5ba93c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Jan 2010 13:49:44 -0700 Subject: spi/mpc8xxx: don't check platform_get_irq's return value against zero MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit platform_get_irq returns -ENXIO on failure, so !irq was probably always true. Make irq a signed variable and compare irq <= 0. Note that a return value of zero is still handled as error even though this could mean irq0. This is a followup to 305b3228f9ff4d59f49e6d34a7034d44ee8ce2f0 that changed the return value of platform_get_irq from 0 to -ENXIO on error. Signed-off-by: Uwe Kleine-König Acked-by: Anton Vorontsov Signed-off-by: Grant Likely --- drivers/spi/spi_mpc8xxx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_mpc8xxx.c index 1fb2a6ea328c..08065fb15817 100644 --- a/drivers/spi/spi_mpc8xxx.c +++ b/drivers/spi/spi_mpc8xxx.c @@ -1328,7 +1328,7 @@ static struct of_platform_driver of_mpc8xxx_spi_driver = { static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev) { struct resource *mem; - unsigned int irq; + int irq; struct spi_master *master; if (!pdev->dev.platform_data) @@ -1339,7 +1339,7 @@ static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev) return -EINVAL; irq = platform_get_irq(pdev, 0); - if (!irq) + if (irq <= 0) return -EINVAL; master = mpc8xxx_spi_probe(&pdev->dev, mem, irq); -- cgit v1.2.2 From ad7de729c60380a48844f885f37451158169c50d Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 20 Jan 2010 13:49:44 -0700 Subject: spi/s3c64xx: Rename s3c64xx_spi_cntrlr_info Rename 'struct s3c64xx_spi_cntrlr_info' to lesser wordy 'struct s3c64xx_spi_info' Signed-off-by: Jassi Brar Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index 88a456dba967..ad93d5d8539c 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -160,7 +160,7 @@ struct s3c64xx_spi_driver_data { struct platform_device *pdev; struct spi_master *master; struct workqueue_struct *workqueue; - struct s3c64xx_spi_cntrlr_info *cntrlr_info; + struct s3c64xx_spi_info *cntrlr_info; struct spi_device *tgl_spi; struct work_struct work; struct list_head queue; @@ -180,7 +180,7 @@ static struct s3c2410_dma_client s3c64xx_spi_dma_client = { static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) { - struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; void __iomem *regs = sdd->regs; unsigned long loops; u32 val; @@ -225,7 +225,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, struct spi_device *spi, struct spi_transfer *xfer, int dma_mode) { - struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; void __iomem *regs = sdd->regs; u32 modecfg, chcfg; @@ -310,7 +310,7 @@ static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd, static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, struct spi_transfer *xfer, int dma_mode) { - struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; void __iomem *regs = sdd->regs; unsigned long val; int ms; @@ -389,7 +389,7 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd, static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) { - struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; void __iomem *regs = sdd->regs; u32 val; @@ -558,7 +558,7 @@ static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd, static void handle_msg(struct s3c64xx_spi_driver_data *sdd, struct spi_message *msg) { - struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; struct spi_device *spi = msg->spi; struct s3c64xx_spi_csinfo *cs = spi->controller_data; struct spi_transfer *xfer; @@ -786,7 +786,7 @@ static int s3c64xx_spi_setup(struct spi_device *spi) { struct s3c64xx_spi_csinfo *cs = spi->controller_data; struct s3c64xx_spi_driver_data *sdd; - struct s3c64xx_spi_cntrlr_info *sci; + struct s3c64xx_spi_info *sci; struct spi_message *msg; u32 psr, speed; unsigned long flags; @@ -867,7 +867,7 @@ setup_exit: static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel) { - struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; void __iomem *regs = sdd->regs; unsigned int val; @@ -902,7 +902,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) { struct resource *mem_res, *dmatx_res, *dmarx_res; struct s3c64xx_spi_driver_data *sdd; - struct s3c64xx_spi_cntrlr_info *sci; + struct s3c64xx_spi_info *sci; struct spi_master *master; int ret; @@ -1078,7 +1078,7 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) { struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); - struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; struct resource *mem_res; unsigned long flags; @@ -1118,7 +1118,7 @@ static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state) { struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); - struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; struct s3c64xx_spi_csinfo *cs; unsigned long flags; @@ -1144,7 +1144,7 @@ static int s3c64xx_spi_resume(struct platform_device *pdev) { struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); - struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; unsigned long flags; sci->cfg_gpio(pdev); -- cgit v1.2.2 From ee64a37732c23ab2bcef5fe7785fd237a7e38951 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 20 Jan 2010 13:49:44 -0700 Subject: spi/s3c64xx: Differentiate ip and rate clock The instance of SPI clock for controller and that used for generating signals ought to be independently handled. Signed-off-by: Jassi Brar Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index ad93d5d8539c..6d03d8f2de6d 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -1000,10 +1000,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) goto err4; } - if (sci->src_clk_nr == S3C64XX_SPI_SRCCLK_PCLK) - sci->src_clk = sdd->clk; - else - sci->src_clk = clk_get(&pdev->dev, sci->src_clk_name); + sci->src_clk = clk_get(&pdev->dev, sci->src_clk_name); if (IS_ERR(sci->src_clk)) { dev_err(&pdev->dev, "Unable to acquire clock '%s'\n", sci->src_clk_name); @@ -1011,7 +1008,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) goto err5; } - if (sci->src_clk != sdd->clk && clk_enable(sci->src_clk)) { + if (clk_enable(sci->src_clk)) { dev_err(&pdev->dev, "Couldn't enable clock '%s'\n", sci->src_clk_name); ret = -EBUSY; @@ -1053,11 +1050,9 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) err8: destroy_workqueue(sdd->workqueue); err7: - if (sci->src_clk != sdd->clk) - clk_disable(sci->src_clk); + clk_disable(sci->src_clk); err6: - if (sci->src_clk != sdd->clk) - clk_put(sci->src_clk); + clk_put(sci->src_clk); err5: clk_disable(sdd->clk); err4: @@ -1093,11 +1088,8 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) destroy_workqueue(sdd->workqueue); - if (sci->src_clk != sdd->clk) - clk_disable(sci->src_clk); - - if (sci->src_clk != sdd->clk) - clk_put(sci->src_clk); + clk_disable(sci->src_clk); + clk_put(sci->src_clk); clk_disable(sdd->clk); clk_put(sdd->clk); @@ -1130,9 +1122,7 @@ static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state) msleep(10); /* Disable the clock */ - if (sci->src_clk != sdd->clk) - clk_disable(sci->src_clk); - + clk_disable(sci->src_clk); clk_disable(sdd->clk); sdd->cur_speed = 0; /* Output Clock is stopped */ @@ -1150,9 +1140,7 @@ static int s3c64xx_spi_resume(struct platform_device *pdev) sci->cfg_gpio(pdev); /* Enable the clock */ - if (sci->src_clk != sdd->clk) - clk_enable(sci->src_clk); - + clk_enable(sci->src_clk); clk_enable(sdd->clk); s3c64xx_spi_hwinit(sdd, pdev->id); -- cgit v1.2.2 From b0d5d6e55340348b0de75eb691b93d7e60dba879 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 20 Jan 2010 13:49:44 -0700 Subject: spi/s3c64xx: Move src_clk to local driver data The pointer to SPI rate source clock had better be the member of driver local data structure rather than platform specific. Also, remove definitions of variable 'sci' that are rendered useless as a consequence. Signed-off-by: Jassi Brar Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index 6d03d8f2de6d..3acf38119e96 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -137,6 +137,7 @@ /** * struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver. * @clk: Pointer to the spi clock. + * @src_clk: Pointer to the clock used to generate SPI signals. * @master: Pointer to the SPI Protocol master. * @workqueue: Work queue for the SPI xfer requests. * @cntrlr_info: Platform specific data for the controller this driver manages. @@ -157,6 +158,7 @@ struct s3c64xx_spi_driver_data { void __iomem *regs; struct clk *clk; + struct clk *src_clk; struct platform_device *pdev; struct spi_master *master; struct workqueue_struct *workqueue; @@ -389,7 +391,6 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd, static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) { - struct s3c64xx_spi_info *sci = sdd->cntrlr_info; void __iomem *regs = sdd->regs; u32 val; @@ -435,7 +436,7 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) /* Configure Clock */ val = readl(regs + S3C64XX_SPI_CLK_CFG); val &= ~S3C64XX_SPI_PSR_MASK; - val |= ((clk_get_rate(sci->src_clk) / sdd->cur_speed / 2 - 1) + val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / 2 - 1) & S3C64XX_SPI_PSR_MASK); writel(val, regs + S3C64XX_SPI_CLK_CFG); @@ -831,17 +832,17 @@ static int s3c64xx_spi_setup(struct spi_device *spi) } /* Check if we can provide the requested rate */ - speed = clk_get_rate(sci->src_clk) / 2 / (0 + 1); /* Max possible */ + speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1); /* Max possible */ if (spi->max_speed_hz > speed) spi->max_speed_hz = speed; - psr = clk_get_rate(sci->src_clk) / 2 / spi->max_speed_hz - 1; + psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1; psr &= S3C64XX_SPI_PSR_MASK; if (psr == S3C64XX_SPI_PSR_MASK) psr--; - speed = clk_get_rate(sci->src_clk) / 2 / (psr + 1); + speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1); if (spi->max_speed_hz < speed) { if (psr+1 < S3C64XX_SPI_PSR_MASK) { psr++; @@ -851,7 +852,7 @@ static int s3c64xx_spi_setup(struct spi_device *spi) } } - speed = clk_get_rate(sci->src_clk) / 2 / (psr + 1); + speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1); if (spi->max_speed_hz >= speed) spi->max_speed_hz = speed; else @@ -1000,15 +1001,15 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) goto err4; } - sci->src_clk = clk_get(&pdev->dev, sci->src_clk_name); - if (IS_ERR(sci->src_clk)) { + sdd->src_clk = clk_get(&pdev->dev, sci->src_clk_name); + if (IS_ERR(sdd->src_clk)) { dev_err(&pdev->dev, "Unable to acquire clock '%s'\n", sci->src_clk_name); - ret = PTR_ERR(sci->src_clk); + ret = PTR_ERR(sdd->src_clk); goto err5; } - if (clk_enable(sci->src_clk)) { + if (clk_enable(sdd->src_clk)) { dev_err(&pdev->dev, "Couldn't enable clock '%s'\n", sci->src_clk_name); ret = -EBUSY; @@ -1050,9 +1051,9 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) err8: destroy_workqueue(sdd->workqueue); err7: - clk_disable(sci->src_clk); + clk_disable(sdd->src_clk); err6: - clk_put(sci->src_clk); + clk_put(sdd->src_clk); err5: clk_disable(sdd->clk); err4: @@ -1073,7 +1074,6 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) { struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); - struct s3c64xx_spi_info *sci = sdd->cntrlr_info; struct resource *mem_res; unsigned long flags; @@ -1088,8 +1088,8 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) destroy_workqueue(sdd->workqueue); - clk_disable(sci->src_clk); - clk_put(sci->src_clk); + clk_disable(sdd->src_clk); + clk_put(sdd->src_clk); clk_disable(sdd->clk); clk_put(sdd->clk); @@ -1110,8 +1110,6 @@ static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state) { struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); - struct s3c64xx_spi_info *sci = sdd->cntrlr_info; - struct s3c64xx_spi_csinfo *cs; unsigned long flags; spin_lock_irqsave(&sdd->lock, flags); @@ -1122,7 +1120,7 @@ static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state) msleep(10); /* Disable the clock */ - clk_disable(sci->src_clk); + clk_disable(sdd->src_clk); clk_disable(sdd->clk); sdd->cur_speed = 0; /* Output Clock is stopped */ @@ -1140,7 +1138,7 @@ static int s3c64xx_spi_resume(struct platform_device *pdev) sci->cfg_gpio(pdev); /* Enable the clock */ - clk_enable(sci->src_clk); + clk_enable(sdd->src_clk); clk_enable(sdd->clk); s3c64xx_spi_hwinit(sdd, pdev->id); -- cgit v1.2.2 From ef6c680dc5a182a79b09567168d6713f46c85784 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 20 Jan 2010 13:49:44 -0700 Subject: spi/s3c64xx: Check before mem-region release Add precautionary check before releasing memory region. Signed-off-by: Jassi Brar Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index 3acf38119e96..0e883f9c720b 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -1097,7 +1097,8 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) iounmap((void *) sdd->regs); mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mem_res->start, resource_size(mem_res)); + if (mem_res != NULL) + release_mem_region(mem_res->start, resource_size(mem_res)); platform_set_drvdata(pdev, NULL); spi_master_put(master); -- cgit v1.2.2 From e6b873c9666015484a01373a4eebc6cfa82e670d Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 20 Jan 2010 13:49:45 -0700 Subject: spi/s3c64xx: Include moved header Header for platform specific stuff has been rename to include the SoC type. Include the new header instead. Signed-off-by: Jassi Brar Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index 0e883f9c720b..9fa0b99e1607 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -28,7 +28,7 @@ #include #include -#include +#include /* Registers and bit-fields */ -- cgit v1.2.2 From fa0fcde66ac3360678360104b24492015e7b852b Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 20 Jan 2010 13:49:45 -0700 Subject: spi/s3c64xx: Add new parameter to cs callback Since most of the chip-selects are simply going to be like gpio_set_value, it would do good to have the same callback type so that it could simply be made to point at gpio_set_value. Signed-off-by: Jassi Brar Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index 9fa0b99e1607..32db69540fa9 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -300,13 +300,14 @@ static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd, if (sdd->tgl_spi != spi) { /* if last mssg on diff device */ /* Deselect the last toggled device */ cs = sdd->tgl_spi->controller_data; - cs->set_level(spi->mode & SPI_CS_HIGH ? 0 : 1); + cs->set_level(cs->line, + spi->mode & SPI_CS_HIGH ? 0 : 1); } sdd->tgl_spi = NULL; } cs = spi->controller_data; - cs->set_level(spi->mode & SPI_CS_HIGH ? 1 : 0); + cs->set_level(cs->line, spi->mode & SPI_CS_HIGH ? 1 : 0); } static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, @@ -386,7 +387,7 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd, if (sdd->tgl_spi == spi) sdd->tgl_spi = NULL; - cs->set_level(spi->mode & SPI_CS_HIGH ? 0 : 1); + cs->set_level(cs->line, spi->mode & SPI_CS_HIGH ? 0 : 1); } static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) -- cgit v1.2.2 From b490e3704ccee12deb295f96029d68e0daf02feb Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Wed, 20 Jan 2010 13:49:45 -0700 Subject: spi/dw_spi: bug fix in wait_till_not_busy() Make the driver wait at least for 1 jiffie before issuing the warning, no matter what HZ is set to Signed-off-by: Feng Tang Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index 31620fae77be..521d680af289 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -161,7 +161,7 @@ static inline void mrst_spi_debugfs_remove(struct dw_spi *dws) static void wait_till_not_busy(struct dw_spi *dws) { - unsigned long end = jiffies + usecs_to_jiffies(1000); + unsigned long end = jiffies + 1 + usecs_to_jiffies(1000); while (time_before(jiffies, end)) { if (!(dw_readw(dws, sr) & SR_BUSY)) -- cgit v1.2.2 From 51f921c1eb1124fb99ab0728c19e8e14c82c81be Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Wed, 20 Jan 2010 13:49:45 -0700 Subject: spi/dw_spi: add a missed dw_spi_remove_host() in exit sequence Signed-off-by: Feng Tang Signed-off-by: Grant Likely --- drivers/spi/dw_spi_pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/spi/dw_spi_pci.c b/drivers/spi/dw_spi_pci.c index 34ba69161734..7980f1443ce1 100644 --- a/drivers/spi/dw_spi_pci.c +++ b/drivers/spi/dw_spi_pci.c @@ -98,6 +98,7 @@ static void __devexit spi_pci_remove(struct pci_dev *pdev) struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); pci_set_drvdata(pdev, NULL); + dw_spi_remove_host(&dwpci->dws); iounmap(dwpci->dws.regs); pci_release_region(pdev, 0); kfree(dwpci); -- cgit v1.2.2 From 552e450929a7298cc8834fd2824a60b2e914f70e Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Wed, 20 Jan 2010 13:49:45 -0700 Subject: spi/dw_spi: refine the IRQ mode working flow Now dw_spi core fully supports 3 transfer modes: pure polling, DMA and IRQ mode. IRQ mode will use the FIFO half empty as the IRQ trigger, so each interface driver need set the fifo_len, so that core driver can handle it properly Signed-off-by: Feng Tang Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 64 +++++++++++++++++++++++++++++------------------- drivers/spi/dw_spi_pci.c | 1 + 2 files changed, 40 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index 521d680af289..1bb709b3920f 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -358,6 +358,8 @@ static void transfer_complete(struct dw_spi *dws) static irqreturn_t interrupt_transfer(struct dw_spi *dws) { u16 irq_status, irq_mask = 0x3f; + u32 int_level = dws->fifo_len / 2; + u32 left; irq_status = dw_readw(dws, isr) & irq_mask; /* Error handling */ @@ -369,22 +371,23 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws) return IRQ_HANDLED; } - /* INT comes from tx */ - if (dws->tx && (irq_status & SPI_INT_TXEI)) { - while (dws->tx < dws->tx_end) + if (irq_status & SPI_INT_TXEI) { + spi_mask_intr(dws, SPI_INT_TXEI); + + left = (dws->tx_end - dws->tx) / dws->n_bytes; + left = (left > int_level) ? int_level : left; + + while (left--) dws->write(dws); + dws->read(dws); - if (dws->tx == dws->tx_end) { - spi_mask_intr(dws, SPI_INT_TXEI); + /* Re-enable the IRQ if there is still data left to tx */ + if (dws->tx_end > dws->tx) + spi_umask_intr(dws, SPI_INT_TXEI); + else transfer_complete(dws); - } } - /* INT comes from rx */ - if (dws->rx && (irq_status & SPI_INT_RXFI)) { - if (dws->read(dws)) - transfer_complete(dws); - } return IRQ_HANDLED; } @@ -428,6 +431,7 @@ static void pump_transfers(unsigned long data) u8 bits = 0; u8 imask = 0; u8 cs_change = 0; + u16 txint_level = 0; u16 clk_div = 0; u32 speed = 0; u32 cr0 = 0; @@ -438,6 +442,9 @@ static void pump_transfers(unsigned long data) chip = dws->cur_chip; spi = message->spi; + if (unlikely(!chip->clk_div)) + chip->clk_div = dws->max_freq / chip->speed_hz; + if (message->state == ERROR_STATE) { message->status = -EIO; goto early_exit; @@ -492,7 +499,7 @@ static void pump_transfers(unsigned long data) /* clk_div doesn't support odd number */ clk_div = dws->max_freq / speed; - clk_div = (clk_div >> 1) << 1; + clk_div = (clk_div + 1) & 0xfffe; chip->speed_hz = speed; chip->clk_div = clk_div; @@ -535,11 +542,16 @@ static void pump_transfers(unsigned long data) /* Check if current transfer is a DMA transaction */ dws->dma_mapped = map_dma_buffers(dws); + /* + * Interrupt mode + * we only need set the TXEI IRQ, as TX/RX always happen syncronizely + */ if (!dws->dma_mapped && !chip->poll_mode) { - if (dws->rx) - imask |= SPI_INT_RXFI; - if (dws->tx) - imask |= SPI_INT_TXEI; + int templen = dws->len / dws->n_bytes; + txint_level = dws->fifo_len / 2; + txint_level = (templen > txint_level) ? txint_level : templen; + + imask |= SPI_INT_TXEI; dws->transfer_handler = interrupt_transfer; } @@ -549,21 +561,23 @@ static void pump_transfers(unsigned long data) * 2. clk_div is changed * 3. control value changes */ - if (dw_readw(dws, ctrl0) != cr0 || cs_change || clk_div) { + if (dw_readw(dws, ctrl0) != cr0 || cs_change || clk_div || imask) { spi_enable_chip(dws, 0); if (dw_readw(dws, ctrl0) != cr0) dw_writew(dws, ctrl0, cr0); + spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); + spi_chip_sel(dws, spi->chip_select); + /* Set the interrupt mask, for poll mode just diable all int */ spi_mask_intr(dws, 0xff); - if (!chip->poll_mode) + if (imask) spi_umask_intr(dws, imask); + if (txint_level) + dw_writew(dws, txfltr, txint_level); - spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); - spi_chip_sel(dws, spi->chip_select); spi_enable_chip(dws, 1); - if (cs_change) dws->prev_chip = chip; } @@ -712,11 +726,11 @@ static int dw_spi_setup(struct spi_device *spi) } chip->bits_per_word = spi->bits_per_word; + if (!spi->max_speed_hz) { + dev_err(&spi->dev, "No max speed HZ parameter\n"); + return -EINVAL; + } chip->speed_hz = spi->max_speed_hz; - if (chip->speed_hz) - chip->clk_div = 25000000 / chip->speed_hz; - else - chip->clk_div = 8; /* default value */ chip->tmode = 0; /* Tx & Rx */ /* Default SPI mode is SCPOL = 0, SCPH = 0 */ diff --git a/drivers/spi/dw_spi_pci.c b/drivers/spi/dw_spi_pci.c index 7980f1443ce1..1f0735f9cc76 100644 --- a/drivers/spi/dw_spi_pci.c +++ b/drivers/spi/dw_spi_pci.c @@ -73,6 +73,7 @@ static int __devinit spi_pci_probe(struct pci_dev *pdev, dws->num_cs = 4; dws->max_freq = 25000000; /* for Moorestwon */ dws->irq = pdev->irq; + dws->fifo_len = 40; /* FIFO has 40 words buffer */ ret = dw_spi_add_host(dws); if (ret) -- cgit v1.2.2 From ac48eee064f743a198cb38e5a6a62c3f1082ebc1 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 20 Jan 2010 13:49:45 -0700 Subject: spi: update MSIOF includes Update the MSIOF driver to remove the architecture speficic spi header file and add err.h. This makes the driver compile on non-SH architectures. Signed-off-by: Magnus Damm Signed-off-by: Grant Likely --- drivers/spi/spi_sh_msiof.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi_sh_msiof.c b/drivers/spi/spi_sh_msiof.c index 51e5e1dfa6e5..3b5b1be57057 100644 --- a/drivers/spi/spi_sh_msiof.c +++ b/drivers/spi/spi_sh_msiof.c @@ -20,12 +20,12 @@ #include #include #include +#include #include #include #include -#include #include struct sh_msiof_spi_priv { -- cgit v1.2.2 From f4d4ecfe788b4141d8c90cfc3ac2831f620f5c1b Mon Sep 17 00:00:00 2001 From: Alberto Panizzo Date: Wed, 20 Jan 2010 13:49:45 -0700 Subject: spi/spi_imx: add device information by switching pr_debug() to dev_dbg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Useful when debugging multiple spi channels. Signed-off-by: Alberto Panizzo Acked-by: Uwe Kleine-König Signed-off-by: Grant Likely --- drivers/spi/spi_imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c index 1893f1e96dc4..0ddbbe45e834 100644 --- a/drivers/spi/spi_imx.c +++ b/drivers/spi/spi_imx.c @@ -469,7 +469,7 @@ static int spi_imx_setup(struct spi_device *spi) struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); int gpio = spi_imx->chipselect[spi->chip_select]; - pr_debug("%s: mode %d, %u bpw, %d hz\n", __func__, + dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", __func__, spi->mode, spi->bits_per_word, spi->max_speed_hz); if (gpio >= 0) -- cgit v1.2.2 From 9778214990af88ec6720bd771d7fc0fa1b140b02 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 20 Jan 2010 13:49:45 -0700 Subject: spi: xilinx_spi: Fix up I/O routine wrapping bogosity. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit xilinx_spi presently makes some fairly questionable assumptions about I/O routines, and attempts to assign ioread32/iowrite32 and friends directly to its own internal function pointers. On many platforms these I/O routines are macros or wrappers and not actual functions on their own, resulting in things like: ERROR: "ioread32be" [drivers/spi/xilinx_spi.ko] undefined! ERROR: "iowrite32be" [drivers/spi/xilinx_spi.ko] undefined! ERROR: "iowrite32" [drivers/spi/xilinx_spi.ko] undefined! ERROR: "ioread32" [drivers/spi/xilinx_spi.ko] undefined! If xilinx_spi wants to do this sort of casting, it needs to provide its own wrappers for these, or change how it does accesses completely. I've opted for the first approach, and the attached silly patch does that. If someone with the hardware available wants to give the second option a try that's ok too. In any event, the current code is broken for at least: arm, avr32, blackfin, microblaze, mn10300, and sh. Signed-off-by: Paul Mundt Acked-by: Richard Röjfors Signed-off-by: Grant Likely --- drivers/spi/xilinx_spi.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index 9f386379c169..1b47363cb73f 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -93,6 +93,26 @@ struct xilinx_spi { void (*rx_fn) (struct xilinx_spi *); }; +static void xspi_write32(u32 val, void __iomem *addr) +{ + iowrite32(val, addr); +} + +static unsigned int xspi_read32(void __iomem *addr) +{ + return ioread32(addr); +} + +static void xspi_write32_be(u32 val, void __iomem *addr) +{ + iowrite32be(val, addr); +} + +static unsigned int xspi_read32_be(void __iomem *addr) +{ + return ioread32be(addr); +} + static void xspi_tx8(struct xilinx_spi *xspi) { xspi->write_fn(*xspi->tx_ptr, xspi->regs + XSPI_TXD_OFFSET); @@ -374,11 +394,11 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, xspi->mem = *mem; xspi->irq = irq; if (pdata->little_endian) { - xspi->read_fn = ioread32; - xspi->write_fn = iowrite32; + xspi->read_fn = xspi_read32; + xspi->write_fn = xspi_write32; } else { - xspi->read_fn = ioread32be; - xspi->write_fn = iowrite32be; + xspi->read_fn = xspi_read32_be; + xspi->write_fn = xspi_write32_be; } xspi->bits_per_word = pdata->bits_per_word; if (xspi->bits_per_word == 8) { -- cgit v1.2.2 From 99147b5c4167612a987860b661b9f8b79e66b81f Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 20 Jan 2010 14:03:39 -0700 Subject: spi/dw_spi: fix __init/__devinit section mismatch Section mismatch in reference from the function dw_spi_add_host() to the function init_queue() Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index 1bb709b3920f..f713af8309e3 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -749,7 +749,7 @@ static void dw_spi_cleanup(struct spi_device *spi) kfree(chip); } -static int __init init_queue(struct dw_spi *dws) +static int __devinit init_queue(struct dw_spi *dws) { INIT_LIST_HEAD(&dws->queue); spin_lock_init(&dws->lock); -- cgit v1.2.2 From c587b6fa05106606053fc5e8e344f07cd34ace23 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Thu, 21 Jan 2010 10:41:10 +0800 Subject: spi/dw_spi: add a FIFO depth detection FIFO depth is configurable for each implementation of DW core, so add a depth detection for those interface drivers who don't set the fifo_len explicitly Signed-off-by: Feng Tang Acked-by: Jean-Hugues Deschenes Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index f713af8309e3..d948ef4f3910 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -831,6 +831,22 @@ static void spi_hw_init(struct dw_spi *dws) spi_mask_intr(dws, 0xff); spi_enable_chip(dws, 1); flush(dws); + + /* + * Try to detect the FIFO depth if not set by interface driver, + * the depth could be from 2 to 256 from HW spec + */ + if (!dws->fifo_len) { + u32 fifo; + for (fifo = 2; fifo <= 257; fifo++) { + dw_writew(dws, txfltr, fifo); + if (fifo != dw_readw(dws, txfltr)) + break; + } + + dws->fifo_len = (fifo == 257) ? 0 : fifo; + dw_writew(dws, txfltr, 0); + } } int __devinit dw_spi_add_host(struct dw_spi *dws) -- cgit v1.2.2 From 20a588fcc862df79d8fcafbc41950e3ae93dea09 Mon Sep 17 00:00:00 2001 From: George Shore Date: Thu, 21 Jan 2010 11:40:49 +0000 Subject: spi/dw_spi: add return value to empty mrst_spi_debugfs_init() As per the function signature. Signed-off-by: George Shore Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index d948ef4f3910..cf945a4cc419 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -152,6 +152,7 @@ static void mrst_spi_debugfs_remove(struct dw_spi *dws) #else static inline int mrst_spi_debugfs_init(struct dw_spi *dws) { + return 0; } static inline void mrst_spi_debugfs_remove(struct dw_spi *dws) -- cgit v1.2.2 From 426c0093d8da4d7b6b0e62cda917b1bae26db4c2 Mon Sep 17 00:00:00 2001 From: George Shore Date: Thu, 21 Jan 2010 11:40:50 +0000 Subject: spi/dw_spi: fixed a spelling typo in a warning message. Signed-off-by: George Shore Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index cf945a4cc419..d0a080a5b598 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -169,7 +169,7 @@ static void wait_till_not_busy(struct dw_spi *dws) return; } dev_err(&dws->master->dev, - "DW SPI: Stutus keeps busy for 1000us after a read/write!\n"); + "DW SPI: Status keeps busy for 1000us after a read/write!\n"); } static void flush(struct dw_spi *dws) -- cgit v1.2.2 From f4aec798ae5a837a1f062e295f9a5f1b00962589 Mon Sep 17 00:00:00 2001 From: George Shore Date: Thu, 21 Jan 2010 11:40:51 +0000 Subject: spi/dw_spi: remove conditional from 'poll_transfer'. The 'poll_transfer' function employs a conditional to test whether the transmit buffer is valid; in doing so, on a receive operation no data is clocked out, thus no data is clocked in and ultimately errors appear. This removes the conditional as the transmit function will be set to a null writer when the transmit buffer is invalid, allowing the driver to clock 0x00 out to the device to receive data from the device. Signed-off-by: George Shore Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index d0a080a5b598..3853df5db052 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -408,12 +408,9 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id) /* Must be called inside pump_transfers() */ static void poll_transfer(struct dw_spi *dws) { - if (dws->tx) { - while (dws->write(dws)) - dws->read(dws); - } + while (dws->write(dws)) + dws->read(dws); - dws->read(dws); transfer_complete(dws); } -- cgit v1.2.2 From 052dc7c45d8f685fb3720a08331ba3e91e87937e Mon Sep 17 00:00:00 2001 From: George Shore Date: Thu, 21 Jan 2010 11:40:52 +0000 Subject: spi/dw_spi: conditional transfer mode changes This allows the switching between transfer modes between 'transmit only', 'receive only' and 'transmit and receive' modes. Due to the design of the SPI block, changing transfer modes requires that the block be disabled; in doing so the chipselect line is inherently deasserted and (usually) the attached device discards its state. Consequentially, switching modes requires that a platform-specific chipselect function has been defined so that the chipselect is not dropped during the change. Signed-off-by: George Shore Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index 3853df5db052..e434320fded8 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -537,6 +537,22 @@ static void pump_transfers(unsigned long data) } message->state = RUNNING_STATE; + /* + * Adjust transfer mode if necessary. Requires platform dependent + * chipselect mechanism. + */ + if (dws->cs_control) { + if (dws->rx && dws->tx) + chip->tmode = 0x00; + else if (dws->rx) + chip->tmode = 0x02; + else + chip->tmode = 0x01; + + cr0 &= ~(0x3 << SPI_MODE_OFFSET); + cr0 |= (chip->tmode << SPI_TMOD_OFFSET); + } + /* Check if current transfer is a DMA transaction */ dws->dma_mapped = map_dma_buffers(dws); -- cgit v1.2.2 From 8bcb4a88c5834c6a0fc7140edea32186664fe360 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Thu, 21 Jan 2010 07:25:38 -0700 Subject: spi/dw_spi: fix missing export of dw_spi_remove_host So that interface drivers could be built as modules Signed-off-by: Feng Tang Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index e434320fded8..8ed38f1d6c18 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -957,6 +957,7 @@ void __devexit dw_spi_remove_host(struct dw_spi *dws) /* Disconnect from the SPI framework */ spi_unregister_master(dws->master); } +EXPORT_SYMBOL(dw_spi_remove_host); int dw_spi_suspend_host(struct dw_spi *dws) { -- cgit v1.2.2 From f7b6fd6d1d3833529f1626c761ba7e338586d35e Mon Sep 17 00:00:00 2001 From: Jean-Hugues Deschenes Date: Thu, 21 Jan 2010 07:46:42 -0700 Subject: Memory-mapped dw_spi driver Adds a memory-mapped I/O dw_spi platform device. Signed-off-by: Jean-Hugues Deschenes Signed-off-by: Grant Likely --- drivers/spi/Kconfig | 4 ++ drivers/spi/Makefile | 1 + drivers/spi/dw_spi_mmio.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 drivers/spi/dw_spi_mmio.c (limited to 'drivers') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 28becdd4dea9..201746ad825c 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -334,6 +334,10 @@ config SPI_DW_PCI tristate "PCI interface driver for DW SPI core" depends on SPI_DESIGNWARE && PCI +config SPI_DW_MMIO + tristate "Memory-mapped io interface driver for DW SPI core" + depends on SPI_DESIGNWARE + # # There are lots of SPI device types, with sensors and memory # being probably the most widely used ones. diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index d3a65ab8ebbf..d7d0f89b797b 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_SPI_COLDFIRE_QSPI) += coldfire_qspi.o obj-$(CONFIG_SPI_DAVINCI) += davinci_spi.o obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.o obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o +obj-$(CONFIG_SPI_DW_MMIO) += dw_spi_mmio.o obj-$(CONFIG_SPI_GPIO) += spi_gpio.o obj-$(CONFIG_SPI_IMX) += spi_imx.o obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o diff --git a/drivers/spi/dw_spi_mmio.c b/drivers/spi/dw_spi_mmio.c new file mode 100644 index 000000000000..26c4b49bdd5c --- /dev/null +++ b/drivers/spi/dw_spi_mmio.c @@ -0,0 +1,148 @@ +/* + * dw_spi_mmio.c - Memory-mapped interface driver for DW SPI Core + * + * Copyright (c) 2010, Octasic semiconductor. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#define DRIVER_NAME "dw_spi_mmio" + +struct dw_spi_mmio { + struct dw_spi dws; + struct clk *clk; +}; + +static int __devinit dw_spi_mmio_probe(struct platform_device *pdev) +{ + struct dw_spi_mmio *dwsmmio; + struct dw_spi *dws; + struct resource *mem, *ioarea; + int ret; + + dwsmmio = kzalloc(sizeof(struct dw_spi_mmio), GFP_KERNEL); + if (!dwsmmio) { + ret = -ENOMEM; + goto err_end; + } + + dws = &dwsmmio->dws; + + /* Get basic io resource and map it */ + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "no mem resource?\n"); + ret = -EINVAL; + goto err_kfree; + } + + ioarea = request_mem_region(mem->start, resource_size(mem), + pdev->name); + if (!ioarea) { + dev_err(&pdev->dev, "SPI region already claimed\n"); + ret = -EBUSY; + goto err_kfree; + } + + dws->regs = ioremap_nocache(mem->start, resource_size(mem)); + if (!dws->regs) { + dev_err(&pdev->dev, "SPI region already mapped\n"); + ret = -ENOMEM; + goto err_release_reg; + } + + dws->irq = platform_get_irq(pdev, 0); + if (dws->irq < 0) { + dev_err(&pdev->dev, "no irq resource?\n"); + ret = dws->irq; /* -ENXIO */ + goto err_unmap; + } + + dwsmmio->clk = clk_get(&pdev->dev, NULL); + if (!dwsmmio->clk) { + ret = -ENODEV; + goto err_irq; + } + clk_enable(dwsmmio->clk); + + dws->parent_dev = &pdev->dev; + dws->bus_num = 0; + dws->num_cs = 4; + dws->max_freq = clk_get_rate(dwsmmio->clk); + + ret = dw_spi_add_host(dws); + if (ret) + goto err_clk; + + platform_set_drvdata(pdev, dwsmmio); + return 0; + +err_clk: + clk_disable(dwsmmio->clk); + clk_put(dwsmmio->clk); + dwsmmio->clk = NULL; +err_irq: + free_irq(dws->irq, dws); +err_unmap: + iounmap(dws->regs); +err_release_reg: + release_mem_region(mem->start, resource_size(mem)); +err_kfree: + kfree(dwsmmio); +err_end: + return ret; +} + +static int __devexit dw_spi_mmio_remove(struct platform_device *pdev) +{ + struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev); + struct resource *mem; + + platform_set_drvdata(pdev, NULL); + + clk_disable(dwsmmio->clk); + clk_put(dwsmmio->clk); + dwsmmio->clk = NULL; + + free_irq(dwsmmio->dws.irq, &dwsmmio->dws); + dw_spi_remove_host(&dwsmmio->dws); + iounmap(dwsmmio->dws.regs); + kfree(dwsmmio); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(mem->start, resource_size(mem)); + return 0; +} + +static struct platform_driver dw_spi_mmio_driver = { + .remove = __devexit_p(dw_spi_mmio_remove), + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init dw_spi_mmio_init(void) +{ + return platform_driver_probe(&dw_spi_mmio_driver, dw_spi_mmio_probe); +} + +static void __exit dw_spi_mmio_exit(void) +{ + platform_driver_unregister(&dw_spi_mmio_driver); +} + +module_init(dw_spi_mmio_init); +module_exit(dw_spi_mmio_exit); + +MODULE_AUTHOR("Jean-Hugues Deschenes "); +MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.2 From 0a4c1d7d446d3ed6179f907541d180e49b56d4f4 Mon Sep 17 00:00:00 2001 From: Jean-Hugues Deschenes Date: Thu, 21 Jan 2010 09:55:42 -0700 Subject: spi/dw_spi: mmio code style fixups Minor code style cleanups following comments by Wolfram Sang Signed-off-by: Jean-Hugues Deschenes Signed-off-by: Grant Likely --- drivers/spi/dw_spi_mmio.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/dw_spi_mmio.c b/drivers/spi/dw_spi_mmio.c index 26c4b49bdd5c..e35b45ac5174 100644 --- a/drivers/spi/dw_spi_mmio.c +++ b/drivers/spi/dw_spi_mmio.c @@ -17,8 +17,8 @@ #define DRIVER_NAME "dw_spi_mmio" struct dw_spi_mmio { - struct dw_spi dws; - struct clk *clk; + struct dw_spi dws; + struct clk *clk; }; static int __devinit dw_spi_mmio_probe(struct platform_device *pdev) @@ -134,13 +134,12 @@ static int __init dw_spi_mmio_init(void) { return platform_driver_probe(&dw_spi_mmio_driver, dw_spi_mmio_probe); } +module_init(dw_spi_mmio_init); static void __exit dw_spi_mmio_exit(void) { platform_driver_unregister(&dw_spi_mmio_driver); } - -module_init(dw_spi_mmio_init); module_exit(dw_spi_mmio_exit); MODULE_AUTHOR("Jean-Hugues Deschenes "); -- cgit v1.2.2 From 8ca8d15ade201b7723fa386eadcce2044463ff56 Mon Sep 17 00:00:00 2001 From: Jean-Hugues Deschenes Date: Thu, 21 Jan 2010 09:55:54 -0700 Subject: spi/dw_spi: Allow dw_spi.c to be a module Signed-off-by: Jean-Hugues Deschenes Signed-off-by: Grant Likely --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 201746ad825c..1d1e39686c38 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -325,7 +325,7 @@ config SPI_NUC900 # config SPI_DESIGNWARE - bool "DesignWare SPI controller core support" + tristate "DesignWare SPI controller core support" depends on SPI_MASTER help general driver for SPI controller core from DesignWare -- cgit v1.2.2 From 212b3c8b8ab94d983c2e0ee1821f17dd5b4e0859 Mon Sep 17 00:00:00 2001 From: Jean-Hugues Deschenes Date: Fri, 22 Jan 2010 10:08:31 -0700 Subject: spi/dw_spi: Fix dw_spi_mmio to depend on HAVE_CLK dw_spi_mmio is dependent on the clock framework. This marks it as such in Kconfig. Signed-off-by: Jean-Hugues Deschenes Signed-off-by: Grant Likely --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 1d1e39686c38..0fee95cd9a49 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -336,7 +336,7 @@ config SPI_DW_PCI config SPI_DW_MMIO tristate "Memory-mapped io interface driver for DW SPI core" - depends on SPI_DESIGNWARE + depends on SPI_DESIGNWARE && HAVE_CLK # # There are lots of SPI device types, with sensors and memory -- cgit v1.2.2 From 0406ad336c066190770cbf350b552d608e43ed09 Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Wed, 20 Jan 2010 00:06:30 -0700 Subject: ACPI: processor: add kernel command line support for early _PDC eval Allow platforms not listed in DMI table to opt-in and evaluate _PDC early. Signed-off-by: Alex Chiang Signed-off-by: Len Brown --- drivers/acpi/processor_pdc.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c index 7247819dbd80..3bbafe9576ae 100644 --- a/drivers/acpi/processor_pdc.c +++ b/drivers/acpi/processor_pdc.c @@ -151,6 +151,13 @@ static int set_early_pdc_optin(const struct dmi_system_id *id) return 0; } +static int param_early_pdc_optin(char *s) +{ + early_pdc_optin = 1; + return 1; +} +__setup("acpi_early_pdc_eval", param_early_pdc_optin); + static struct dmi_system_id __cpuinitdata early_pdc_optin_table[] = { { set_early_pdc_optin, "HP Envy", { -- cgit v1.2.2 From a4932299d03a1c20e58e4cc40a66fb0a048fb3a7 Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Wed, 20 Jan 2010 00:06:35 -0700 Subject: ACPI: processor: only evaluate _PDC once per processor If we evaluate _PDC in the early path, we do not want to evaluate it again when the processor driver is loaded. Cc: Venkatesh Pallipadi Signed-off-by: Alex Chiang Signed-off-by: Len Brown --- drivers/acpi/processor_pdc.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c index 3bbafe9576ae..e306ba9aa34e 100644 --- a/drivers/acpi/processor_pdc.c +++ b/drivers/acpi/processor_pdc.c @@ -125,6 +125,8 @@ acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in) return status; } +static int early_pdc_done; + void acpi_processor_set_pdc(acpi_handle handle) { struct acpi_object_list *obj_list; @@ -132,6 +134,9 @@ void acpi_processor_set_pdc(acpi_handle handle) if (arch_has_acpi_pdc() == false) return; + if (early_pdc_done) + return; + obj_list = acpi_processor_alloc_pdc(); if (!obj_list) return; @@ -199,4 +204,6 @@ void __init acpi_early_processor_set_pdc(void) acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, early_init_pdc, NULL, NULL, NULL); + + early_pdc_done = 1; } -- cgit v1.2.2 From 48a719c238bcbb72d6da79de9c5b3b93ab472107 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 22 Jan 2010 16:01:04 +0100 Subject: intel-agp: Switch to wbinvd_on_all_cpus Simplify if-statement while at it. [ hpa: we need to #include ] Cc: Dave Jones Cc: David Airlie Signed-off-by: Borislav Petkov LKML-Reference: <1264172467-25155-3-git-send-email-bp@amd64.org> Signed-off-by: H. Peter Anvin --- drivers/char/agp/intel-agp.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 3999a5f25f38..8a713f1e9653 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "agp.h" /* @@ -815,12 +816,6 @@ static void intel_i830_setup_flush(void) intel_i830_fini_flush(); } -static void -do_wbinvd(void *null) -{ - wbinvd(); -} - /* The chipset_flush interface needs to get data that has already been * flushed out of the CPU all the way out to main memory, because the GPU * doesn't snoop those buffers. @@ -837,12 +832,10 @@ static void intel_i830_chipset_flush(struct agp_bridge_data *bridge) memset(pg, 0, 1024); - if (cpu_has_clflush) { + if (cpu_has_clflush) clflush_cache_range(pg, 1024); - } else { - if (on_each_cpu(do_wbinvd, NULL, 1) != 0) - printk(KERN_ERR "Timed out waiting for cache flush.\n"); - } + else if (wbinvd_on_all_cpus() != 0) + printk(KERN_ERR "Timed out waiting for cache flush.\n"); } /* The intel i830 automatically initializes the agp aperture during POST. -- cgit v1.2.2 From 3970dd8c5169505f0cc5e4c3e2fde7bdd9bbad3e Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Jan 2010 23:19:45 +0100 Subject: pcmcia: do not lock socket driver module on card insert Do not lock the socket driver module on card insert, as the PCMCIA core can handle a socket module removal, at least if we add a call to socket_remove() on pccardd()'s shutdown. Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs.c | 13 ++++++++++--- drivers/pcmcia/cs_internal.h | 20 -------------------- 2 files changed, 10 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index f0630a61da90..137a5db2eca2 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -407,7 +407,7 @@ static void socket_shutdown(struct pcmcia_socket *s) "*** DANGER *** unable to remove socket power\n"); } - cs_socket_put(s); + s->state &= ~SOCKET_INUSE; } static int socket_setup(struct pcmcia_socket *skt, int initial_delay) @@ -496,8 +496,8 @@ static int socket_insert(struct pcmcia_socket *skt) dev_dbg(&skt->dev, "insert\n"); - if (!cs_socket_get(skt)) - return -ENODEV; + WARN_ON(skt->state & SOCKET_INUSE); + skt->state |= SOCKET_INUSE; ret = socket_setup(skt, setup_delay); if (ret == 0) { @@ -697,6 +697,13 @@ static int pccardd(void *__skt) /* make sure we are running before we exit */ set_current_state(TASK_RUNNING); + /* shut down socket, if a device is still present */ + if (skt->state & SOCKET_PRESENT) { + mutex_lock(&skt->skt_mutex); + socket_remove(skt); + mutex_unlock(&skt->skt_mutex); + } + /* remove from the device core */ pccard_sysfs_remove_socket(&skt->dev); device_unregister(&skt->dev); diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 3bc02d53a3a3..9a3bbad7761b 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -87,26 +87,6 @@ struct pccard_resource_ops { #define SOCKET_CARDBUS 0x8000 #define SOCKET_CARDBUS_CONFIG 0x10000 -static inline int cs_socket_get(struct pcmcia_socket *skt) -{ - int ret; - - WARN_ON(skt->state & SOCKET_INUSE); - - ret = try_module_get(skt->owner); - if (ret) - skt->state |= SOCKET_INUSE; - return ret; -} - -static inline void cs_socket_put(struct pcmcia_socket *skt) -{ - if (skt->state & SOCKET_INUSE) { - skt->state &= ~SOCKET_INUSE; - module_put(skt->owner); - } -} - /* * Stuff internal to module "pcmcia_core": -- cgit v1.2.2 From 385ee871092a524869c71a8180888aadcd6ca36d Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Wed, 6 Jan 2010 11:23:58 +0100 Subject: pcmcia: remove useless indirection As release_resoure_db() used to be called only from one place, and it's a two-line function, remove it. Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs.c | 3 ++- drivers/pcmcia/cs_internal.h | 3 --- drivers/pcmcia/rsrc_mgr.c | 6 ------ 3 files changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 137a5db2eca2..43c90f69a7a5 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -283,7 +283,8 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket) up_write(&pcmcia_socket_list_rwsem); /* wait for sysfs to drop all references */ - release_resource_db(socket); + if (socket->resource_ops->exit) + socket->resource_ops->exit(socket); wait_for_completion(&socket->socket_released); } /* pcmcia_unregister_socket */ EXPORT_SYMBOL(pcmcia_unregister_socket); diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 9a3bbad7761b..7f86d09a5830 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -95,9 +95,6 @@ struct pccard_resource_ops { /* cistpl.c */ int verify_cis_cache(struct pcmcia_socket *s); -/* rsrc_mgr.c */ -void release_resource_db(struct pcmcia_socket *s); - /* socket_sysfs.c */ extern int pccard_sysfs_add_socket(struct device *dev); extern void pccard_sysfs_remove_socket(struct device *dev); diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index 52db17263d8b..66c780073cd2 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -58,12 +58,6 @@ struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align, } EXPORT_SYMBOL(pcmcia_find_mem_region); -void release_resource_db(struct pcmcia_socket *s) -{ - if (s->resource_ops->exit) - s->resource_ops->exit(s); -} - static int static_init(struct pcmcia_socket *s) { -- cgit v1.2.2 From f9c316f4a2d32e4d03497ecb24e1d2309361a5b8 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Wed, 6 Jan 2010 11:32:22 +0100 Subject: pcmcia: remove some rsrc_mgr indirections Remove rsrc_mgr indirections only used by pcmcia_resource.c Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs_internal.h | 8 -------- drivers/pcmcia/pcmcia_resource.c | 17 +++++++++++++++++ drivers/pcmcia/rsrc_mgr.c | 18 ------------------ 3 files changed, 17 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 7f86d09a5830..ad05e3b59473 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -168,14 +168,6 @@ int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple); /* rsrc_mgr.c */ int pcmcia_validate_mem(struct pcmcia_socket *s); -struct resource *pcmcia_find_io_region(unsigned long base, - int num, - unsigned long align, - struct pcmcia_socket *s); -int pcmcia_adjust_io_region(struct resource *res, - unsigned long r_start, - unsigned long r_end, - struct pcmcia_socket *s); struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align, diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index d5db95644b64..880b0b63b6a3 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -43,6 +43,23 @@ module_param(io_speed, int, 0444); static u8 pcmcia_used_irq[NR_IRQS]; #endif +static int pcmcia_adjust_io_region(struct resource *res, unsigned long start, + unsigned long end, struct pcmcia_socket *s) +{ + if (s->resource_ops->adjust_io_region) + return s->resource_ops->adjust_io_region(res, start, end, s); + return -ENOMEM; +} + +static struct resource *pcmcia_find_io_region(unsigned long base, int num, + unsigned long align, + struct pcmcia_socket *s) +{ + if (s->resource_ops->find_io) + return s->resource_ops->find_io(base, num, align, s); + return NULL; +} + /** alloc_io_space * diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index 66c780073cd2..81540c420bbd 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -31,24 +31,6 @@ int pcmcia_validate_mem(struct pcmcia_socket *s) } EXPORT_SYMBOL(pcmcia_validate_mem); -int pcmcia_adjust_io_region(struct resource *res, unsigned long r_start, - unsigned long r_end, struct pcmcia_socket *s) -{ - if (s->resource_ops->adjust_io_region) - return s->resource_ops->adjust_io_region(res, r_start, r_end, s); - return -ENOMEM; -} -EXPORT_SYMBOL(pcmcia_adjust_io_region); - -struct resource *pcmcia_find_io_region(unsigned long base, int num, - unsigned long align, struct pcmcia_socket *s) -{ - if (s->resource_ops->find_io) - return s->resource_ops->find_io(base, num, align, s); - return NULL; -} -EXPORT_SYMBOL(pcmcia_find_io_region); - struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align, int low, struct pcmcia_socket *s) { -- cgit v1.2.2 From a7eb169dc7292979d78f2d2f1655026ae3a9ff5f Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Wed, 6 Jan 2010 12:18:13 +0100 Subject: pcmcia: m32r uses static socket resources m32r_cfc sets the socket capabilities to SS_CAP_STATIC_MAP and also sets io_offset != 0. This means no calls to &pccard_nonstatic_ops went through. Therfore, replace it with &pccard_static_ops which is exactly for this case. CC: Mamoru Sakugawa CC: Hirokazu Takata Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/Kconfig | 2 -- drivers/pcmcia/m32r_cfc.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 9f3adbd9f700..7e9fd38e14fb 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -238,14 +238,12 @@ config PCMCIA_PROBE config M32R_PCC bool "M32R PCMCIA I/F" depends on M32R && CHIP_M32700 && PCMCIA - select PCCARD_NONSTATIC help Say Y here to use the M32R PCMCIA controller. config M32R_CFC bool "M32R CF I/F Controller" depends on M32R && (PLAT_USRV || PLAT_M32700UT || PLAT_MAPPI2 || PLAT_MAPPI3 || PLAT_OPSPUT) - select PCCARD_NONSTATIC help Say Y here to use the M32R CompactFlash controller. diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index 26a621c9e2fc..0ece2cd4a85e 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -764,7 +764,7 @@ static int __init init_m32r_pcc(void) for (i = 0 ; i < pcc_sockets ; i++) { socket[i].socket.dev.parent = &pcc_device.dev; socket[i].socket.ops = &pcc_operations; - socket[i].socket.resource_ops = &pccard_nonstatic_ops; + socket[i].socket.resource_ops = &pccard_static_ops; socket[i].socket.owner = THIS_MODULE; socket[i].number = i; ret = pcmcia_register_socket(&socket[i].socket); -- cgit v1.2.2 From cd9ec30da58bcd8ab154eba9eb54d16c67e7ef3b Mon Sep 17 00:00:00 2001 From: Johnathon Harris Date: Thu, 21 Jan 2010 14:36:52 +0000 Subject: HID: add support for Ortek WKB-2000 This patch adds a new USB HID driver for the Ortek WKB-2000, working around an incorrect LogicalMaximum value in the USB resource descriptor. Tracked by http://bugzilla.kernel.org/show_bug.cgi?id=14787 Bug originally reported by Ubuntu users: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/405390 Signed-off-by: Johnathon Harris Tested-by: Daniel J Blueman Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 +++++++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-ortek.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+) create mode 100644 drivers/hid/hid-ortek.c (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 38e969207636..139668d6382a 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -218,6 +218,13 @@ config HID_NTRIG ---help--- Support for N-Trig touch screen. +config HID_ORTEK + tristate "Ortek" if EMBEDDED + depends on USB_HID + default !EMBEDDED + ---help--- + Support for Ortek WKB-2000 wireless keyboard + mouse trackpad. + config HID_PANTHERLORD tristate "Pantherlord support" if EMBEDDED depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 15541c47b172..b62d4b3afdc2 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o +obj-$(CONFIG_HID_ORTEK) += hid-ortek.o obj-$(CONFIG_HID_QUANTA) += hid-quanta.o obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 116a3460e75a..7fe509879fe3 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1337,6 +1337,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 064c09a221ef..6c38359385a9 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -363,6 +363,9 @@ #define USB_VENDOR_ID_ONTRAK 0x0a07 #define USB_DEVICE_ID_ONTRAK_ADU100 0x0064 +#define USB_VENDOR_ID_ORTEK 0x05a4 +#define USB_DEVICE_ID_ORTEK_WKB2000 0x2000 + #define USB_VENDOR_ID_PANJIT 0x134c #define USB_VENDOR_ID_PANTHERLORD 0x0810 diff --git a/drivers/hid/hid-ortek.c b/drivers/hid/hid-ortek.c new file mode 100644 index 000000000000..aa9a960f73a4 --- /dev/null +++ b/drivers/hid/hid-ortek.c @@ -0,0 +1,56 @@ +/* + * HID driver for Ortek WKB-2000 (wireless keyboard + mouse trackpad). + * Fixes LogicalMaximum error in USB report description, see + * http://bugzilla.kernel.org/show_bug.cgi?id=14787 + * + * Copyright (c) 2010 Johnathon Harris + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include + +#include "hid-ids.h" + +static void ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) +{ + if (rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x01) { + dev_info(&hdev->dev, "Fixing up Ortek WKB-2000 " + "report descriptor.\n"); + rdesc[55] = 0x92; + } +} + +static const struct hid_device_id ortek_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, + { } +}; +MODULE_DEVICE_TABLE(hid, ortek_devices); + +static struct hid_driver ortek_driver = { + .name = "ortek", + .id_table = ortek_devices, + .report_fixup = ortek_report_fixup +}; + +static int __init ortek_init(void) +{ + return hid_register_driver(&ortek_driver); +} + +static void __exit ortek_exit(void) +{ + hid_unregister_driver(&ortek_driver); +} + +module_init(ortek_init); +module_exit(ortek_exit); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 1f43cfb9474d1c4f22598b6e3213ec035be6dd56 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 28 Jan 2010 13:47:25 -0700 Subject: of: merge machine_is_compatible() Merge common code between PowerPC and Microblaze Signed-off-by: Grant Likely Tested-by: Wolfram Sang Acked-by: Benjamin Herrenschmidt --- drivers/of/base.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index ec56739eb247..dba995b70b84 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -143,6 +143,27 @@ int of_device_is_compatible(const struct device_node *device, } EXPORT_SYMBOL(of_device_is_compatible); +/** + * machine_is_compatible - Test root of device tree for a given compatible value + * @compat: compatible string to look for in root node's compatible property. + * + * Returns true if the root node has the given value in its + * compatible property. + */ +int machine_is_compatible(const char *compat) +{ + struct device_node *root; + int rc = 0; + + root = of_find_node_by_path("/"); + if (root) { + rc = of_device_is_compatible(root, compat); + of_node_put(root); + } + return rc; +} +EXPORT_SYMBOL(machine_is_compatible); + /** * of_device_is_available - check if a device is available for use * -- cgit v1.2.2 From 923f7e30b480438f1e86e01e5cde814248b59a39 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 28 Jan 2010 13:52:53 -0700 Subject: of: Merge of_node_get() and of_node_put() Merge common code between PowerPC and MicroBlaze Signed-off-by: Grant Likely Tested-by: Wolfram Sang Acked-by: Benjamin Herrenschmidt --- drivers/of/base.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index dba995b70b84..cf89ee6253f3 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -60,6 +60,81 @@ int of_n_size_cells(struct device_node *np) } EXPORT_SYMBOL(of_n_size_cells); +#if !defined(CONFIG_SPARC) /* SPARC doesn't do ref counting (yet) */ +/** + * of_node_get - Increment refcount of a node + * @node: Node to inc refcount, NULL is supported to + * simplify writing of callers + * + * Returns node. + */ +struct device_node *of_node_get(struct device_node *node) +{ + if (node) + kref_get(&node->kref); + return node; +} +EXPORT_SYMBOL(of_node_get); + +static inline struct device_node *kref_to_device_node(struct kref *kref) +{ + return container_of(kref, struct device_node, kref); +} + +/** + * of_node_release - release a dynamically allocated node + * @kref: kref element of the node to be released + * + * In of_node_put() this function is passed to kref_put() + * as the destructor. + */ +static void of_node_release(struct kref *kref) +{ + struct device_node *node = kref_to_device_node(kref); + struct property *prop = node->properties; + + /* We should never be releasing nodes that haven't been detached. */ + if (!of_node_check_flag(node, OF_DETACHED)) { + pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name); + dump_stack(); + kref_init(&node->kref); + return; + } + + if (!of_node_check_flag(node, OF_DYNAMIC)) + return; + + while (prop) { + struct property *next = prop->next; + kfree(prop->name); + kfree(prop->value); + kfree(prop); + prop = next; + + if (!prop) { + prop = node->deadprops; + node->deadprops = NULL; + } + } + kfree(node->full_name); + kfree(node->data); + kfree(node); +} + +/** + * of_node_put - Decrement refcount of a node + * @node: Node to dec refcount, NULL is supported to + * simplify writing of callers + * + */ +void of_node_put(struct device_node *node) +{ + if (node) + kref_put(&node->kref, of_node_release); +} +EXPORT_SYMBOL(of_node_put); +#endif /* !CONFIG_SPARC */ + struct property *of_find_property(const struct device_node *np, const char *name, int *lenp) -- cgit v1.2.2 From 6016a363f6b56b46b24655bcfc0499b715851cf3 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 28 Jan 2010 14:06:53 -0700 Subject: of: unify phandle name in struct device_node In struct device_node, the phandle is named 'linux_phandle' for PowerPC and MicroBlaze, and 'node' for SPARC. There is no good reason for the difference, it is just an artifact of the code diverging over a couple of years. This patch renames both to simply .phandle. Note: the .node also existed in PowerPC/MicroBlaze, but the only user seems to be arch/powerpc/platforms/powermac/pfunc_core.c. It doesn't look like the assignment between .linux_phandle and .node is significantly different enough to warrant the separate code paths unless ibm,phandle properties actually appear in Apple device trees. I think it is safe to eliminate the old .node property and use phandle everywhere. Signed-off-by: Grant Likely Acked-by: David S. Miller Tested-by: Wolfram Sang Acked-by: Benjamin Herrenschmidt --- drivers/of/fdt.c | 7 +++---- drivers/sbus/char/openprom.c | 10 +++++----- drivers/video/aty/atyfb_base.c | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 616a4767a950..7f8861121a31 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -310,12 +310,11 @@ unsigned long __init unflatten_dt_node(unsigned long mem, __alignof__(struct property)); if (allnextpp) { if (strcmp(pname, "linux,phandle") == 0) { - np->node = *((u32 *)*p); - if (np->linux_phandle == 0) - np->linux_phandle = np->node; + if (np->phandle == 0) + np->phandle = *((u32 *)*p); } if (strcmp(pname, "ibm,phandle") == 0) - np->linux_phandle = *((u32 *)*p); + np->phandle = *((u32 *)*p); pp->name = pname; pp->length = sz; pp->value = (void *)*p; diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index 75ac19b1192f..fc2f676e984d 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -233,7 +233,7 @@ static int opromnext(void __user *argp, unsigned int cmd, struct device_node *dp ph = 0; if (dp) - ph = dp->node; + ph = dp->phandle; data->current_node = dp; *((int *) op->oprom_array) = ph; @@ -256,7 +256,7 @@ static int oprompci2node(void __user *argp, struct device_node *dp, struct openp dp = pci_device_to_OF_node(pdev); data->current_node = dp; - *((int *)op->oprom_array) = dp->node; + *((int *)op->oprom_array) = dp->phandle; op->oprom_size = sizeof(int); err = copyout(argp, op, bufsize + sizeof(int)); @@ -273,7 +273,7 @@ static int oprompath2node(void __user *argp, struct device_node *dp, struct open dp = of_find_node_by_path(op->oprom_array); if (dp) - ph = dp->node; + ph = dp->phandle; data->current_node = dp; *((int *)op->oprom_array) = ph; op->oprom_size = sizeof(int); @@ -540,7 +540,7 @@ static int opiocgetnext(unsigned int cmd, void __user *argp) } } if (dp) - nd = dp->node; + nd = dp->phandle; if (copy_to_user(argp, &nd, sizeof(phandle))) return -EFAULT; @@ -570,7 +570,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file, case OPIOCGETOPTNODE: BUILD_BUG_ON(sizeof(phandle) != sizeof(int)); - if (copy_to_user(argp, &options_node->node, sizeof(phandle))) + if (copy_to_user(argp, &options_node->phandle, sizeof(phandle))) return -EFAULT; return 0; diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 913b4a47ae52..bb20987d58af 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -3104,7 +3104,7 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev, } dp = pci_device_to_OF_node(pdev); - if (node == dp->node) { + if (node == dp->phandle) { struct fb_var_screeninfo *var = &default_var; unsigned int N, P, Q, M, T, R; u32 v_total, h_total; -- cgit v1.2.2 From d2f6650a950dadd20667a04a9dc785f240d43695 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Fri, 29 Jan 2010 17:48:51 +0100 Subject: ACPI: Add NULL pointer check in acpi_bus_start If acpi_bus_add does not return a device and it's passed to acpi_bus_start, bad things will happen: BUG: unable to handle kernel NULL pointer dereference at 0000000000000008 IP: [] acpi_bus_start+0x14/0x24 ... [] acpiphp_bus_add+0xba/0x130 [acpiphp] [] enable_device+0x132/0x2ff [acpiphp] [] acpiphp_enable_slot+0xb8/0x130 [acpiphp] [] handle_hotplug_event_func+0x87/0x190 [acpiphp] Next patch would make this NULL pointer check obsolete, but better having one more than one missing... Signed-off-by: Thomas Renninger Acked-by: Bjorn Helgaas CC: stable@kernel.org Signed-off-by: Len Brown --- drivers/acpi/scan.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ff9f6226085d..8044583f3034 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1357,6 +1357,9 @@ int acpi_bus_start(struct acpi_device *device) { struct acpi_bus_ops ops; + if (!device) + return -EINVAL; + memset(&ops, 0, sizeof(ops)); ops.acpi_op_start = 1; -- cgit v1.2.2 From 7779688fc3d1ceddad84846a7b0affbe8e78ec6e Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Fri, 29 Jan 2010 17:48:52 +0100 Subject: ACPI: acpi_bus_{scan,bus,add}: return -ENODEV if no device was found Callers (acpi_memhotplug.c, dock.c and others) check for the return value of acpi_bus_add() and assume a valid device was returned in case zero was returned. Thus return -ENODEV if no device was found in acpi_bus_scan and propagate this through acpi_bus_add and acpi_bus_start. Also remove a confusing comment in acpiphp_glue.c, acpi_bus_scan will and cannot invoke if acpi_bus_add returns no valid device. Signed-off-by: Thomas Renninger Acked-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 24 +++++++++++++++++++----- drivers/pci/hotplug/acpiphp_glue.c | 6 ------ 2 files changed, 19 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 8044583f3034..3e009674f333 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1336,9 +1336,25 @@ static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops, if (child) *child = device; - return 0; + + if (device) + return 0; + else + return -ENODEV; } +/* + * acpi_bus_add and acpi_bus_start + * + * scan a given ACPI tree and (probably recently hot-plugged) + * create and add or starts found devices. + * + * If no devices were found -ENODEV is returned which does not + * mean that this is a real error, there just have been no suitable + * ACPI objects in the table trunk from which the kernel could create + * a device and add/start an appropriate driver. + */ + int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type) @@ -1348,8 +1364,7 @@ acpi_bus_add(struct acpi_device **child, memset(&ops, 0, sizeof(ops)); ops.acpi_op_add = 1; - acpi_bus_scan(handle, &ops, child); - return 0; + return acpi_bus_scan(handle, &ops, child); } EXPORT_SYMBOL(acpi_bus_add); @@ -1363,8 +1378,7 @@ int acpi_bus_start(struct acpi_device *device) memset(&ops, 0, sizeof(ops)); ops.acpi_op_start = 1; - acpi_bus_scan(device->handle, &ops, NULL); - return 0; + return acpi_bus_scan(device->handle, &ops, NULL); } EXPORT_SYMBOL(acpi_bus_start); diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 8e952fdab764..cb2fd01eddae 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -720,12 +720,6 @@ static int acpiphp_bus_add(struct acpiphp_func *func) -ret_val); goto acpiphp_bus_add_out; } - /* - * try to start anyway. We could have failed to add - * simply because this bus had previously been added - * on another add. Don't bother with the return value - * we just keep going. - */ ret_val = acpi_bus_start(device); acpiphp_bus_add_out: -- cgit v1.2.2 From b79c7adf82e8b8a6d6ad1dadf7e687a4a030cf8c Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 2 Feb 2010 13:01:25 +0900 Subject: mtd: trivial sh_flctl changes This patch contains a few changes for the sh_flctl driver: - not sh7723-only driver - get rid of kconfig dependency - use dev_err() instead of printk() - use __devinit and __devexit for probe()/remove() - fix probe() return values Signed-off-by: Magnus Damm Acked-by: Yoshihiro Shimoda Signed-off-by: Paul Mundt --- drivers/mtd/nand/Kconfig | 4 ++-- drivers/mtd/nand/sh_flctl.c | 42 +++++++++++++++++++++++------------------- 2 files changed, 25 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 677cd53f18c3..bb6465604235 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -457,10 +457,10 @@ config MTD_NAND_NOMADIK config MTD_NAND_SH_FLCTL tristate "Support for NAND on Renesas SuperH FLCTL" - depends on MTD_NAND && SUPERH && CPU_SUBTYPE_SH7723 + depends on MTD_NAND && SUPERH help Several Renesas SuperH CPU has FLCTL. This option enables support - for NAND Flash using FLCTL. This driver support SH7723. + for NAND Flash using FLCTL. config MTD_NAND_DAVINCI tristate "Support NAND on DaVinci SoC" diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 02bef21f2e4b..ab068a503b29 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -1,10 +1,10 @@ /* * SuperH FLCTL nand controller * - * Copyright © 2008 Renesas Solutions Corp. - * Copyright © 2008 Atom Create Engineering Co., Ltd. + * Copyright (c) 2008 Renesas Solutions Corp. + * Copyright (c) 2008 Atom Create Engineering Co., Ltd. * - * Based on fsl_elbc_nand.c, Copyright © 2006-2007 Freescale Semiconductor + * Based on fsl_elbc_nand.c, Copyright (c) 2006-2007 Freescale Semiconductor * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -75,6 +75,11 @@ static void start_translation(struct sh_flctl *flctl) writeb(TRSTRT, FLTRCR(flctl)); } +static void timeout_error(struct sh_flctl *flctl, const char *str) +{ + dev_err(&flctl->pdev->dev, "Timeout occured in %s\n", str); +} + static void wait_completion(struct sh_flctl *flctl) { uint32_t timeout = LOOP_TIMEOUT_MAX; @@ -87,7 +92,7 @@ static void wait_completion(struct sh_flctl *flctl) udelay(1); } - printk(KERN_ERR "wait_completion(): Timeout occured \n"); + timeout_error(flctl, __func__); writeb(0x0, FLTRCR(flctl)); } @@ -132,7 +137,7 @@ static void wait_rfifo_ready(struct sh_flctl *flctl) return; udelay(1); } - printk(KERN_ERR "wait_rfifo_ready(): Timeout occured \n"); + timeout_error(flctl, __func__); } static void wait_wfifo_ready(struct sh_flctl *flctl) @@ -146,7 +151,7 @@ static void wait_wfifo_ready(struct sh_flctl *flctl) return; udelay(1); } - printk(KERN_ERR "wait_wfifo_ready(): Timeout occured \n"); + timeout_error(flctl, __func__); } static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number) @@ -198,7 +203,7 @@ static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number) writel(0, FL4ECCCR(flctl)); } - printk(KERN_ERR "wait_recfifo_ready(): Timeout occured \n"); + timeout_error(flctl, __func__); return 1; /* timeout */ } @@ -214,7 +219,7 @@ static void wait_wecfifo_ready(struct sh_flctl *flctl) return; udelay(1); } - printk(KERN_ERR "wait_wecfifo_ready(): Timeout occured \n"); + timeout_error(flctl, __func__); } static void read_datareg(struct sh_flctl *flctl, int offset) @@ -769,38 +774,36 @@ static int flctl_chip_init_tail(struct mtd_info *mtd) return 0; } -static int __init flctl_probe(struct platform_device *pdev) +static int __devinit flctl_probe(struct platform_device *pdev) { struct resource *res; struct sh_flctl *flctl; struct mtd_info *flctl_mtd; struct nand_chip *nand; struct sh_flctl_platform_data *pdata; - int ret; + int ret = -ENXIO; pdata = pdev->dev.platform_data; if (pdata == NULL) { - printk(KERN_ERR "sh_flctl platform_data not found.\n"); - return -ENODEV; + dev_err(&pdev->dev, "no platform data defined\n"); + return -EINVAL; } flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL); if (!flctl) { - printk(KERN_ERR "Unable to allocate NAND MTD dev structure.\n"); + dev_err(&pdev->dev, "failed to allocate driver data\n"); return -ENOMEM; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { - printk(KERN_ERR "%s: resource not found.\n", __func__); - ret = -ENODEV; + dev_err(&pdev->dev, "failed to get I/O memory\n"); goto err; } - flctl->reg = ioremap(res->start, res->end - res->start + 1); + flctl->reg = ioremap(res->start, resource_size(res)); if (flctl->reg == NULL) { - printk(KERN_ERR "%s: ioremap error.\n", __func__); - ret = -ENOMEM; + dev_err(&pdev->dev, "failed to remap I/O memory\n"); goto err; } @@ -808,6 +811,7 @@ static int __init flctl_probe(struct platform_device *pdev) flctl_mtd = &flctl->mtd; nand = &flctl->chip; flctl_mtd->priv = nand; + flctl->pdev = pdev; flctl->hwecc = pdata->has_hwecc; flctl_register_init(flctl, pdata->flcmncr_val); @@ -846,7 +850,7 @@ err: return ret; } -static int __exit flctl_remove(struct platform_device *pdev) +static int __devexit flctl_remove(struct platform_device *pdev) { struct sh_flctl *flctl = platform_get_drvdata(pdev); -- cgit v1.2.2 From 010ab820582d03bcd3648416b5837107e8a9c5f3 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 27 Jan 2010 09:17:21 +0000 Subject: mtd: sh_flctl SHBUSSEL and SEL_16BIT support This patch extends the sh_flctl driver with support for 16-bit bus configuration using SEL_16BIT and support for multiplexed pins using SHBUSSEL. Signed-off-by: Magnus Damm Acked-by: Yoshihiro Shimoda Signed-off-by: Paul Mundt --- drivers/mtd/nand/sh_flctl.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index ab068a503b29..1842df8bdd93 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -105,6 +105,8 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr) addr = page_addr; /* ERASE1 */ } else if (page_addr != -1) { /* SEQIN, READ0, etc.. */ + if (flctl->chip.options & NAND_BUSWIDTH_16) + column >>= 1; if (flctl->page_size) { addr = column & 0x0FFF; addr |= (page_addr & 0xff) << 16; @@ -280,7 +282,7 @@ static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset) static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val) { struct sh_flctl *flctl = mtd_to_flctl(mtd); - uint32_t flcmncr_val = readl(FLCMNCR(flctl)); + uint32_t flcmncr_val = readl(FLCMNCR(flctl)) & ~SEL_16BIT; uint32_t flcmdcr_val, addr_len_bytes = 0; /* Set SNAND bit if page size is 2048byte */ @@ -302,6 +304,8 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va case NAND_CMD_READOOB: addr_len_bytes = flctl->rw_ADRCNT; flcmdcr_val |= CDSRC_E; + if (flctl->chip.options & NAND_BUSWIDTH_16) + flcmncr_val |= SEL_16BIT; break; case NAND_CMD_SEQIN: /* This case is that cmd is READ0 or READ1 or READ00 */ @@ -310,6 +314,8 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va case NAND_CMD_PAGEPROG: addr_len_bytes = flctl->rw_ADRCNT; flcmdcr_val |= DOCMD2_E | CDSRC_E | SELRW; + if (flctl->chip.options & NAND_BUSWIDTH_16) + flcmncr_val |= SEL_16BIT; break; case NAND_CMD_READID: flcmncr_val &= ~SNAND_E; @@ -528,6 +534,8 @@ static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command, set_addr(mtd, 0, page_addr); flctl->read_bytes = mtd->writesize + mtd->oobsize; + if (flctl->chip.options & NAND_BUSWIDTH_16) + column >>= 1; flctl->index += column; goto read_normal_exit; @@ -691,6 +699,18 @@ static uint8_t flctl_read_byte(struct mtd_info *mtd) return data; } +static uint16_t flctl_read_word(struct mtd_info *mtd) +{ + struct sh_flctl *flctl = mtd_to_flctl(mtd); + int index = flctl->index; + uint16_t data; + uint16_t *buf = (uint16_t *)&flctl->done_buff[index]; + + data = *buf; + flctl->index += 2; + return data; +} + static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { int i; @@ -829,6 +849,11 @@ static int __devinit flctl_probe(struct platform_device *pdev) nand->select_chip = flctl_select_chip; nand->cmdfunc = flctl_cmdfunc; + if (pdata->flcmncr_val & SEL_16BIT) { + nand->options |= NAND_BUSWIDTH_16; + nand->read_word = flctl_read_word; + } + ret = nand_scan_ident(flctl_mtd, 1); if (ret) goto err; -- cgit v1.2.2 From 8a349d4b13c41c00564cd79f6fabdec347084758 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 2 Feb 2010 07:22:13 +0000 Subject: spi/spi_s3c64xx.c: Fix continuation line formats String constants that are continued on subsequent lines with \ are not good. Signed-off-by: Joe Perches Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index 32db69540fa9..97365815a729 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -634,8 +634,8 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd, S3C64XX_SPI_DEACT(sdd); if (status) { - dev_err(&spi->dev, "I/O Error: \ - rx-%d tx-%d res:rx-%c tx-%c len-%d\n", + dev_err(&spi->dev, "I/O Error: " + "rx-%d tx-%d res:rx-%c tx-%c len-%d\n", xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0, (sdd->state & RXBUSY) ? 'f' : 'p', (sdd->state & TXBUSY) ? 'f' : 'p', @@ -1039,11 +1039,10 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) goto err8; } - dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d \ - with %d Slaves attached\n", + dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d " + "with %d Slaves attached\n", pdev->id, master->num_chipselect); - dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\ - \tDMA=[Rx-%d, Tx-%d]\n", + dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n", mem_res->end, mem_res->start, sdd->rx_dmach, sdd->tx_dmach); -- cgit v1.2.2 From e9867c569970d8afb4b882bafbbe81426bd46333 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 2 Feb 2010 17:35:13 +0900 Subject: sh: Provide create_irq_nr() for dynamic IRQ creation by number. This just reworks the existing create_irq_on_node() in to the new create_irq_nr() which is generally exposed. This permits boards that haven't converted over to sparseirq to try and use their existing ranges, rather than having arbitrary vectors assigned to them. Signed-off-by: Paul Mundt --- drivers/sh/intc.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index d5d7f23c19a5..7d286aedaeeb 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c @@ -872,7 +872,7 @@ device_initcall(register_intc_sysdevs); /* * Dynamic IRQ allocation and deallocation */ -static unsigned int create_irq_on_node(unsigned int irq_want, int node) +unsigned int create_irq_nr(unsigned int irq_want, int node) { unsigned int irq = 0, new; unsigned long flags; @@ -881,24 +881,28 @@ static unsigned int create_irq_on_node(unsigned int irq_want, int node) spin_lock_irqsave(&vector_lock, flags); /* - * First try the wanted IRQ, then scan. + * First try the wanted IRQ */ - if (test_and_set_bit(irq_want, intc_irq_map)) { + if (test_and_set_bit(irq_want, intc_irq_map) == 0) { + new = irq_want; + } else { + /* .. then fall back to scanning. */ new = find_first_zero_bit(intc_irq_map, nr_irqs); if (unlikely(new == nr_irqs)) goto out_unlock; - desc = irq_to_desc_alloc_node(new, node); - if (unlikely(!desc)) { - pr_info("can't get irq_desc for %d\n", new); - goto out_unlock; - } - - desc = move_irq_desc(desc, node); __set_bit(new, intc_irq_map); - irq = new; } + desc = irq_to_desc_alloc_node(new, node); + if (unlikely(!desc)) { + pr_info("can't get irq_desc for %d\n", new); + goto out_unlock; + } + + desc = move_irq_desc(desc, node); + irq = new; + out_unlock: spin_unlock_irqrestore(&vector_lock, flags); @@ -913,7 +917,7 @@ int create_irq(void) int nid = cpu_to_node(smp_processor_id()); int irq; - irq = create_irq_on_node(NR_IRQS_LEGACY, nid); + irq = create_irq_nr(NR_IRQS_LEGACY, nid); if (irq == 0) irq = -1; -- cgit v1.2.2 From 7d39e849912f0c3c8c6fc94be7bf7d120b1ee0ba Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Tue, 2 Feb 2010 20:46:34 +0100 Subject: HID: update copyright Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 2 +- drivers/hid/hid-input.c | 2 +- drivers/hid/usbhid/hid-core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 7fe509879fe3..1bbd96d4efe4 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -4,7 +4,7 @@ * Copyright (c) 1999 Andreas Gal * Copyright (c) 2000-2005 Vojtech Pavlik * Copyright (c) 2005 Michael Haboustak for Concept2, Inc - * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2006-2010 Jiri Kosina */ /* diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index dad7aae9c975..8430d626511c 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2000-2001 Vojtech Pavlik - * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2006-2010 Jiri Kosina * * HID to Linux Input mapping */ diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index e72751d6e3e7..eb7e0019891f 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -5,7 +5,7 @@ * Copyright (c) 2000-2005 Vojtech Pavlik * Copyright (c) 2005 Michael Haboustak for Concept2, Inc * Copyright (c) 2007-2008 Oliver Neukum - * Copyright (c) 2006-2009 Jiri Kosina + * Copyright (c) 2006-2010 Jiri Kosina */ /* -- cgit v1.2.2 From 1c3a02c215a5b955b342f29dc1719e1a5771eaf1 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Tue, 2 Feb 2010 18:43:32 +0200 Subject: HID: add NOGET quirk for Prodige Cordless Combo I happen to own a keyboard identified as 05af:3062 which is labeled as "FlatX Coldless Combo" by "Prodige", which exhibits input problems without NOGET quirk. For some reason, lsusb reports this device as "Jing-Mold Enterprise Co., Ltd", which is not mentioned anywhere on the package. A quick search on the intenet shows that there a other people who have this in their lsusb output, but apparently they don't have the problem I am seeing (or they are not such furious typists as myself). Signed-off-by: Alexander Shishkin Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/usbhid/hid-quirks.c | 1 + 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 6c38359385a9..4e5adc3fac4a 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -383,6 +383,9 @@ #define USB_VENDOR_ID_POWERCOM 0x0d9f #define USB_DEVICE_ID_POWERCOM_UPS 0x0002 +#define USB_VENDOR_ID_PRODIGE 0x05af +#define USB_DEVICE_ID_PRODIGE_CORDLESS 0x3062 + #define USB_VENDOR_ID_SAITEK 0x06a3 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 38773dc2821b..fc074c11e0d3 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -45,6 +45,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, -- cgit v1.2.2 From 8127f4e883666c9960cfa89cffd36313748f8bab Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Tue, 2 Feb 2010 18:09:06 -0200 Subject: HID: use multi input quirk for eTurboTouch touchscreen This device generates ABS_Z and ABS_RX events, while it should be generating ABS_X and ABS_Y instead. Using the MULTI_INPUT quirk solves this issue. Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Daniel Oliveira Nascimento Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/usbhid/hid-quirks.c | 1 + 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 4e5adc3fac4a..bb5f4fa479ad 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -169,6 +169,9 @@ #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 +#define USB_VENDOR_ID_ETURBOTOUCH 0x22b9 +#define USB_DEVICE_ID_ETURBOTOUCH 0x0006 + #define USB_VENDOR_ID_EZKEY 0x0518 #define USB_DEVICE_ID_BTC_8193 0x0002 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index fc074c11e0d3..88a1c693fdcc 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -43,6 +43,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL }, + { USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET }, -- cgit v1.2.2 From dc942cee2fcb734d6f3ef7966040e4e034b67d5b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 22 Dec 2009 21:22:59 +0000 Subject: powerpc/viodasd: Remove VIOD_KERN_ macros for printks Use #define pr_fmt(fmt) "viod: " fmt Remove #define VIOD_KERN_WARNING and VIOD_KERN_INFO Convert printk(VIOD_KERN_ to pr_ Coalesce long format strings Signed-off-by: Joe Perches Acked-by: Stephen Rothwell drivers/block/viodasd.c | 86 +++++++++++++++++++--------------------------- 1 files changed, 36 insertions(+), 50 deletions(-) Signed-off-by: Benjamin Herrenschmidt --- drivers/block/viodasd.c | 86 +++++++++++++++++++++---------------------------- 1 file changed, 36 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index a8c8b56b275e..1b3def1e8591 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -28,6 +28,9 @@ * All disk operations are performed by sending messages back and forth to * the OS/400 partition. */ + +#define pr_fmt(fmt) "viod: " fmt + #include #include #include @@ -63,9 +66,6 @@ MODULE_LICENSE("GPL"); #define VIOD_VERS "1.64" -#define VIOD_KERN_WARNING KERN_WARNING "viod: " -#define VIOD_KERN_INFO KERN_INFO "viod: " - enum { PARTITION_SHIFT = 3, MAX_DISKNO = HVMAXARCHITECTEDVIRTUALDISKS, @@ -156,7 +156,7 @@ static int viodasd_open(struct block_device *bdev, fmode_t mode) ((u64)DEVICE_NO(d) << 48) | ((u64)flags << 32), 0, 0, 0); if (hvrc != 0) { - printk(VIOD_KERN_WARNING "HV open failed %d\n", (int)hvrc); + pr_warning("HV open failed %d\n", (int)hvrc); return -EIO; } @@ -167,9 +167,8 @@ static int viodasd_open(struct block_device *bdev, fmode_t mode) const struct vio_error_entry *err = vio_lookup_rc(viodasd_err_table, we.sub_result); - printk(VIOD_KERN_WARNING - "bad rc opening disk: %d:0x%04x (%s)\n", - (int)we.rc, we.sub_result, err->msg); + pr_warning("bad rc opening disk: %d:0x%04x (%s)\n", + (int)we.rc, we.sub_result, err->msg); return -EIO; } @@ -195,8 +194,7 @@ static int viodasd_release(struct gendisk *disk, fmode_t mode) ((u64)DEVICE_NO(d) << 48) /* | ((u64)flags << 32) */, 0, 0, 0); if (hvrc != 0) - printk(VIOD_KERN_WARNING "HV close call failed %d\n", - (int)hvrc); + pr_warning("HV close call failed %d\n", (int)hvrc); return 0; } @@ -288,8 +286,7 @@ static int send_request(struct request *req) bevent = (struct vioblocklpevent *) vio_get_event_buffer(viomajorsubtype_blockio); if (bevent == NULL) { - printk(VIOD_KERN_WARNING - "error allocating disk event buffer\n"); + pr_warning("error allocating disk event buffer\n"); goto error_ret; } @@ -333,9 +330,8 @@ static int send_request(struct request *req) } if (hvrc != HvLpEvent_Rc_Good) { - printk(VIOD_KERN_WARNING - "error sending disk event to OS/400 (rc %d)\n", - (int)hvrc); + pr_warning("error sending disk event to OS/400 (rc %d)\n", + (int)hvrc); goto error_ret; } spin_unlock_irqrestore(&viodasd_spinlock, flags); @@ -402,7 +398,7 @@ retry: ((u64)dev_no << 48) | ((u64)flags<< 32), 0, 0, 0); if (hvrc != 0) { - printk(VIOD_KERN_WARNING "bad rc on HV open %d\n", (int)hvrc); + pr_warning("bad rc on HV open %d\n", (int)hvrc); return 0; } @@ -416,9 +412,8 @@ retry: goto retry; } if (we.max_disk > (MAX_DISKNO - 1)) { - printk_once(VIOD_KERN_INFO - "Only examining the first %d of %d disks connected\n", - MAX_DISKNO, we.max_disk + 1); + printk_once(KERN_INFO pr_fmt("Only examining the first %d of %d disks connected\n"), + MAX_DISKNO, we.max_disk + 1); } /* Send the close event to OS/400. We DON'T expect a response */ @@ -432,17 +427,15 @@ retry: ((u64)dev_no << 48) | ((u64)flags << 32), 0, 0, 0); if (hvrc != 0) { - printk(VIOD_KERN_WARNING - "bad rc sending event to OS/400 %d\n", (int)hvrc); + pr_warning("bad rc sending event to OS/400 %d\n", (int)hvrc); return 0; } if (d->dev == NULL) { /* this is when we reprobe for new disks */ if (vio_create_viodasd(dev_no) == NULL) { - printk(VIOD_KERN_WARNING - "cannot allocate virtual device for disk %d\n", - dev_no); + pr_warning("cannot allocate virtual device for disk %d\n", + dev_no); return 0; } /* @@ -457,15 +450,13 @@ retry: spin_lock_init(&d->q_lock); q = blk_init_queue(do_viodasd_request, &d->q_lock); if (q == NULL) { - printk(VIOD_KERN_WARNING "cannot allocate queue for disk %d\n", - dev_no); + pr_warning("cannot allocate queue for disk %d\n", dev_no); return 0; } g = alloc_disk(1 << PARTITION_SHIFT); if (g == NULL) { - printk(VIOD_KERN_WARNING - "cannot allocate disk structure for disk %d\n", - dev_no); + pr_warning("cannot allocate disk structure for disk %d\n", + dev_no); blk_cleanup_queue(q); return 0; } @@ -489,13 +480,12 @@ retry: g->driverfs_dev = d->dev; set_capacity(g, d->size >> 9); - printk(VIOD_KERN_INFO "disk %d: %lu sectors (%lu MB) " - "CHS=%d/%d/%d sector size %d%s\n", - dev_no, (unsigned long)(d->size >> 9), - (unsigned long)(d->size >> 20), - (int)d->cylinders, (int)d->tracks, - (int)d->sectors, (int)d->bytes_per_sector, - d->read_only ? " (RO)" : ""); + pr_info("disk %d: %lu sectors (%lu MB) CHS=%d/%d/%d sector size %d%s\n", + dev_no, (unsigned long)(d->size >> 9), + (unsigned long)(d->size >> 20), + (int)d->cylinders, (int)d->tracks, + (int)d->sectors, (int)d->bytes_per_sector, + d->read_only ? " (RO)" : ""); /* register us in the global list */ add_disk(g); @@ -580,8 +570,8 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent) if (error) { const struct vio_error_entry *err; err = vio_lookup_rc(viodasd_err_table, bevent->sub_result); - printk(VIOD_KERN_WARNING "read/write error %d:0x%04x (%s)\n", - event->xRc, bevent->sub_result, err->msg); + pr_warning("read/write error %d:0x%04x (%s)\n", + event->xRc, bevent->sub_result, err->msg); num_sect = blk_rq_sectors(req); } qlock = req->q->queue_lock; @@ -606,8 +596,7 @@ static void handle_block_event(struct HvLpEvent *event) return; /* First, we should NEVER get an int here...only acks */ if (hvlpevent_is_int(event)) { - printk(VIOD_KERN_WARNING - "Yikes! got an int in viodasd event handler!\n"); + pr_warning("Yikes! got an int in viodasd event handler!\n"); if (hvlpevent_need_ack(event)) { event->xRc = HvLpEvent_Rc_InvalidSubtype; HvCallEvent_ackLpEvent(event); @@ -650,7 +639,7 @@ static void handle_block_event(struct HvLpEvent *event) break; default: - printk(VIOD_KERN_WARNING "invalid subtype!"); + pr_warning("invalid subtype!"); if (hvlpevent_need_ack(event)) { event->xRc = HvLpEvent_Rc_InvalidSubtype; HvCallEvent_ackLpEvent(event); @@ -739,29 +728,26 @@ static int __init viodasd_init(void) vio_set_hostlp(); if (viopath_hostLp == HvLpIndexInvalid) { - printk(VIOD_KERN_WARNING "invalid hosting partition\n"); + pr_warning("invalid hosting partition\n"); rc = -EIO; goto early_fail; } - printk(VIOD_KERN_INFO "vers " VIOD_VERS ", hosting partition %d\n", - viopath_hostLp); + pr_info("vers " VIOD_VERS ", hosting partition %d\n", viopath_hostLp); /* register the block device */ rc = register_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME); if (rc) { - printk(VIOD_KERN_WARNING - "Unable to get major number %d for %s\n", - VIODASD_MAJOR, VIOD_GENHD_NAME); + pr_warning("Unable to get major number %d for %s\n", + VIODASD_MAJOR, VIOD_GENHD_NAME); goto early_fail; } /* Actually open the path to the hosting partition */ rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2); if (rc) { - printk(VIOD_KERN_WARNING - "error opening path to host partition %d\n", - viopath_hostLp); + pr_warning("error opening path to host partition %d\n", + viopath_hostLp); goto unregister_blk; } @@ -770,7 +756,7 @@ static int __init viodasd_init(void) rc = vio_register_driver(&viodasd_driver); if (rc) { - printk(VIOD_KERN_WARNING "vio_register_driver failed\n"); + pr_warning("vio_register_driver failed\n"); goto unset_handler; } -- cgit v1.2.2 From b51130685817d8c1b56386f9957405b5be2cdfe0 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 18 Jan 2010 03:44:57 +0000 Subject: hvc_console: Make the ops pointer const. This is nicer for modern R/O protection. And noone needs it non-const, so constify the callers as well. Signed-off-by: Rusty Russell Signed-off-by: Amit Shah To: Christian Borntraeger Cc: linuxppc-dev@ozlabs.org Signed-off-by: Benjamin Herrenschmidt --- drivers/char/hvc_beat.c | 2 +- drivers/char/hvc_console.c | 7 ++++--- drivers/char/hvc_console.h | 7 ++++--- drivers/char/hvc_iseries.c | 2 +- drivers/char/hvc_iucv.c | 2 +- drivers/char/hvc_rtas.c | 2 +- drivers/char/hvc_udbg.c | 2 +- drivers/char/hvc_vio.c | 2 +- drivers/char/hvc_xen.c | 2 +- 9 files changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvc_beat.c b/drivers/char/hvc_beat.c index 0afc8b82212e..6913fc33270c 100644 --- a/drivers/char/hvc_beat.c +++ b/drivers/char/hvc_beat.c @@ -84,7 +84,7 @@ static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt) return cnt; } -static struct hv_ops hvc_beat_get_put_ops = { +static const struct hv_ops hvc_beat_get_put_ops = { .get_chars = hvc_beat_get_chars, .put_chars = hvc_beat_put_chars, }; diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 416d3423150d..d8dac5820f0e 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -125,7 +125,7 @@ static struct hvc_struct *hvc_get_by_index(int index) * console interfaces but can still be used as a tty device. This has to be * static because kmalloc will not work during early console init. */ -static struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES]; +static const struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES]; static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] = {[0 ... MAX_NR_HVC_CONSOLES - 1] = -1}; @@ -247,7 +247,7 @@ static void destroy_hvc_struct(struct kref *kref) * vty adapters do NOT get an hvc_instantiate() callback since they * appear after early console init. */ -int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops) +int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops) { struct hvc_struct *hp; @@ -749,7 +749,8 @@ static const struct tty_operations hvc_ops = { }; struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data, - struct hv_ops *ops, int outbuf_size) + const struct hv_ops *ops, + int outbuf_size) { struct hvc_struct *hp; int i; diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h index 10950ca706d8..52ddf4d3716c 100644 --- a/drivers/char/hvc_console.h +++ b/drivers/char/hvc_console.h @@ -55,7 +55,7 @@ struct hvc_struct { int outbuf_size; int n_outbuf; uint32_t vtermno; - struct hv_ops *ops; + const struct hv_ops *ops; int irq_requested; int data; struct winsize ws; @@ -76,11 +76,12 @@ struct hv_ops { }; /* Register a vterm and a slot index for use as a console (console_init) */ -extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops); +extern int hvc_instantiate(uint32_t vtermno, int index, + const struct hv_ops *ops); /* register a vterm for hvc tty operation (module_init or hotplug add) */ extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int data, - struct hv_ops *ops, int outbuf_size); + const struct hv_ops *ops, int outbuf_size); /* remove a vterm from hvc tty operation (module_exit or hotplug remove) */ extern int hvc_remove(struct hvc_struct *hp); diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c index 936d05bf37fa..fd0242676a2a 100644 --- a/drivers/char/hvc_iseries.c +++ b/drivers/char/hvc_iseries.c @@ -197,7 +197,7 @@ done: return sent; } -static struct hv_ops hvc_get_put_ops = { +static const struct hv_ops hvc_get_put_ops = { .get_chars = get_chars, .put_chars = put_chars, .notifier_add = notifier_add_irq, diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c index fe62bd0e17b7..21681a81cc35 100644 --- a/drivers/char/hvc_iucv.c +++ b/drivers/char/hvc_iucv.c @@ -922,7 +922,7 @@ static int hvc_iucv_pm_restore_thaw(struct device *dev) /* HVC operations */ -static struct hv_ops hvc_iucv_ops = { +static const struct hv_ops hvc_iucv_ops = { .get_chars = hvc_iucv_get_chars, .put_chars = hvc_iucv_put_chars, .notifier_add = hvc_iucv_notifier_add, diff --git a/drivers/char/hvc_rtas.c b/drivers/char/hvc_rtas.c index 88590d040046..61c4a61558d9 100644 --- a/drivers/char/hvc_rtas.c +++ b/drivers/char/hvc_rtas.c @@ -71,7 +71,7 @@ static int hvc_rtas_read_console(uint32_t vtermno, char *buf, int count) return i; } -static struct hv_ops hvc_rtas_get_put_ops = { +static const struct hv_ops hvc_rtas_get_put_ops = { .get_chars = hvc_rtas_read_console, .put_chars = hvc_rtas_write_console, }; diff --git a/drivers/char/hvc_udbg.c b/drivers/char/hvc_udbg.c index bd63ba878a56..b0957e61a7be 100644 --- a/drivers/char/hvc_udbg.c +++ b/drivers/char/hvc_udbg.c @@ -58,7 +58,7 @@ static int hvc_udbg_get(uint32_t vtermno, char *buf, int count) return i; } -static struct hv_ops hvc_udbg_ops = { +static const struct hv_ops hvc_udbg_ops = { .get_chars = hvc_udbg_get, .put_chars = hvc_udbg_put, }; diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c index 10be343d6ae7..27370e99c66f 100644 --- a/drivers/char/hvc_vio.c +++ b/drivers/char/hvc_vio.c @@ -77,7 +77,7 @@ static int filtered_get_chars(uint32_t vtermno, char *buf, int count) return got; } -static struct hv_ops hvc_get_put_ops = { +static const struct hv_ops hvc_get_put_ops = { .get_chars = filtered_get_chars, .put_chars = hvc_put_chars, .notifier_add = notifier_add_irq, diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c index b1a71638c772..60446f82a3fc 100644 --- a/drivers/char/hvc_xen.c +++ b/drivers/char/hvc_xen.c @@ -122,7 +122,7 @@ static int read_console(uint32_t vtermno, char *buf, int len) return recv; } -static struct hv_ops hvc_ops = { +static const struct hv_ops hvc_ops = { .get_chars = read_console, .put_chars = write_console, .notifier_add = notifier_add_irq, -- cgit v1.2.2 From 119ea10947cc1402abbf9d6200815b0606536906 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 18 Jan 2010 03:44:58 +0000 Subject: hvc_console: Remove __devinit annotation from hvc_alloc Virtio consoles can be hotplugged, so hvc_alloc gets called from multiple sites: from the initial probe() routine as well as later on from workqueue handlers which aren't __devinit code. So, drop the __devinit annotation for hvc_alloc. Signed-off-by: Amit Shah Cc: linuxppc-dev@ozlabs.org Signed-off-by: Benjamin Herrenschmidt --- drivers/char/hvc_console.c | 6 +++--- drivers/char/hvc_console.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index d8dac5820f0e..4c3b59be286a 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -748,9 +748,9 @@ static const struct tty_operations hvc_ops = { .chars_in_buffer = hvc_chars_in_buffer, }; -struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data, - const struct hv_ops *ops, - int outbuf_size) +struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, + const struct hv_ops *ops, + int outbuf_size) { struct hvc_struct *hp; int i; diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h index 52ddf4d3716c..54381eba4e4a 100644 --- a/drivers/char/hvc_console.h +++ b/drivers/char/hvc_console.h @@ -80,8 +80,8 @@ extern int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops); /* register a vterm for hvc tty operation (module_init or hotplug add) */ -extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int data, - const struct hv_ops *ops, int outbuf_size); +extern struct hvc_struct * hvc_alloc(uint32_t vtermno, int data, + const struct hv_ops *ops, int outbuf_size); /* remove a vterm from hvc tty operation (module_exit or hotplug remove) */ extern int hvc_remove(struct hvc_struct *hp); -- cgit v1.2.2 From 33a470f6d5e1879c26f16f6b34dc09f82d44f6e9 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 31 Jan 2010 04:00:30 +0000 Subject: macintosh/therm_adt746x: Fix sysfs attributes lifetime Looking at drivers/macintosh/therm_adt746x.c, the sysfs files are created in thermostat_init() and removed in thermostat_exit(), which are the driver's init and exit functions. These files are backed-up by a per-device structure, so it looks like the wrong thing to do: the sysfs files have a lifetime longer than the data structure that is backing it up. I think that sysfs files creation should be moved to the end of probe_thermostat() and sysfs files removal should be moved to the beginning of remove_thermostat(). Signed-off-by: Jean Delvare Tested-by: Christian Kujau Cc: Benjamin Herrenschmidt Cc: Colin Leroy Cc: stable@kernel.org Signed-off-by: Benjamin Herrenschmidt --- drivers/macintosh/therm_adt746x.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 5ff47ba7f2d0..58809b0510f9 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -90,6 +90,8 @@ static struct task_struct *thread_therm = NULL; static void write_both_fan_speed(struct thermostat *th, int speed); static void write_fan_speed(struct thermostat *th, int speed, int fan); +static void thermostat_create_files(void); +static void thermostat_remove_files(void); static int write_reg(struct thermostat* th, int reg, u8 data) @@ -161,6 +163,8 @@ remove_thermostat(struct i2c_client *client) struct thermostat *th = i2c_get_clientdata(client); int i; + thermostat_remove_files(); + if (thread_therm != NULL) { kthread_stop(thread_therm); } @@ -449,6 +453,8 @@ static int probe_thermostat(struct i2c_client *client, return -ENOMEM; } + thermostat_create_files(); + return 0; } @@ -566,7 +572,6 @@ thermostat_init(void) struct device_node* np; const u32 *prop; int i = 0, offset = 0; - int err; np = of_find_node_by_name(NULL, "fan"); if (!np) @@ -633,6 +638,17 @@ thermostat_init(void) return -ENODEV; } +#ifndef CONFIG_I2C_POWERMAC + request_module("i2c-powermac"); +#endif + + return i2c_add_driver(&thermostat_driver); +} + +static void thermostat_create_files(void) +{ + int err; + err = device_create_file(&of_dev->dev, &dev_attr_sensor1_temperature); err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_temperature); err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_limit); @@ -647,16 +663,9 @@ thermostat_init(void) if (err) printk(KERN_WARNING "Failed to create tempertaure attribute file(s).\n"); - -#ifndef CONFIG_I2C_POWERMAC - request_module("i2c-powermac"); -#endif - - return i2c_add_driver(&thermostat_driver); } -static void __exit -thermostat_exit(void) +static void thermostat_remove_files(void) { if (of_dev) { device_remove_file(&of_dev->dev, &dev_attr_sensor1_temperature); @@ -673,9 +682,14 @@ thermostat_exit(void) device_remove_file(&of_dev->dev, &dev_attr_sensor2_fan_speed); - of_device_unregister(of_dev); } +} + +static void __exit +thermostat_exit(void) +{ i2c_del_driver(&thermostat_driver); + of_device_unregister(of_dev); } module_init(thermostat_init); -- cgit v1.2.2 From 98ceb75c7c14eada76b0aa9f03a635a735cee3cb Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 31 Jan 2010 04:03:23 +0000 Subject: macintosh/hwmon/ams: Fix device removal sequence Some code that is in ams_exit() (the module exit code) should instead be called when the device (not module) is removed. It probably doesn't make much of a difference in the PMU case, but in the I2C case it does matter. I make no guarantee that my fix isn't racy, I'm not familiar enough with the ams driver code to tell for sure. Signed-off-by: Jean Delvare Tested-by: Christian Kujau Cc: Benjamin Herrenschmidt Cc: Stelian Pop Cc: Michael Hanselmann Cc: stable@kernel.org Signed-off-by: Benjamin Herrenschmidt --- drivers/hwmon/ams/ams-core.c | 11 +++++++---- drivers/hwmon/ams/ams-i2c.c | 2 ++ drivers/hwmon/ams/ams-pmu.c | 2 ++ drivers/hwmon/ams/ams.h | 1 + 4 files changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/ams/ams-core.c b/drivers/hwmon/ams/ams-core.c index 6c9ace1b76f6..2ad62c339cd2 100644 --- a/drivers/hwmon/ams/ams-core.c +++ b/drivers/hwmon/ams/ams-core.c @@ -213,7 +213,7 @@ int __init ams_init(void) return -ENODEV; } -void ams_exit(void) +void ams_sensor_detach(void) { /* Remove input device */ ams_input_exit(); @@ -221,9 +221,6 @@ void ams_exit(void) /* Remove attributes */ device_remove_file(&ams_info.of_dev->dev, &dev_attr_current); - /* Shut down implementation */ - ams_info.exit(); - /* Flush interrupt worker * * We do this after ams_info.exit(), because an interrupt might @@ -239,6 +236,12 @@ void ams_exit(void) pmf_unregister_irq_client(&ams_freefall_client); } +static void __exit ams_exit(void) +{ + /* Shut down implementation */ + ams_info.exit(); +} + MODULE_AUTHOR("Stelian Pop, Michael Hanselmann"); MODULE_DESCRIPTION("Apple Motion Sensor driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/ams/ams-i2c.c b/drivers/hwmon/ams/ams-i2c.c index 2cbf8a6506c7..abeecd27b484 100644 --- a/drivers/hwmon/ams/ams-i2c.c +++ b/drivers/hwmon/ams/ams-i2c.c @@ -238,6 +238,8 @@ static int ams_i2c_probe(struct i2c_client *client, static int ams_i2c_remove(struct i2c_client *client) { if (ams_info.has_device) { + ams_sensor_detach(); + /* Disable interrupts */ ams_i2c_set_irq(AMS_IRQ_ALL, 0); diff --git a/drivers/hwmon/ams/ams-pmu.c b/drivers/hwmon/ams/ams-pmu.c index fb18b3d3162b..4f61b3ee1b08 100644 --- a/drivers/hwmon/ams/ams-pmu.c +++ b/drivers/hwmon/ams/ams-pmu.c @@ -133,6 +133,8 @@ static void ams_pmu_get_xyz(s8 *x, s8 *y, s8 *z) static void ams_pmu_exit(void) { + ams_sensor_detach(); + /* Disable interrupts */ ams_pmu_set_irq(AMS_IRQ_ALL, 0); diff --git a/drivers/hwmon/ams/ams.h b/drivers/hwmon/ams/ams.h index 5ed387b0bd9a..b28d7e27a031 100644 --- a/drivers/hwmon/ams/ams.h +++ b/drivers/hwmon/ams/ams.h @@ -61,6 +61,7 @@ extern struct ams ams_info; extern void ams_sensors(s8 *x, s8 *y, s8 *z); extern int ams_sensor_attach(void); +extern void ams_sensor_detach(void); extern int ams_pmu_init(struct device_node *np); extern int ams_i2c_init(struct device_node *np); -- cgit v1.2.2 From f54405db66fbec11679241daefd16fd8291a5762 Mon Sep 17 00:00:00 2001 From: Alex Neblett Date: Tue, 2 Feb 2010 21:16:03 -0800 Subject: HID: add support for Pixart Imaging Optical Touch Screen Added support for the Pixart Imaging Inc. Optical Touch Screen found in the MSI AE2220 and other new all in one computers to the Quanta Optical Touch dual-touch panel driver found in the latest git clone git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git. Signed-off-by: Alex Neblett Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-quanta.c | 2 ++ 3 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 2dd9b28e39c4..282f4a1e7214 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1343,6 +1343,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 39ff98a5bd61..b29d9da799f4 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -400,6 +400,7 @@ #define USB_VENDOR_ID_QUANTA 0x0408 #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH 0x3000 +#define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN 0x3001 #define USB_VENDOR_ID_SAMSUNG 0x0419 #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001 diff --git a/drivers/hid/hid-quanta.c b/drivers/hid/hid-quanta.c index 244d61c18a47..9ac49287b943 100644 --- a/drivers/hid/hid-quanta.c +++ b/drivers/hid/hid-quanta.c @@ -224,6 +224,8 @@ static void quanta_remove(struct hid_device *hdev) static const struct hid_device_id quanta_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, + USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, { } }; MODULE_DEVICE_TABLE(hid, quanta_devices); -- cgit v1.2.2 From d4bfa033ed84e0ae446eff445d107ffd5ee78df3 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 29 Jan 2010 15:03:36 +0100 Subject: HID: make raw reports possible for both feature and output reports In commit 2da31939a42 ("Bluetooth: Implement raw output support for HIDP layer"), support for Bluetooth hid_output_raw_report was added, but it pushes the data to the intr socket instead of the ctrl one. This has been fixed by 6bf8268f9a91f1 ("Bluetooth: Use the control channel for raw HID reports") Still, it is necessary to distinguish whether the report in question should be either FEATURE or OUTPUT. For this, we have to extend the generic HID API, so that hid_output_raw_report() callback provides means to specify this value so that it can be passed down to lower level hardware drivers (currently Bluetooth and USB). Based on original patch by Bastien Nocera Acked-by: Marcel Holtmann Signed-off-by: Jiri Kosina --- drivers/hid/hidraw.c | 2 +- drivers/hid/usbhid/hid-core.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index cdd136942bca..d04476700b7b 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -134,7 +134,7 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t goto out; } - ret = dev->hid_output_raw_report(dev, buf, count); + ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT); out: kfree(buf); return ret; diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index e2997a8d5e1b..caa16c057ce2 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -774,7 +774,8 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) return 0; } -static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count) +static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count, + unsigned char report_type) { struct usbhid_device *usbhid = hid->driver_data; struct usb_device *dev = hid_to_usb_dev(hid); @@ -785,7 +786,7 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), HID_REQ_SET_REPORT, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - ((HID_OUTPUT_REPORT + 1) << 8) | *buf, + ((report_type + 1) << 8) | *buf, interface->desc.bInterfaceNumber, buf + 1, count - 1, USB_CTRL_SET_TIMEOUT); -- cgit v1.2.2 From 46a709b900bfcf43244cd19cf3245c77484ec733 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Wed, 20 Jan 2010 12:00:53 +0000 Subject: HID: Implement Wacom quirk in the kernel The hid-wacom driver required user-space to poke at the tablet to make it send data about the cursor location. This patch makes it do the same thing but in the kernel. Signed-off-by: Bastien Nocera Acked-by: Marcel Holtmann Signed-off-by: Jiri Kosina --- drivers/hid/hid-wacom.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index 12dcda529201..b8778db720bc 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c @@ -156,7 +156,9 @@ static int wacom_probe(struct hid_device *hdev, struct hid_input *hidinput; struct input_dev *input; struct wacom_data *wdata; + char rep_data[2]; int ret; + int limit; wdata = kzalloc(sizeof(*wdata), GFP_KERNEL); if (wdata == NULL) { @@ -166,6 +168,7 @@ static int wacom_probe(struct hid_device *hdev, hid_set_drvdata(hdev, wdata); + /* Parse the HID report now */ ret = hid_parse(hdev); if (ret) { dev_err(&hdev->dev, "parse failed\n"); @@ -178,6 +181,30 @@ static int wacom_probe(struct hid_device *hdev, goto err_free; } + /* Set Wacom mode2 */ + rep_data[0] = 0x03; rep_data[1] = 0x00; + limit = 3; + do { + ret = hdev->hid_output_raw_report(hdev, rep_data, 2, + HID_FEATURE_REPORT); + } while (ret < 0 && limit-- > 0); + if (ret < 0) { + dev_err(&hdev->dev, "failed to poke device #1, %d\n", ret); + goto err_free; + } + + /* 0x06 - high reporting speed, 0x05 - low speed */ + rep_data[0] = 0x06; rep_data[1] = 0x00; + limit = 3; + do { + ret = hdev->hid_output_raw_report(hdev, rep_data, 2, + HID_FEATURE_REPORT); + } while (ret < 0 && limit-- > 0); + if (ret < 0) { + dev_err(&hdev->dev, "failed to poke device #2, %d\n", ret); + goto err_free; + } + hidinput = list_entry(hdev->inputs.next, struct hid_input, list); input = hidinput->input; -- cgit v1.2.2 From f9ce7c283c16538955d5d094101889792bcde109 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Wed, 20 Jan 2010 12:01:53 +0000 Subject: HID: Enable Sixaxis controller over Bluetooth Now that hid_output_raw_report works, port the PS3 Sixaxis Bluetooth quirk from user-space, into kernel-space. Signed-off-by: Bastien Nocera Acked-by: Marcel Holtmann Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-sony.c | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index eabe5f87c6c1..f7f80e1f1eef 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1340,6 +1340,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) }, diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 4e8450228a24..6ced140b1411 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -48,7 +48,7 @@ static void sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, * to "operational". Without this, the ps3 controller will not report any * events. */ -static int sony_set_operational(struct hid_device *hdev) +static int sony_set_operational_usb(struct hid_device *hdev) { struct usb_interface *intf = to_usb_interface(hdev->dev.parent); struct usb_device *dev = interface_to_usbdev(intf); @@ -73,6 +73,12 @@ static int sony_set_operational(struct hid_device *hdev) return ret; } +static int sony_set_operational_bt(struct hid_device *hdev) +{ + unsigned char buf[] = { 0x53, 0xf4, 0x42, 0x03, 0x00, 0x00 }; + return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); +} + static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret; @@ -101,7 +107,17 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err_free; } - ret = sony_set_operational(hdev); + switch (hdev->bus) { + case BUS_USB: + ret = sony_set_operational_usb(hdev); + break; + case BUS_BLUETOOTH: + ret = sony_set_operational_bt(hdev); + break; + default: + ret = 0; + } + if (ret < 0) goto err_stop; @@ -121,6 +137,7 @@ static void sony_remove(struct hid_device *hdev) static const struct hid_device_id sony_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE), .driver_data = VAIO_RDESC_CONSTANT }, { } -- cgit v1.2.2 From 342f31e84eec9002b75f6fcdec6bd932ac77a390 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 3 Feb 2010 15:52:31 +0100 Subject: HID: make Wacom modesetting failures non-fatal With Wacom tablet mode-setting moved from userspace into kernel, we don't have to consider failures of device queries through the _raw callback as hard failure, as the driver can safely continue anyway. This is consistent with the current USB driver in wacom_sys.c Reported-by: Ping Cheng Signed-off-by: Jiri Kosina --- drivers/hid/hid-wacom.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index b8778db720bc..8d3b46f5d149 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c @@ -181,6 +181,11 @@ static int wacom_probe(struct hid_device *hdev, goto err_free; } + /* + * Note that if the raw queries fail, it's not a hard failure and it + * is safe to continue + */ + /* Set Wacom mode2 */ rep_data[0] = 0x03; rep_data[1] = 0x00; limit = 3; @@ -188,10 +193,8 @@ static int wacom_probe(struct hid_device *hdev, ret = hdev->hid_output_raw_report(hdev, rep_data, 2, HID_FEATURE_REPORT); } while (ret < 0 && limit-- > 0); - if (ret < 0) { - dev_err(&hdev->dev, "failed to poke device #1, %d\n", ret); - goto err_free; - } + if (ret < 0) + dev_warn(&hdev->dev, "failed to poke device #1, %d\n", ret); /* 0x06 - high reporting speed, 0x05 - low speed */ rep_data[0] = 0x06; rep_data[1] = 0x00; @@ -200,10 +203,8 @@ static int wacom_probe(struct hid_device *hdev, ret = hdev->hid_output_raw_report(hdev, rep_data, 2, HID_FEATURE_REPORT); } while (ret < 0 && limit-- > 0); - if (ret < 0) { - dev_err(&hdev->dev, "failed to poke device #2, %d\n", ret); - goto err_free; - } + if (ret < 0) + dev_warn(&hdev->dev, "failed to poke device #2, %d\n", ret); hidinput = list_entry(hdev->inputs.next, struct hid_input, list); input = hidinput->input; -- cgit v1.2.2 From 2dbf209d7a7ab94266b936bd2da6a4026c279992 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 3 Feb 2010 16:11:12 +0100 Subject: HID: make full-fledged hid-bus drivers properly selectable For historical reasons, we don't have most of the in-tree drivers residing on hid-bus properly selectable in kernel configuration unless CONFIG_EMBEDDED is set. This has been introduced on Linus' request from 14 Oct === As to the Kconfig options - do they really add so much space that you need to ask for the quirks? You didn't use to. Can you make the questions depend on EMBEDDED, or at least on the HID_COMPAT thing or whatever? === This still makes perfect sense for small and tiny drivers, which just fix report descriptors, fix up HID->input mappings that slightly violates HUT standard, send one extra packet to the device that is needed before it becomes functional, etc. Since then, we have been gathering more and more HID-bus drivers, which are full-fledged drivers. For these, the size argument becomes more valid. Plus the devices are much more special than "just violates HID specification in this one or two tiny unimportant points". Therefore I am marking such drivers as properly selectable no matter the setting of CONFIG_EMBEDDED, while keeping all the small and tiny ones compiled by default. Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 139668d6382a..617ed7db67d1 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -212,9 +212,8 @@ config HID_MONTEREY Support for Monterey Genius KB29E. config HID_NTRIG - tristate "NTrig" if EMBEDDED + tristate "NTrig" depends on USB_HID - default !EMBEDDED ---help--- Support for N-Trig touch screen. @@ -338,9 +337,8 @@ config THRUSTMASTER_FF Rumble Force or Force Feedback Wheel. config HID_WACOM - tristate "Wacom Bluetooth devices support" if EMBEDDED + tristate "Wacom Bluetooth devices support" depends on BT_HIDP - default !EMBEDDED ---help--- Support for Wacom Graphire Bluetooth tablet. -- cgit v1.2.2 From e054f1647162d7098a9ff619405a72bd7c417213 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Thu, 4 Feb 2010 11:39:13 +1100 Subject: crypto: geode-aes - Fix cip/blk confusion a crypto_cipher cip member was set where a crypto_cipher blk members should have been. Signed-off-by: Roel Kluin Signed-off-by: Herbert Xu --- drivers/crypto/geode-aes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c index 03e71b1a5128..c7a5a43ba691 100644 --- a/drivers/crypto/geode-aes.c +++ b/drivers/crypto/geode-aes.c @@ -141,7 +141,7 @@ static int geode_setkey_cip(struct crypto_tfm *tfm, const u8 *key, ret = crypto_cipher_setkey(op->fallback.cip, key, len); if (ret) { tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; - tfm->crt_flags |= (op->fallback.blk->base.crt_flags & CRYPTO_TFM_RES_MASK); + tfm->crt_flags |= (op->fallback.cip->base.crt_flags & CRYPTO_TFM_RES_MASK); } return ret; } -- cgit v1.2.2 From c2c3489c5b0fdb8fbf0f5e9424905c2994ab5660 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Thu, 4 Feb 2010 13:36:24 -0200 Subject: HID: use multi input quirk for TouchPack touchscreen This device generates ABS_Z and ABS_RX events, while it should be generating ABS_X and ABS_Y instead. Using the MULTI_INPUT quirk solves this issue. Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Daniel Oliveira Nascimento [jkosina@suse.cz: fixed blacklist ordering while resolving conflict] [jkosina@suse.cz: fixed typo to make it compile] Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/usbhid/hid-quirks.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b29d9da799f4..282bfe8d95e8 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -424,6 +424,9 @@ #define USB_VENDOR_ID_THRUSTMASTER 0x044f +#define USB_VENDOR_ID_TOUCHPACK 0x1bfd +#define USB_DEVICE_ID_TOUCHPACK_RTS 0x1688 + #define USB_VENDOR_ID_TOPMAX 0x0663 #define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 88a1c693fdcc..7844280897d1 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -46,7 +46,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, @@ -59,6 +59,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK, HID_QUIRK_NOGET }, { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT }, -- cgit v1.2.2 From 95a8b6efc5d07103583f706c8a5889437d537939 Mon Sep 17 00:00:00 2001 From: Mike Travis Date: Tue, 2 Feb 2010 14:38:13 -0800 Subject: pci: Update pci_set_vga_state() to call arch functions Update pci_set_vga_state to call arch dependent functions to enable Legacy VGA I/O transactions to be redirected to correct target. [akpm@linux-foundation.org: make pci_register_set_vga_state() __init] Signed-off-by: Mike Travis LKML-Reference: <201002022238.o12McE1J018723@imap1.linux-foundation.org> Cc: Thomas Gleixner Cc: Robin Holt Cc: Jack Steiner Cc: Ingo Molnar Cc: Jesse Barnes Cc: David Airlie Signed-off-by: Andrew Morton Signed-off-by: H. Peter Anvin --- drivers/pci/pci.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 315fea47e784..ac2a576133f9 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2615,6 +2615,23 @@ int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type) return 0; } +/* Some architectures require additional programming to enable VGA */ +static arch_set_vga_state_t arch_set_vga_state; + +void __init pci_register_set_vga_state(arch_set_vga_state_t func) +{ + arch_set_vga_state = func; /* NULL disables */ +} + +static int pci_set_vga_state_arch(struct pci_dev *dev, bool decode, + unsigned int command_bits, bool change_bridge) +{ + if (arch_set_vga_state) + return arch_set_vga_state(dev, decode, command_bits, + change_bridge); + return 0; +} + /** * pci_set_vga_state - set VGA decode state on device and parents if requested * @dev: the PCI device @@ -2628,9 +2645,15 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode, struct pci_bus *bus; struct pci_dev *bridge; u16 cmd; + int rc; WARN_ON(command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY)); + /* ARCH specific VGA enables */ + rc = pci_set_vga_state_arch(dev, decode, command_bits, change_bridge); + if (rc) + return rc; + pci_read_config_word(dev, PCI_COMMAND, &cmd); if (decode == true) cmd |= command_bits; @@ -2845,6 +2868,7 @@ EXPORT_SYMBOL(pcim_pin_device); EXPORT_SYMBOL(pci_disable_device); EXPORT_SYMBOL(pci_find_capability); EXPORT_SYMBOL(pci_bus_find_capability); +EXPORT_SYMBOL(pci_register_set_vga_state); EXPORT_SYMBOL(pci_release_regions); EXPORT_SYMBOL(pci_request_regions); EXPORT_SYMBOL(pci_request_regions_exclusive); @@ -2877,4 +2901,3 @@ EXPORT_SYMBOL(pci_target_state); EXPORT_SYMBOL(pci_prepare_to_sleep); EXPORT_SYMBOL(pci_back_from_sleep); EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state); - -- cgit v1.2.2 From 773a38dbdad03474c5ee235f7d9bf9f51c9e3c2b Mon Sep 17 00:00:00 2001 From: Mike Travis Date: Tue, 2 Feb 2010 14:38:15 -0800 Subject: vgaarb: Fix VGA arbiter to accept PCI domains other than 0 Update the VGA Arbiter to accept PCI Domains other than 0. Signed-off-by: Mike Travis LKML-Reference: <201002022238.o12McFe8018730@imap1.linux-foundation.org> Cc: Thomas Gleixner Cc: Robin Holt Cc: Jack Steiner Cc: Ingo Molnar Cc: Jesse Barnes Cc: David Airlie Signed-off-by: Andrew Morton Signed-off-by: H. Peter Anvin --- drivers/gpu/vga/vgaarb.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index 1ac0c93603c9..ba7fa9ee54dc 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -954,6 +954,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, } } else if (strncmp(curr_pos, "target ", 7) == 0) { + struct pci_bus *pbus; unsigned int domain, bus, devfn; struct vga_device *vgadev; @@ -969,18 +970,31 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, ret_val = -EPROTO; goto done; } - - pdev = pci_get_bus_and_slot(bus, devfn); + pr_devel("vgaarb: %s ==> %x:%x:%x.%x\n", curr_pos, + domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + + pbus = pci_find_bus(domain, bus); + pr_devel("vgaarb: pbus %p\n", pbus); + if (pbus == NULL) { + pr_err("vgaarb: invalid PCI domain and/or bus address %x:%x\n", + domain, bus); + ret_val = -ENODEV; + goto done; + } + pdev = pci_get_slot(pbus, devfn); + pr_devel("vgaarb: pdev %p\n", pdev); if (!pdev) { - pr_info("vgaarb: invalid PCI address!\n"); + pr_err("vgaarb: invalid PCI address %x:%x\n", + bus, devfn); ret_val = -ENODEV; goto done; } } vgadev = vgadev_find(pdev); + pr_devel("vgaarb: vgadev %p\n", vgadev); if (vgadev == NULL) { - pr_info("vgaarb: this pci device is not a vga device\n"); + pr_err("vgaarb: this pci device is not a vga device\n"); pci_dev_put(pdev); ret_val = -ENODEV; goto done; @@ -998,7 +1012,8 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, } } if (i == MAX_USER_CARDS) { - pr_err("vgaarb: maximum user cards number reached!\n"); + pr_err("vgaarb: maximum user cards (%d) number reached!\n", + MAX_USER_CARDS); pci_dev_put(pdev); /* XXX: which value to return? */ ret_val = -ENOMEM; -- cgit v1.2.2 From 36028f3383872eefb558a4aae4c12ec2b5fa640f Mon Sep 17 00:00:00 2001 From: Mike Travis Date: Tue, 2 Feb 2010 17:45:01 -0800 Subject: vgaarb: Add user selectability of the number of GPUS in a system Update the VGA Arbiter to allow the user to select the number of GPU's supported in a system. v2: simplify setting of MAX_USER_CARDS, revert back to original default of 16 Signed-off-by: Mike Travis LKML-Reference: <4B68D51D.6090401@sgi.com> Cc: Thomas Gleixner Cc: Robin Holt Cc: Jack Steiner Cc: Ingo Molnar Cc: Jesse Barnes Cc: David Airlie Signed-off-by: Andrew Morton Signed-off-by: H. Peter Anvin --- drivers/gpu/vga/Kconfig | 8 ++++++++ drivers/gpu/vga/vgaarb.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/vga/Kconfig b/drivers/gpu/vga/Kconfig index 790e675b13eb..0920492cea0a 100644 --- a/drivers/gpu/vga/Kconfig +++ b/drivers/gpu/vga/Kconfig @@ -8,3 +8,11 @@ config VGA_ARB are accessed at same time they need some kind of coordination. Please see Documentation/vgaarbiter.txt for more details. Select this to enable VGA arbiter. + +config VGA_ARB_MAX_GPUS + int "Maximum number of GPUs" + default 16 + depends on VGA_ARB + help + Reserves space in the kernel to maintain resource locking for + multiple GPUS. The overhead for each GPU is very small. diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index ba7fa9ee54dc..325a53364211 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -688,7 +688,7 @@ EXPORT_SYMBOL(vga_client_register); * the arbiter. */ -#define MAX_USER_CARDS 16 +#define MAX_USER_CARDS CONFIG_VGA_ARB_MAX_GPUS #define PCI_INVALID_CARD ((struct pci_dev *)-1UL) /* -- cgit v1.2.2 From fc4618575f79eea062cdc51715040e40cd35b71c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 19 Jan 2010 07:24:55 +0000 Subject: sh: prepare the DMA driver for slave functionality Slave DMA functionality uses scatter-gather arrays for data transfers, whereas memcpy just uses a single data buffer. This patch converts the current memcpy implementation in shdma.c to use scatter-gather, making it just a special case with one SG-element. This allows us to isolate descriptor list manipulations and locking into one function, thus reducing error chances. Signed-off-by: Guennadi Liakhovetski Acked-by: Dan Williams Signed-off-by: Paul Mundt --- drivers/dma/shdma.c | 221 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 153 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index d10cc899c460..427c3effc432 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -53,12 +53,12 @@ static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all); #define SH_DMAC_CHAN_BASE(id) (dma_base_addr[id]) static void sh_dmae_writel(struct sh_dmae_chan *sh_dc, u32 data, u32 reg) { - ctrl_outl(data, (SH_DMAC_CHAN_BASE(sh_dc->id) + reg)); + ctrl_outl(data, SH_DMAC_CHAN_BASE(sh_dc->id) + reg); } static u32 sh_dmae_readl(struct sh_dmae_chan *sh_dc, u32 reg) { - return ctrl_inl((SH_DMAC_CHAN_BASE(sh_dc->id) + reg)); + return ctrl_inl(SH_DMAC_CHAN_BASE(sh_dc->id) + reg); } static void dmae_init(struct sh_dmae_chan *sh_chan) @@ -95,14 +95,14 @@ static int sh_dmae_rst(int id) return 0; } -static int dmae_is_busy(struct sh_dmae_chan *sh_chan) +static bool dmae_is_busy(struct sh_dmae_chan *sh_chan) { u32 chcr = sh_dmae_readl(sh_chan, CHCR); - if (chcr & CHCR_DE) { - if (!(chcr & CHCR_TE)) - return -EBUSY; /* working */ - } - return 0; /* waiting */ + + if ((chcr & (CHCR_DE | CHCR_TE)) == CHCR_DE) + return true; /* working */ + + return false; /* waiting */ } static inline unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan) @@ -136,10 +136,9 @@ static void dmae_halt(struct sh_dmae_chan *sh_chan) static int dmae_set_chcr(struct sh_dmae_chan *sh_chan, u32 val) { - int ret = dmae_is_busy(sh_chan); /* When DMA was working, can not set data to CHCR */ - if (ret) - return ret; + if (dmae_is_busy(sh_chan)) + return -EBUSY; sh_dmae_writel(sh_chan, val, CHCR); return 0; @@ -153,9 +152,9 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val) { u32 addr; int shift = 0; - int ret = dmae_is_busy(sh_chan); - if (ret) - return ret; + + if (dmae_is_busy(sh_chan)) + return -EBUSY; if (sh_chan->id & DMARS_CHAN_MSK) shift = DMARS_SHIFT; @@ -301,23 +300,95 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan) kfree(desc); } -static struct dma_async_tx_descriptor *sh_dmae_prep_memcpy( - struct dma_chan *chan, dma_addr_t dma_dest, dma_addr_t dma_src, - size_t len, unsigned long flags) +/* + * sh_dmae_add_desc - get, set up and return one transfer descriptor + * @sh_chan: DMA channel + * @flags: DMA transfer flags + * @dest: destination DMA address, incremented when direction equals + * DMA_FROM_DEVICE or DMA_BIDIRECTIONAL + * @src: source DMA address, incremented when direction equals + * DMA_TO_DEVICE or DMA_BIDIRECTIONAL + * @len: DMA transfer length + * @first: if NULL, set to the current descriptor and cookie set to -EBUSY + * @direction: needed for slave DMA to decide which address to keep constant, + * equals DMA_BIDIRECTIONAL for MEMCPY + * Returns 0 or an error + * Locks: called with desc_lock held + */ +static struct sh_desc *sh_dmae_add_desc(struct sh_dmae_chan *sh_chan, + unsigned long flags, dma_addr_t *dest, dma_addr_t *src, size_t *len, + struct sh_desc **first, enum dma_data_direction direction) { - struct sh_dmae_chan *sh_chan; - struct sh_desc *first = NULL, *prev = NULL, *new; + struct sh_desc *new; size_t copy_size; - LIST_HEAD(tx_list); - int chunks = (len + SH_DMA_TCR_MAX) / (SH_DMA_TCR_MAX + 1); - if (!chan) + if (!*len) return NULL; - if (!len) + /* Allocate the link descriptor from the free list */ + new = sh_dmae_get_desc(sh_chan); + if (!new) { + dev_err(sh_chan->dev, "No free link descriptor available\n"); return NULL; + } - sh_chan = to_sh_chan(chan); + copy_size = min(*len, (size_t)SH_DMA_TCR_MAX + 1); + + new->hw.sar = *src; + new->hw.dar = *dest; + new->hw.tcr = copy_size; + + if (!*first) { + /* First desc */ + new->async_tx.cookie = -EBUSY; + *first = new; + } else { + /* Other desc - invisible to the user */ + new->async_tx.cookie = -EINVAL; + } + + dev_dbg(sh_chan->dev, "chaining (%u/%u)@%x -> %x with %p, cookie %d\n", + copy_size, *len, *src, *dest, &new->async_tx, + new->async_tx.cookie); + + new->mark = DESC_PREPARED; + new->async_tx.flags = flags; + + *len -= copy_size; + if (direction == DMA_BIDIRECTIONAL || direction == DMA_TO_DEVICE) + *src += copy_size; + if (direction == DMA_BIDIRECTIONAL || direction == DMA_FROM_DEVICE) + *dest += copy_size; + + return new; +} + +/* + * sh_dmae_prep_sg - prepare transfer descriptors from an SG list + * + * Common routine for public (MEMCPY) and slave DMA. The MEMCPY case is also + * converted to scatter-gather to guarantee consistent locking and a correct + * list manipulation. For slave DMA direction carries the usual meaning, and, + * logically, the SG list is RAM and the addr variable contains slave address, + * e.g., the FIFO I/O register. For MEMCPY direction equals DMA_BIDIRECTIONAL + * and the SG list contains only one element and points at the source buffer. + */ +static struct dma_async_tx_descriptor *sh_dmae_prep_sg(struct sh_dmae_chan *sh_chan, + struct scatterlist *sgl, unsigned int sg_len, dma_addr_t *addr, + enum dma_data_direction direction, unsigned long flags) +{ + struct scatterlist *sg; + struct sh_desc *first = NULL, *new = NULL /* compiler... */; + LIST_HEAD(tx_list); + int chunks = 0; + int i; + + if (!sg_len) + return NULL; + + for_each_sg(sgl, sg, sg_len, i) + chunks += (sg_dma_len(sg) + SH_DMA_TCR_MAX) / + (SH_DMA_TCR_MAX + 1); /* Have to lock the whole loop to protect against concurrent release */ spin_lock_bh(&sh_chan->desc_lock); @@ -333,49 +404,32 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_memcpy( * only during this function, then they are immediately spliced * back onto the free list in form of a chain */ - do { - /* Allocate the link descriptor from the free list */ - new = sh_dmae_get_desc(sh_chan); - if (!new) { - dev_err(sh_chan->dev, - "No free memory for link descriptor\n"); - list_for_each_entry(new, &tx_list, node) - new->mark = DESC_IDLE; - list_splice(&tx_list, &sh_chan->ld_free); - spin_unlock_bh(&sh_chan->desc_lock); - return NULL; - } - - copy_size = min(len, (size_t)SH_DMA_TCR_MAX + 1); - - new->hw.sar = dma_src; - new->hw.dar = dma_dest; - new->hw.tcr = copy_size; - if (!first) { - /* First desc */ - new->async_tx.cookie = -EBUSY; - first = new; - } else { - /* Other desc - invisible to the user */ - new->async_tx.cookie = -EINVAL; - } - - dev_dbg(sh_chan->dev, - "chaining %u of %u with %p, dst %x, cookie %d\n", - copy_size, len, &new->async_tx, dma_dest, - new->async_tx.cookie); - - new->mark = DESC_PREPARED; - new->async_tx.flags = flags; - new->chunks = chunks--; - - prev = new; - len -= copy_size; - dma_src += copy_size; - dma_dest += copy_size; - /* Insert the link descriptor to the LD ring */ - list_add_tail(&new->node, &tx_list); - } while (len); + for_each_sg(sgl, sg, sg_len, i) { + dma_addr_t sg_addr = sg_dma_address(sg); + size_t len = sg_dma_len(sg); + + if (!len) + goto err_get_desc; + + do { + dev_dbg(sh_chan->dev, "Add SG #%d@%p[%d], dma %llx\n", + i, sg, len, (unsigned long long)sg_addr); + + if (direction == DMA_FROM_DEVICE) + new = sh_dmae_add_desc(sh_chan, flags, + &sg_addr, addr, &len, &first, + direction); + else + new = sh_dmae_add_desc(sh_chan, flags, + addr, &sg_addr, &len, &first, + direction); + if (!new) + goto err_get_desc; + + new->chunks = chunks--; + list_add_tail(&new->node, &tx_list); + } while (len); + } if (new != first) new->async_tx.cookie = -ENOSPC; @@ -386,6 +440,37 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_memcpy( spin_unlock_bh(&sh_chan->desc_lock); return &first->async_tx; + +err_get_desc: + list_for_each_entry(new, &tx_list, node) + new->mark = DESC_IDLE; + list_splice(&tx_list, &sh_chan->ld_free); + + spin_unlock_bh(&sh_chan->desc_lock); + + return NULL; +} + +static struct dma_async_tx_descriptor *sh_dmae_prep_memcpy( + struct dma_chan *chan, dma_addr_t dma_dest, dma_addr_t dma_src, + size_t len, unsigned long flags) +{ + struct sh_dmae_chan *sh_chan; + struct scatterlist sg; + + if (!chan || !len) + return NULL; + + sh_chan = to_sh_chan(chan); + + sg_init_table(&sg, 1); + sg_set_page(&sg, pfn_to_page(PFN_DOWN(dma_src)), len, + offset_in_page(dma_src)); + sg_dma_address(&sg) = dma_src; + sg_dma_len(&sg) = len; + + return sh_dmae_prep_sg(sh_chan, &sg, 1, &dma_dest, DMA_BIDIRECTIONAL, + flags); } static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all) @@ -559,7 +644,7 @@ static irqreturn_t sh_dmae_err(int irq, void *data) /* IRQ Multi */ if (shdev->pdata.mode & SHDMA_MIX_IRQ) { - int cnt = 0; + int __maybe_unused cnt = 0; switch (irq) { #if defined(DMTE6_IRQ) && defined(DMAE1_IRQ) case DMTE6_IRQ: -- cgit v1.2.2 From 623b4ac4bf9e767991c66e29b47dd4b19458fb42 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 3 Feb 2010 14:44:12 +0000 Subject: sh: fix Transfer Size calculation in both DMA drivers Both the original arch/sh/drivers/dma/dma-sh.c and the new SH dmaengine drivers do not take into account bits 3:2 of the Transfer Size field in the CHCR register, besides, bit-field defines set bit 2, but the mask only passes bits 1:0 through. TS_16BLK and TS_32BLK macros are bogus too. This patch fixes all these issues for sh7722 and sh7724, other CPUs stay unchanged and might need to be fixed too. Signed-off-by: Guennadi Liakhovetski Acked-by: Dan Williams Signed-off-by: Paul Mundt --- drivers/dma/shdma.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index 427c3effc432..3e1037c5ebd1 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -105,10 +105,14 @@ static bool dmae_is_busy(struct sh_dmae_chan *sh_chan) return false; /* waiting */ } +static unsigned int ts_shift[] = TS_SHIFT; static inline unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan) { u32 chcr = sh_dmae_readl(sh_chan, CHCR); - return ts_shift[(chcr & CHCR_TS_MASK) >> CHCR_TS_SHIFT]; + int cnt = ((chcr & CHCR_TS_LOW_MASK) >> CHCR_TS_LOW_SHIFT) | + ((chcr & CHCR_TS_HIGH_MASK) >> CHCR_TS_HIGH_SHIFT); + + return ts_shift[cnt]; } static void dmae_set_reg(struct sh_dmae_chan *sh_chan, struct sh_dmae_regs *hw) -- cgit v1.2.2 From cfefe99795251d76d92e8457f4152f532a961ec5 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 3 Feb 2010 14:46:41 +0000 Subject: sh: implement DMA_SLAVE capability in SH dmaengine driver Tested to work with a SIU ASoC driver on sh7722 (migor). Signed-off-by: Guennadi Liakhovetski Acked-by: Dan Williams Signed-off-by: Paul Mundt --- drivers/dma/shdma.c | 190 +++++++++++++++++++++++++++++++++++++++------------- drivers/dma/shdma.h | 7 +- 2 files changed, 144 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index 3e1037c5ebd1..b75ce8b84c46 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -48,6 +48,9 @@ enum sh_dmae_desc_status { */ #define RS_DEFAULT (RS_DUAL) +/* A bitmask with bits enough for enum sh_dmae_slave_chan_id */ +static unsigned long sh_dmae_slave_used[BITS_TO_LONGS(SHDMA_SLAVE_NUMBER)]; + static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all); #define SH_DMAC_CHAN_BASE(id) (dma_base_addr[id]) @@ -61,12 +64,6 @@ static u32 sh_dmae_readl(struct sh_dmae_chan *sh_dc, u32 reg) return ctrl_inl(SH_DMAC_CHAN_BASE(sh_dc->id) + reg); } -static void dmae_init(struct sh_dmae_chan *sh_chan) -{ - u32 chcr = RS_DEFAULT; /* default is DUAL mode */ - sh_dmae_writel(sh_chan, chcr, CHCR); -} - /* * Reset DMA controller * @@ -106,9 +103,8 @@ static bool dmae_is_busy(struct sh_dmae_chan *sh_chan) } static unsigned int ts_shift[] = TS_SHIFT; -static inline unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan) +static inline unsigned int calc_xmit_shift(u32 chcr) { - u32 chcr = sh_dmae_readl(sh_chan, CHCR); int cnt = ((chcr & CHCR_TS_LOW_MASK) >> CHCR_TS_LOW_SHIFT) | ((chcr & CHCR_TS_HIGH_MASK) >> CHCR_TS_HIGH_SHIFT); @@ -119,7 +115,7 @@ static void dmae_set_reg(struct sh_dmae_chan *sh_chan, struct sh_dmae_regs *hw) { sh_dmae_writel(sh_chan, hw->sar, SAR); sh_dmae_writel(sh_chan, hw->dar, DAR); - sh_dmae_writel(sh_chan, hw->tcr >> calc_xmit_shift(sh_chan), TCR); + sh_dmae_writel(sh_chan, hw->tcr >> sh_chan->xmit_shift, TCR); } static void dmae_start(struct sh_dmae_chan *sh_chan) @@ -127,7 +123,7 @@ static void dmae_start(struct sh_dmae_chan *sh_chan) u32 chcr = sh_dmae_readl(sh_chan, CHCR); chcr |= CHCR_DE | CHCR_IE; - sh_dmae_writel(sh_chan, chcr, CHCR); + sh_dmae_writel(sh_chan, chcr & ~CHCR_TE, CHCR); } static void dmae_halt(struct sh_dmae_chan *sh_chan) @@ -138,20 +134,27 @@ static void dmae_halt(struct sh_dmae_chan *sh_chan) sh_dmae_writel(sh_chan, chcr, CHCR); } +static void dmae_init(struct sh_dmae_chan *sh_chan) +{ + u32 chcr = RS_DEFAULT; /* default is DUAL mode */ + sh_chan->xmit_shift = calc_xmit_shift(chcr); + sh_dmae_writel(sh_chan, chcr, CHCR); +} + static int dmae_set_chcr(struct sh_dmae_chan *sh_chan, u32 val) { /* When DMA was working, can not set data to CHCR */ if (dmae_is_busy(sh_chan)) return -EBUSY; + sh_chan->xmit_shift = calc_xmit_shift(val); sh_dmae_writel(sh_chan, val, CHCR); + return 0; } -#define DMARS1_ADDR 0x04 -#define DMARS2_ADDR 0x08 -#define DMARS_SHIFT 8 -#define DMARS_CHAN_MSK 0x01 +#define DMARS_SHIFT 8 +#define DMARS_CHAN_MSK 0x01 static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val) { u32 addr; @@ -163,29 +166,18 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val) if (sh_chan->id & DMARS_CHAN_MSK) shift = DMARS_SHIFT; - switch (sh_chan->id) { - /* DMARS0 */ - case 0: - case 1: - addr = SH_DMARS_BASE; - break; - /* DMARS1 */ - case 2: - case 3: - addr = (SH_DMARS_BASE + DMARS1_ADDR); - break; - /* DMARS2 */ - case 4: - case 5: - addr = (SH_DMARS_BASE + DMARS2_ADDR); - break; - default: + if (sh_chan->id < 6) + /* DMA0RS0 - DMA0RS2 */ + addr = SH_DMARS_BASE0 + (sh_chan->id / 2) * 4; +#ifdef SH_DMARS_BASE1 + else if (sh_chan->id < 12) + /* DMA1RS0 - DMA1RS2 */ + addr = SH_DMARS_BASE1 + ((sh_chan->id - 6) / 2) * 4; +#endif + else return -EINVAL; - } - ctrl_outw((val << shift) | - (ctrl_inw(addr) & (shift ? 0xFF00 : 0x00FF)), - addr); + ctrl_outw((val << shift) | (ctrl_inw(addr) & (0xFF00 >> shift)), addr); return 0; } @@ -253,10 +245,53 @@ static struct sh_desc *sh_dmae_get_desc(struct sh_dmae_chan *sh_chan) return NULL; } +static struct sh_dmae_slave_config *sh_dmae_find_slave( + struct sh_dmae_chan *sh_chan, enum sh_dmae_slave_chan_id slave_id) +{ + struct dma_device *dma_dev = sh_chan->common.device; + struct sh_dmae_device *shdev = container_of(dma_dev, + struct sh_dmae_device, common); + struct sh_dmae_pdata *pdata = &shdev->pdata; + int i; + + if ((unsigned)slave_id >= SHDMA_SLAVE_NUMBER) + return NULL; + + for (i = 0; i < pdata->config_num; i++) + if (pdata->config[i].slave_id == slave_id) + return pdata->config + i; + + return NULL; +} + static int sh_dmae_alloc_chan_resources(struct dma_chan *chan) { struct sh_dmae_chan *sh_chan = to_sh_chan(chan); struct sh_desc *desc; + struct sh_dmae_slave *param = chan->private; + + /* + * This relies on the guarantee from dmaengine that alloc_chan_resources + * never runs concurrently with itself or free_chan_resources. + */ + if (param) { + struct sh_dmae_slave_config *cfg; + + cfg = sh_dmae_find_slave(sh_chan, param->slave_id); + if (!cfg) + return -EINVAL; + + if (test_and_set_bit(param->slave_id, sh_dmae_slave_used)) + return -EBUSY; + + param->config = cfg; + + dmae_set_dmars(sh_chan, cfg->mid_rid); + dmae_set_chcr(sh_chan, cfg->chcr); + } else { + if ((sh_dmae_readl(sh_chan, CHCR) & 0x700) != 0x400) + dmae_set_chcr(sh_chan, RS_DEFAULT); + } spin_lock_bh(&sh_chan->desc_lock); while (sh_chan->descs_allocated < NR_DESCS_PER_CHANNEL) { @@ -289,10 +324,18 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan) struct sh_desc *desc, *_desc; LIST_HEAD(list); + dmae_halt(sh_chan); + /* Prepared and not submitted descriptors can still be on the queue */ if (!list_empty(&sh_chan->ld_queue)) sh_dmae_chan_ld_cleanup(sh_chan, true); + if (chan->private) { + /* The caller is holding dma_list_mutex */ + struct sh_dmae_slave *param = chan->private; + clear_bit(param->slave_id, sh_dmae_slave_used); + } + spin_lock_bh(&sh_chan->desc_lock); list_splice_init(&sh_chan->ld_free, &list); @@ -304,7 +347,7 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan) kfree(desc); } -/* +/** * sh_dmae_add_desc - get, set up and return one transfer descriptor * @sh_chan: DMA channel * @flags: DMA transfer flags @@ -351,12 +394,14 @@ static struct sh_desc *sh_dmae_add_desc(struct sh_dmae_chan *sh_chan, new->async_tx.cookie = -EINVAL; } - dev_dbg(sh_chan->dev, "chaining (%u/%u)@%x -> %x with %p, cookie %d\n", + dev_dbg(sh_chan->dev, + "chaining (%u/%u)@%x -> %x with %p, cookie %d, shift %d\n", copy_size, *len, *src, *dest, &new->async_tx, - new->async_tx.cookie); + new->async_tx.cookie, sh_chan->xmit_shift); new->mark = DESC_PREPARED; new->async_tx.flags = flags; + new->direction = direction; *len -= copy_size; if (direction == DMA_BIDIRECTIONAL || direction == DMA_TO_DEVICE) @@ -465,6 +510,8 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_memcpy( if (!chan || !len) return NULL; + chan->private = NULL; + sh_chan = to_sh_chan(chan); sg_init_table(&sg, 1); @@ -477,6 +524,44 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_memcpy( flags); } +static struct dma_async_tx_descriptor *sh_dmae_prep_slave_sg( + struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, + enum dma_data_direction direction, unsigned long flags) +{ + struct sh_dmae_slave *param; + struct sh_dmae_chan *sh_chan; + + if (!chan) + return NULL; + + sh_chan = to_sh_chan(chan); + param = chan->private; + + /* Someone calling slave DMA on a public channel? */ + if (!param || !sg_len) { + dev_warn(sh_chan->dev, "%s: bad parameter: %p, %d, %d\n", + __func__, param, sg_len, param ? param->slave_id : -1); + return NULL; + } + + /* + * if (param != NULL), this is a successfully requested slave channel, + * therefore param->config != NULL too. + */ + return sh_dmae_prep_sg(sh_chan, sgl, sg_len, ¶m->config->addr, + direction, flags); +} + +static void sh_dmae_terminate_all(struct dma_chan *chan) +{ + struct sh_dmae_chan *sh_chan = to_sh_chan(chan); + + if (!chan) + return; + + sh_dmae_chan_ld_cleanup(sh_chan, true); +} + static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all) { struct sh_desc *desc, *_desc; @@ -508,7 +593,11 @@ static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all cookie = tx->cookie; if (desc->mark == DESC_COMPLETED && desc->chunks == 1) { - BUG_ON(sh_chan->completed_cookie != desc->cookie - 1); + if (sh_chan->completed_cookie != desc->cookie - 1) + dev_dbg(sh_chan->dev, + "Completing cookie %d, expected %d\n", + desc->cookie, + sh_chan->completed_cookie + 1); sh_chan->completed_cookie = desc->cookie; } @@ -581,7 +670,7 @@ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan) return; } - /* Find the first un-transfer desciptor */ + /* Find the first not transferred desciptor */ list_for_each_entry(sd, &sh_chan->ld_queue, node) if (sd->mark == DESC_SUBMITTED) { /* Get the ld start address from ld_queue */ @@ -685,11 +774,14 @@ static void dmae_do_tasklet(unsigned long data) struct sh_dmae_chan *sh_chan = (struct sh_dmae_chan *)data; struct sh_desc *desc; u32 sar_buf = sh_dmae_readl(sh_chan, SAR); + u32 dar_buf = sh_dmae_readl(sh_chan, DAR); spin_lock(&sh_chan->desc_lock); list_for_each_entry(desc, &sh_chan->ld_queue, node) { - if ((desc->hw.sar + desc->hw.tcr) == sar_buf && - desc->mark == DESC_SUBMITTED) { + if (desc->mark == DESC_SUBMITTED && + ((desc->direction == DMA_FROM_DEVICE && + (desc->hw.dar + desc->hw.tcr) == dar_buf) || + (desc->hw.sar + desc->hw.tcr) == sar_buf)) { dev_dbg(sh_chan->dev, "done #%d@%p dst %u\n", desc->async_tx.cookie, &desc->async_tx, desc->hw.dar); @@ -762,7 +854,7 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id) } snprintf(new_sh_chan->dev_id, sizeof(new_sh_chan->dev_id), - "sh-dmae%d", new_sh_chan->id); + "sh-dmae%d", new_sh_chan->id); /* set up channel irq */ err = request_irq(irq, &sh_dmae_interrupt, irqflags, @@ -773,11 +865,6 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id) goto err_no_irq; } - /* CHCR register control function */ - new_sh_chan->set_chcr = dmae_set_chcr; - /* DMARS register control function */ - new_sh_chan->set_dmars = dmae_set_dmars; - shdev->chan[id] = new_sh_chan; return 0; @@ -848,12 +935,19 @@ static int __init sh_dmae_probe(struct platform_device *pdev) INIT_LIST_HEAD(&shdev->common.channels); dma_cap_set(DMA_MEMCPY, shdev->common.cap_mask); + dma_cap_set(DMA_SLAVE, shdev->common.cap_mask); + shdev->common.device_alloc_chan_resources = sh_dmae_alloc_chan_resources; shdev->common.device_free_chan_resources = sh_dmae_free_chan_resources; shdev->common.device_prep_dma_memcpy = sh_dmae_prep_memcpy; shdev->common.device_is_tx_complete = sh_dmae_is_complete; shdev->common.device_issue_pending = sh_dmae_memcpy_issue_pending; + + /* Compulsory for DMA_SLAVE fields */ + shdev->common.device_prep_slave_sg = sh_dmae_prep_slave_sg; + shdev->common.device_terminate_all = sh_dmae_terminate_all; + shdev->common.dev = &pdev->dev; /* Default transfer size of 32 bytes requires 32-byte alignment */ shdev->common.copy_align = 5; diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h index 108f1cffb6f5..7e227f3c87c4 100644 --- a/drivers/dma/shdma.h +++ b/drivers/dma/shdma.h @@ -29,6 +29,7 @@ struct sh_desc { struct sh_dmae_regs hw; struct list_head node; struct dma_async_tx_descriptor async_tx; + enum dma_data_direction direction; dma_cookie_t cookie; int chunks; int mark; @@ -45,13 +46,9 @@ struct sh_dmae_chan { struct device *dev; /* Channel device */ struct tasklet_struct tasklet; /* Tasklet */ int descs_allocated; /* desc count */ + int xmit_shift; /* log_2(bytes_per_xfer) */ int id; /* Raw id of this channel */ char dev_id[16]; /* unique name per DMAC of channel */ - - /* Set chcr */ - int (*set_chcr)(struct sh_dmae_chan *sh_chan, u32 regs); - /* Set DMA resource */ - int (*set_dmars)(struct sh_dmae_chan *sh_chan, u16 res); }; struct sh_dmae_device { -- cgit v1.2.2 From 9e9622d1a064705181bea0600ea9eacd95adab7f Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 8 Feb 2010 11:47:44 +0900 Subject: serial: sh-sci: remove SCIF code in sci_rxd_in() Since sci_rxd_in() is used by SCI only, clean up the header file by killing off code dealing with SCIF ports and their register definitions. Also introduce a default sci_rxd_in() function which can be shared by all SCIF-only processors. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.h | 220 +----------------------------------------------- 1 file changed, 1 insertion(+), 219 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index 0efcded59ae6..f7d2589926d2 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -518,34 +518,6 @@ static inline int sci_rxd_in(struct uart_port *port) { if (port->mapbase == 0xfffffe80) return __raw_readb(SCPDR)&0x01 ? 1 : 0; /* SCI */ - if (port->mapbase == 0xa4000150) - return __raw_readb(SCPDR)&0x10 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xa4000140) - return __raw_readb(SCPDR)&0x04 ? 1 : 0; /* IRDA */ - return 1; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7705) -static inline int sci_rxd_in(struct uart_port *port) -{ - if (port->mapbase == SCIF0) - return __raw_readb(SCPDR)&0x04 ? 1 : 0; /* IRDA */ - if (port->mapbase == SCIF2) - return __raw_readb(SCPDR)&0x10 ? 1 : 0; /* SCIF */ - return 1; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) -static inline int sci_rxd_in(struct uart_port *port) -{ - return sci_in(port,SCxSR)&0x0010 ? 1 : 0; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \ - defined(CONFIG_CPU_SUBTYPE_SH7721) -static inline int sci_rxd_in(struct uart_port *port) -{ - if (port->mapbase == 0xa4430000) - return sci_in(port, SCxSR) & 0x0003 ? 1 : 0; - else if (port->mapbase == 0xa4438000) - return sci_in(port, SCxSR) & 0x0003 ? 1 : 0; return 1; } #elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \ @@ -558,207 +530,17 @@ static inline int sci_rxd_in(struct uart_port *port) { if (port->mapbase == 0xffe00000) return __raw_readb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */ - if (port->mapbase == 0xffe80000) - return __raw_readw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */ - return 1; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH4_202) -static inline int sci_rxd_in(struct uart_port *port) -{ - if (port->mapbase == 0xffe80000) - return __raw_readw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */ return 1; } -#elif defined(CONFIG_CPU_SUBTYPE_SH7757) -static inline int sci_rxd_in(struct uart_port *port) -{ - if (port->mapbase == 0xfe4b0000) - return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; - if (port->mapbase == 0xfe4c0000) - return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; - if (port->mapbase == 0xfe4d0000) - return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7760) -static inline int sci_rxd_in(struct uart_port *port) -{ - if (port->mapbase == 0xfe600000) - return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xfe610000) - return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xfe620000) - return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ - return 1; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7343) -static inline int sci_rxd_in(struct uart_port *port) -{ - if (port->mapbase == 0xffe00000) - return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xffe10000) - return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xffe20000) - return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xffe30000) - return __raw_readw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */ - return 1; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7366) -static inline int sci_rxd_in(struct uart_port *port) -{ - if (port->mapbase == 0xffe00000) - return __raw_readb(SCPDR0) & 0x0001 ? 1 : 0; /* SCIF0 */ - return 1; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7722) -static inline int sci_rxd_in(struct uart_port *port) -{ - if (port->mapbase == 0xffe00000) - return __raw_readb(PSDR) & 0x02 ? 1 : 0; /* SCIF0 */ - if (port->mapbase == 0xffe10000) - return __raw_readb(PADR) & 0x40 ? 1 : 0; /* SCIF1 */ - if (port->mapbase == 0xffe20000) - return __raw_readb(PWDR) & 0x04 ? 1 : 0; /* SCIF2 */ - - return 1; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7723) -static inline int sci_rxd_in(struct uart_port *port) -{ - if (port->mapbase == 0xffe00000) - return __raw_readb(SCSPTR0) & 0x0008 ? 1 : 0; /* SCIF0 */ - if (port->mapbase == 0xffe10000) - return __raw_readb(SCSPTR1) & 0x0020 ? 1 : 0; /* SCIF1 */ - if (port->mapbase == 0xffe20000) - return __raw_readb(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF2 */ - if (port->mapbase == 0xa4e30000) - return __raw_readb(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF3 */ - if (port->mapbase == 0xa4e40000) - return __raw_readb(SCSPTR4) & 0x0001 ? 1 : 0; /* SCIF4 */ - if (port->mapbase == 0xa4e50000) - return __raw_readb(SCSPTR5) & 0x0008 ? 1 : 0; /* SCIF5 */ - return 1; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7724) -# define SCFSR 0x0010 -# define SCASSR 0x0014 -static inline int sci_rxd_in(struct uart_port *port) -{ - if (port->type == PORT_SCIF) - return __raw_readw((port->mapbase + SCFSR)) & SCIF_BRK ? 1 : 0; - if (port->type == PORT_SCIFA) - return __raw_readw((port->mapbase + SCASSR)) & SCIF_BRK ? 1 : 0; - return 1; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103) -static inline int sci_rxd_in(struct uart_port *port) -{ - return sci_in(port, SCSPTR)&0x0001 ? 1 : 0; /* SCIF */ -} #elif defined(__H8300H__) || defined(__H8300S__) static inline int sci_rxd_in(struct uart_port *port) { int ch = (port->mapbase - SMR0) >> 3; return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0; } -#elif defined(CONFIG_CPU_SUBTYPE_SH7763) -static inline int sci_rxd_in(struct uart_port *port) -{ - if (port->mapbase == 0xffe00000) - return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xffe08000) - return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xffe10000) - return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF/IRDA */ - - return 1; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7770) -static inline int sci_rxd_in(struct uart_port *port) -{ - if (port->mapbase == 0xff923000) - return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xff924000) - return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xff925000) - return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ - return 1; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7780) -static inline int sci_rxd_in(struct uart_port *port) -{ - if (port->mapbase == 0xffe00000) - return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xffe10000) - return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ - return 1; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \ - defined(CONFIG_CPU_SUBTYPE_SH7786) -static inline int sci_rxd_in(struct uart_port *port) -{ - if (port->mapbase == 0xffea0000) - return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xffeb0000) - return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xffec0000) - return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xffed0000) - return __raw_readw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xffee0000) - return __raw_readw(SCSPTR4) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xffef0000) - return __raw_readw(SCSPTR5) & 0x0001 ? 1 : 0; /* SCIF */ - return 1; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \ - defined(CONFIG_CPU_SUBTYPE_SH7203) || \ - defined(CONFIG_CPU_SUBTYPE_SH7206) || \ - defined(CONFIG_CPU_SUBTYPE_SH7263) -static inline int sci_rxd_in(struct uart_port *port) -{ - if (port->mapbase == 0xfffe8000) - return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xfffe8800) - return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xfffe9000) - return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xfffe9800) - return __raw_readw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */ -#if defined(CONFIG_CPU_SUBTYPE_SH7201) - if (port->mapbase == 0xfffeA000) - return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xfffeA800) - return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xfffeB000) - return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xfffeB800) - return __raw_readw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */ -#endif - return 1; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7619) -static inline int sci_rxd_in(struct uart_port *port) -{ - if (port->mapbase == 0xf8400000) - return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xf8410000) - return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xf8420000) - return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ - return 1; -} -#elif defined(CONFIG_CPU_SUBTYPE_SHX3) +#else /* default case for non-SCI processors */ static inline int sci_rxd_in(struct uart_port *port) { - if (port->mapbase == 0xffc30000) - return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xffc40000) - return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xffc50000) - return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->mapbase == 0xffc60000) - return __raw_readw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */ return 1; } #endif -- cgit v1.2.2 From 0f88009d5cfae890bd3466126d1622ad4f16b798 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Mon, 18 Jan 2010 10:14:51 -0600 Subject: [SCSI] scsi_transport_sas: add support for transport layer retries (TLR) The mpt2sas driver wants to use transport layer retries (TLR) so the simplest thing to do seems to be to add the enabling flags and checks to the SAS transport class, since they're a SAS specific protocol feature. Signed-off-by: James Bottomley --- drivers/scsi/scsi_sas_internal.h | 2 +- drivers/scsi/scsi_transport_sas.c | 103 +++++++++++++++++++++++++++++++++++--- 2 files changed, 98 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_sas_internal.h b/drivers/scsi/scsi_sas_internal.h index 998cb5be6833..6266a5d73d0f 100644 --- a/drivers/scsi/scsi_sas_internal.h +++ b/drivers/scsi/scsi_sas_internal.h @@ -5,7 +5,7 @@ #define SAS_PHY_ATTRS 17 #define SAS_PORT_ATTRS 1 #define SAS_RPORT_ATTRS 7 -#define SAS_END_DEV_ATTRS 3 +#define SAS_END_DEV_ATTRS 5 #define SAS_EXPANDER_ATTRS 7 struct sas_internal { diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index f27e52d963d3..927e99cb7225 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -155,6 +155,17 @@ static struct { sas_bitfield_name_search(linkspeed, sas_linkspeed_names) sas_bitfield_name_set(linkspeed, sas_linkspeed_names) +static struct sas_end_device *sas_sdev_to_rdev(struct scsi_device *sdev) +{ + struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target); + struct sas_end_device *rdev; + + BUG_ON(rphy->identify.device_type != SAS_END_DEVICE); + + rdev = rphy_to_end_device(rphy); + return rdev; +} + static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost, struct sas_rphy *rphy) { @@ -358,6 +369,85 @@ void sas_remove_host(struct Scsi_Host *shost) } EXPORT_SYMBOL(sas_remove_host); +/** + * sas_tlr_supported - checking TLR bit in vpd 0x90 + * @sdev: scsi device struct + * + * Check Transport Layer Retries are supported or not. + * If vpd page 0x90 is present, TRL is supported. + * + */ +unsigned int +sas_tlr_supported(struct scsi_device *sdev) +{ + const int vpd_len = 32; + struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); + char *buffer = kzalloc(vpd_len, GFP_KERNEL); + int ret = 0; + + if (scsi_get_vpd_page(sdev, 0x90, buffer, vpd_len)) + goto out; + + /* + * Magic numbers: the VPD Protocol page (0x90) + * has a 4 byte header and then one entry per device port + * the TLR bit is at offset 8 on each port entry + * if we take the first port, that's at total offset 12 + */ + ret = buffer[12] & 0x01; + + out: + kfree(buffer); + rdev->tlr_supported = ret; + return ret; + +} +EXPORT_SYMBOL_GPL(sas_tlr_supported); + +/** + * sas_disable_tlr - setting TLR flags + * @sdev: scsi device struct + * + * Seting tlr_enabled flag to 0. + * + */ +void +sas_disable_tlr(struct scsi_device *sdev) +{ + struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); + + rdev->tlr_enabled = 0; +} +EXPORT_SYMBOL_GPL(sas_disable_tlr); + +/** + * sas_enable_tlr - setting TLR flags + * @sdev: scsi device struct + * + * Seting tlr_enabled flag 1. + * + */ +void sas_enable_tlr(struct scsi_device *sdev) +{ + unsigned int tlr_supported = 0; + tlr_supported = sas_tlr_supported(sdev); + + if (tlr_supported) { + struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); + + rdev->tlr_enabled = 1; + } + + return; +} +EXPORT_SYMBOL_GPL(sas_enable_tlr); + +unsigned int sas_is_tlr_enabled(struct scsi_device *sdev) +{ + struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); + return rdev->tlr_enabled; +} +EXPORT_SYMBOL_GPL(sas_is_tlr_enabled); /* * SAS Phy attributes @@ -1146,15 +1236,10 @@ sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); int sas_read_port_mode_page(struct scsi_device *sdev) { char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata; - struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target); - struct sas_end_device *rdev; + struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); struct scsi_mode_data mode_data; int res, error; - BUG_ON(rphy->identify.device_type != SAS_END_DEVICE); - - rdev = rphy_to_end_device(rphy); - if (!buffer) return -ENOMEM; @@ -1207,6 +1292,10 @@ sas_end_dev_simple_attr(I_T_nexus_loss_timeout, I_T_nexus_loss_timeout, "%d\n", int); sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout, "%d\n", int); +sas_end_dev_simple_attr(tlr_supported, tlr_supported, + "%d\n", int); +sas_end_dev_simple_attr(tlr_enabled, tlr_enabled, + "%d\n", int); static DECLARE_TRANSPORT_CLASS(sas_expander_class, "sas_expander", NULL, NULL, NULL); @@ -1733,6 +1822,8 @@ sas_attach_transport(struct sas_function_template *ft) SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning); SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout); SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout); + SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_supported); + SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_enabled); i->end_dev_attrs[count] = NULL; count = 0; -- cgit v1.2.2 From d7384b28afb2bf2b7be835ddc8c852bdc5e0ce1c Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:50:06 +0530 Subject: [SCSI] mpt2sas: Delete volume before HBA detach. The driver hangs when doing `rmmod mpt2sas` if there are any IR volumes present.The hang is due the scsi midlayer trying to access the IR volumes after the driver releases controller resources. Perhaps when scsi_remove_host is called,the scsi mid layer is sending some request. This doesn't occur for bare drives becuase the driver is already reporting those drives deleted prior to calling mpt2sas_base_detach. To solve this issue, we need to delete the volumes as well. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index efabea1a3ce4..cd551768bfbf 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -5998,6 +5998,8 @@ _scsih_remove(struct pci_dev *pdev) struct _sas_port *mpt2sas_port; struct _sas_device *sas_device; struct _sas_node *expander_sibling; + struct _raid_device *raid_device, *next; + struct MPT2SAS_TARGET *sas_target_priv_data; struct workqueue_struct *wq; unsigned long flags; @@ -6011,6 +6013,21 @@ _scsih_remove(struct pci_dev *pdev) if (wq) destroy_workqueue(wq); + /* release all the volumes */ + list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list, + list) { + if (raid_device->starget) { + sas_target_priv_data = + raid_device->starget->hostdata; + sas_target_priv_data->deleted = 1; + scsi_remove_target(&raid_device->starget->dev); + } + printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid" + "(0x%016llx)\n", ioc->name, raid_device->handle, + (unsigned long long) raid_device->wwid); + _scsih_raid_device_remove(ioc, raid_device); + } + /* free ports attached to the sas_host */ retry_again: list_for_each_entry(mpt2sas_port, -- cgit v1.2.2 From b2ff36ba19dec02b05d3e26e36923b71ab64f34a Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:51:05 +0530 Subject: [SCSI] mpt2sas: Return -ENODATA on IOCTL timeout The driver was modified to return -ENODATA when there is a timeout via ioctl path. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_ctl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 84a124f8e21f..198ecdd849a4 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -891,6 +891,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, issue_host_reset: if (issue_reset) { + ret = -ENODATA; if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { -- cgit v1.2.2 From 6846e75cdfa76c6609ac0381a6739c9f4af8fd3b Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:51:45 +0530 Subject: [SCSI] mpt2sas: User resource_size_t instead of unsigned long Use resource_size_t to define the type resource for the system interface register set. The existing implementation was using "unsigned long" which would be 32 bit in 32 bit OS. If 32 bit OS is using 64 bit physical address space for the system interface register set, we need to shift to using resource_size_t which takes care of physical address space. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 13 ++++++++----- drivers/scsi/mpt2sas/mpt2sas_base.h | 4 +--- 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 89d02401b9ec..bbd4f713d332 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -1222,6 +1222,8 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) u32 memap_sz; u32 pio_sz; int i, r = 0; + u64 pio_chip = 0; + u64 chip_phys = 0; dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, __func__)); @@ -1255,12 +1257,13 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) { if (pio_sz) continue; - ioc->pio_chip = pci_resource_start(pdev, i); + pio_chip = (u64)pci_resource_start(pdev, i); pio_sz = pci_resource_len(pdev, i); } else { if (memap_sz) continue; ioc->chip_phys = pci_resource_start(pdev, i); + chip_phys = (u64)ioc->chip_phys; memap_sz = pci_resource_len(pdev, i); ioc->chip = ioremap(ioc->chip_phys, memap_sz); if (ioc->chip == NULL) { @@ -1280,10 +1283,10 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n", ioc->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" : "IO-APIC enabled"), ioc->pci_irq); - printk(MPT2SAS_INFO_FMT "iomem(0x%lx), mapped(0x%p), size(%d)\n", - ioc->name, ioc->chip_phys, ioc->chip, memap_sz); - printk(MPT2SAS_INFO_FMT "ioport(0x%lx), size(%d)\n", - ioc->name, ioc->pio_chip, pio_sz); + printk(MPT2SAS_INFO_FMT "iomem(0x%016llx), mapped(0x%p), size(%d)\n", + ioc->name, (unsigned long long)chip_phys, ioc->chip, memap_sz); + printk(MPT2SAS_INFO_FMT "ioport(0x%016llx), size(%d)\n", + ioc->name, (unsigned long long)pio_chip, pio_sz); return 0; diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index bb4f14656afa..12fa18be77e1 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -464,7 +464,6 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); * @pdev: pci pdev object * @chip: memory mapped register space * @chip_phys: physical addrss prior to mapping - * @pio_chip: I/O mapped register space * @logging_level: see mpt2sas_debug.h * @fwfault_debug: debuging FW timeouts * @ir_firmware: IR firmware present @@ -587,8 +586,7 @@ struct MPT2SAS_ADAPTER { char tmp_string[MPT_STRING_LENGTH]; struct pci_dev *pdev; Mpi2SystemInterfaceRegs_t __iomem *chip; - unsigned long chip_phys; - unsigned long pio_chip; + resource_size_t chip_phys; int logging_level; int fwfault_debug; u8 ir_firmware; -- cgit v1.2.2 From e75b9b6d9d81e35aed5ef2692285c4948e173c5c Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:52:39 +0530 Subject: [SCSI] mpt2sas: Set ioc->fwfault_debug to the cmd line option mpt2sas_fwfault_debug. (1) change the formentioned string from logging_level to fwfault_debug (2) set ioc->fwfault_debug to the command line option mpt2sas_fwfault_debug setting at driver load time. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index bbd4f713d332..88e6eebc3159 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -107,8 +107,7 @@ _scsih_set_fwfault_debug(const char *val, struct kernel_param *kp) if (ret) return ret; - printk(KERN_INFO "setting logging_level(0x%08x)\n", - mpt2sas_fwfault_debug); + printk(KERN_INFO "setting fwfault_debug(%d)\n", mpt2sas_fwfault_debug); list_for_each_entry(ioc, &mpt2sas_ioc_list, list) ioc->fwfault_debug = mpt2sas_fwfault_debug; return 0; @@ -3576,6 +3575,8 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) init_waitqueue_head(&ioc->reset_wq); + ioc->fwfault_debug = mpt2sas_fwfault_debug; + /* base internal command bits */ mutex_init(&ioc->base_cmds.mutex); ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); -- cgit v1.2.2 From 22c88425e03e8476176375ab0457c88ff3a5b68c Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:53:04 +0530 Subject: [SCSI] mpt2sas: Use compat_ptr to setup the pointer compatibility. On ppc64, an 32bit application was failing due to data buffers not being copied properly from user to kernel memory. The problem due to improper conversion of 32 to 64 bit pointers. The fix is to use compat_ptr to setup the pointer compatibility in the routine _ctl_compat_mpt_command. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_ctl.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 198ecdd849a4..fa9bf83819d5 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -2203,14 +2203,10 @@ _ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg) karg.data_out_size = karg32.data_out_size; karg.max_sense_bytes = karg32.max_sense_bytes; karg.data_sge_offset = karg32.data_sge_offset; - memcpy(&karg.reply_frame_buf_ptr, &karg32.reply_frame_buf_ptr, - sizeof(uint32_t)); - memcpy(&karg.data_in_buf_ptr, &karg32.data_in_buf_ptr, - sizeof(uint32_t)); - memcpy(&karg.data_out_buf_ptr, &karg32.data_out_buf_ptr, - sizeof(uint32_t)); - memcpy(&karg.sense_data_ptr, &karg32.sense_data_ptr, - sizeof(uint32_t)); + karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr); + karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr); + karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr); + karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr); state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING; return _ctl_do_mpt_command(ioc, karg, &uarg->mf, state); } -- cgit v1.2.2 From f7c95ef02b564d9984c0655c9659791b1dd5d7ad Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:54:42 +0530 Subject: [SCSI] mpt2sas: Added raid transport support Adding support for raid transport layer. This will provide sysfs attributes containing raid level, state, and resync rate. MPT2SAS module will select RAID_ATTRS. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/Kconfig | 1 + drivers/scsi/mpt2sas/mpt2sas_base.h | 2 + drivers/scsi/mpt2sas/mpt2sas_scsih.c | 190 ++++++++++++++++++++++++++++++++++- 3 files changed, 189 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt2sas/Kconfig b/drivers/scsi/mpt2sas/Kconfig index 70c4c2467dd8..ba8e128de238 100644 --- a/drivers/scsi/mpt2sas/Kconfig +++ b/drivers/scsi/mpt2sas/Kconfig @@ -44,6 +44,7 @@ config SCSI_MPT2SAS tristate "LSI MPT Fusion SAS 2.0 Device Driver" depends on PCI && SCSI select SCSI_SAS_ATTRS + select RAID_ATTRS ---help--- This driver supports PCI-Express SAS 6Gb/s Host Adapters. diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 12fa18be77e1..014318fa3b0e 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -323,6 +323,7 @@ struct _sas_device { * @device_info: bitfield provides detailed info about the hidden components * @num_pds: number of hidden raid components * @responding: used in _scsih_raid_device_mark_responding + * @percent_complete: resync percent complete */ struct _raid_device { struct list_head list; @@ -336,6 +337,7 @@ struct _raid_device { u32 device_info; u8 num_pds; u8 responding; + u8 percent_complete; }; /** diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index cd551768bfbf..ca984cbc8e2f 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -52,6 +52,7 @@ #include #include #include +#include #include "mpt2sas_base.h" @@ -133,6 +134,9 @@ struct fw_event_work { void *event_data; }; +/* raid transport support */ +static struct raid_template *mpt2sas_raid_template; + /** * struct _scsi_io_transfer - scsi io transfer * @handle: sas device handle (assigned by firmware) @@ -1418,6 +1422,140 @@ _scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc, (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n"); } +/** + * _scsih_is_raid - return boolean indicating device is raid volume + * @dev the device struct object + */ +static int +_scsih_is_raid(struct device *dev) +{ + struct scsi_device *sdev = to_scsi_device(dev); + + return (sdev->channel == RAID_CHANNEL) ? 1 : 0; +} + +/** + * _scsih_get_resync - get raid volume resync percent complete + * @dev the device struct object + */ +static void +_scsih_get_resync(struct device *dev) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); + static struct _raid_device *raid_device; + unsigned long flags; + Mpi2RaidVolPage0_t vol_pg0; + Mpi2ConfigReply_t mpi_reply; + u32 volume_status_flags; + u8 percent_complete = 0; + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, + sdev->channel); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + + if (!raid_device) + goto out; + + if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, + MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, + sizeof(Mpi2RaidVolPage0_t))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out; + } + + volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags); + if (volume_status_flags & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) + percent_complete = raid_device->percent_complete; + out: + raid_set_resync(mpt2sas_raid_template, dev, percent_complete); +} + +/** + * _scsih_get_state - get raid volume level + * @dev the device struct object + */ +static void +_scsih_get_state(struct device *dev) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); + static struct _raid_device *raid_device; + unsigned long flags; + Mpi2RaidVolPage0_t vol_pg0; + Mpi2ConfigReply_t mpi_reply; + u32 volstate; + enum raid_state state = RAID_STATE_UNKNOWN; + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, + sdev->channel); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + + if (!raid_device) + goto out; + + if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, + MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, + sizeof(Mpi2RaidVolPage0_t))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out; + } + + volstate = le32_to_cpu(vol_pg0.VolumeStatusFlags); + if (volstate & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) { + state = RAID_STATE_RESYNCING; + goto out; + } + + switch (vol_pg0.VolumeState) { + case MPI2_RAID_VOL_STATE_OPTIMAL: + case MPI2_RAID_VOL_STATE_ONLINE: + state = RAID_STATE_ACTIVE; + break; + case MPI2_RAID_VOL_STATE_DEGRADED: + state = RAID_STATE_DEGRADED; + break; + case MPI2_RAID_VOL_STATE_FAILED: + case MPI2_RAID_VOL_STATE_MISSING: + state = RAID_STATE_OFFLINE; + break; + } + out: + raid_set_state(mpt2sas_raid_template, dev, state); +} + +/** + * _scsih_set_level - set raid level + * @sdev: scsi device struct + * @raid_device: raid_device object + */ +static void +_scsih_set_level(struct scsi_device *sdev, struct _raid_device *raid_device) +{ + enum raid_level level = RAID_LEVEL_UNKNOWN; + + switch (raid_device->volume_type) { + case MPI2_RAID_VOL_TYPE_RAID0: + level = RAID_LEVEL_0; + break; + case MPI2_RAID_VOL_TYPE_RAID10: + level = RAID_LEVEL_10; + break; + case MPI2_RAID_VOL_TYPE_RAID1E: + level = RAID_LEVEL_1E; + break; + case MPI2_RAID_VOL_TYPE_RAID1: + level = RAID_LEVEL_1; + break; + } + + raid_set_level(mpt2sas_raid_template, &sdev->sdev_gendev, level); +} + /** * _scsih_get_volume_capabilities - volume capabilities * @ioc: per adapter object @@ -1574,6 +1712,8 @@ _scsih_slave_configure(struct scsi_device *sdev) (unsigned long long)raid_device->wwid, raid_device->num_pds, ds); _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); + /* raid transport support */ + _scsih_set_level(sdev, raid_device); return 0; } @@ -5170,11 +5310,33 @@ static void _scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event) { + Mpi2EventDataIrOperationStatus_t *event_data = fw_event->event_data; + static struct _raid_device *raid_device; + unsigned long flags; + u16 handle; + #ifdef CONFIG_SCSI_MPT2SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) _scsih_sas_ir_operation_status_event_debug(ioc, - fw_event->event_data); + event_data); #endif + + /* code added for raid transport support */ + if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) { + + handle = le16_to_cpu(event_data->VolDevHandle); + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + + if (!raid_device) + return; + + if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) + raid_device->percent_complete = + event_data->PercentComplete; + } } /** @@ -6390,6 +6552,13 @@ static struct pci_driver scsih_driver = { #endif }; +/* raid transport support */ +static struct raid_function_template mpt2sas_raid_functions = { + .cookie = &scsih_driver_template, + .is_raid = _scsih_is_raid, + .get_resync = _scsih_get_resync, + .get_state = _scsih_get_state, +}; /** * _scsih_init - main entry point for this driver. @@ -6409,6 +6578,12 @@ _scsih_init(void) sas_attach_transport(&mpt2sas_transport_functions); if (!mpt2sas_transport_template) return -ENODEV; + /* raid transport support */ + mpt2sas_raid_template = raid_class_attach(&mpt2sas_raid_functions); + if (!mpt2sas_raid_template) { + sas_release_transport(mpt2sas_transport_template); + return -ENODEV; + } mpt2sas_base_initialize_callback_handler(); @@ -6443,8 +6618,11 @@ _scsih_init(void) mpt2sas_ctl_init(); error = pci_register_driver(&scsih_driver); - if (error) + if (error) { + /* raid transport support */ + raid_class_release(mpt2sas_raid_template); sas_release_transport(mpt2sas_transport_template); + } return error; } @@ -6462,7 +6640,8 @@ _scsih_exit(void) pci_unregister_driver(&scsih_driver); - sas_release_transport(mpt2sas_transport_template); + mpt2sas_ctl_exit(); + mpt2sas_base_release_callback_handler(scsi_io_cb_idx); mpt2sas_base_release_callback_handler(tm_cb_idx); mpt2sas_base_release_callback_handler(base_cb_idx); @@ -6474,7 +6653,10 @@ _scsih_exit(void) mpt2sas_base_release_callback_handler(tm_tr_cb_idx); mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx); - mpt2sas_ctl_exit(); + /* raid transport support */ + raid_class_release(mpt2sas_raid_template); + sas_release_transport(mpt2sas_transport_template); + } module_init(_scsih_init); -- cgit v1.2.2 From 50d5c60634673a79f8d88564e10345b50fca7378 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:55:26 +0530 Subject: [SCSI] mpt2sas: Added phy_enable and set_phy_speed sysfs callback support. Added new callbacks phy_enable and set_phy_speed in the mpt2sas_transport_functions template. This will allow end user to enable/disable phys and change links rates using the SysFS interface. Current implementation only supports direct attached phys, but we could in the future add support for expander based phys. A new subroutine mpt2sas_config_set_sas_iounit_pg1 was added; this wrapper function used to send request to controller firmware to modify the phys and link rates. A new subroutine _transport_find_local_phy was added; a function for easly obtaining the local phy object for direct attached. Example to disable a phy echo 0 > /sys/class/phy3:0/enable Example to enable the same phy echo 1 > /sys/class/phy3:0/enable Example to change the link rate to 1.5 #echo "1.5 Gbit" > /sys/class/phy3:0/maximum_linkrate #cat /sys/class/phy3:0/negotiated_linkrate 1.5 Gbit Example to change the link rate to 3.0 #echo "3.0 Gbit" > /sys/class/phy3:0/maximum_linkrate #cat /sys/class/phy3:0/negotiated_linkrate 3.0 Gbit Example to change the link rate to 6.0 #echo "6.0 Gbit" > /sys/class/phy3:0/maximum_linkrate #cat /sys/class/phy3:0/negotiated_linkrate 6.0 Gbit Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.h | 2 + drivers/scsi/mpt2sas/mpt2sas_config.c | 51 +++++++- drivers/scsi/mpt2sas/mpt2sas_transport.c | 196 ++++++++++++++++++++++++++++--- 3 files changed, 232 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 014318fa3b0e..93c067f5dbbc 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -853,6 +853,8 @@ int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page); int mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz); +int mpt2sas_config_set_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz); int mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage8_t *config_page); int mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c index 594a389c6526..411c27d7f787 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_config.c +++ b/drivers/scsi/mpt2sas/mpt2sas_config.c @@ -324,7 +324,9 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t if (r != 0) goto out; if (mpi_request->Action == - MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT) { + MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT || + mpi_request->Action == + MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) { ioc->base_add_sg_single(&mpi_request->PageBufferSGE, MPT2_CONFIG_COMMON_WRITE_SGLFLAGS | mem.sz, mem.page_dma); @@ -882,7 +884,7 @@ mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t } /** - * mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 0 + * mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 1 * @ioc: per adapter object * @mpi_reply: reply mf payload returned from firmware * @config_page: contents of the config page @@ -907,7 +909,7 @@ mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; mpi_request.Header.PageNumber = 1; - mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION; + mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); @@ -921,6 +923,49 @@ mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t return r; } +/** + * mpt2sas_config_set_sas_iounit_pg1 - send sas iounit page 1 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @sz: size of buffer passed in config_page + * Context: sleep. + * + * Calling function should call config_get_number_hba_phys prior to + * this function, so enough memory is allocated for config_page. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_set_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; + mpi_request.Header.PageNumber = 1; + mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; + _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); + out: + return r; +} + /** * mpt2sas_config_get_expander_pg0 - obtain expander page 0 * @ioc: per adapter object diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index 3a82872bad44..789f9ee7f001 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -855,6 +855,17 @@ rphy_to_ioc(struct sas_rphy *rphy) return shost_priv(shost); } +static struct _sas_phy * +_transport_find_local_phy(struct MPT2SAS_ADAPTER *ioc, struct sas_phy *phy) +{ + int i; + + for (i = 0; i < ioc->sas_hba.num_phys; i++) + if (ioc->sas_hba.phy[i].phy == phy) + return(&ioc->sas_hba.phy[i]); + return NULL; +} + /** * _transport_get_linkerrors - * @phy: The sas phy object @@ -870,14 +881,8 @@ _transport_get_linkerrors(struct sas_phy *phy) struct _sas_phy *mpt2sas_phy; Mpi2ConfigReply_t mpi_reply; Mpi2SasPhyPage1_t phy_pg1; - int i; - for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys && - !mpt2sas_phy; i++) { - if (ioc->sas_hba.phy[i].phy != phy) - continue; - mpt2sas_phy = &ioc->sas_hba.phy[i]; - } + mpt2sas_phy = _transport_find_local_phy(ioc, phy); if (!mpt2sas_phy) /* this phy not on sas_host */ return -EINVAL; @@ -971,14 +976,8 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset) struct _sas_phy *mpt2sas_phy; Mpi2SasIoUnitControlReply_t mpi_reply; Mpi2SasIoUnitControlRequest_t mpi_request; - int i; - for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys && - !mpt2sas_phy; i++) { - if (ioc->sas_hba.phy[i].phy != phy) - continue; - mpt2sas_phy = &ioc->sas_hba.phy[i]; - } + mpt2sas_phy = _transport_find_local_phy(ioc, phy); if (!mpt2sas_phy) /* this phy not on sas_host */ return -EINVAL; @@ -1005,6 +1004,173 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset) return 0; } +/** + * _transport_phy_enable - enable/disable phys + * @phy: The sas phy object + * @enable: enable phy when true + * + * Only support sas_host direct attached phys. + * Returns 0 for success, non-zero for failure. + */ +static int +_transport_phy_enable(struct sas_phy *phy, int enable) +{ + struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); + struct _sas_phy *mpt2sas_phy; + Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; + Mpi2ConfigReply_t mpi_reply; + u16 ioc_status; + u16 sz; + int rc = 0; + + mpt2sas_phy = _transport_find_local_phy(ioc, phy); + + if (!mpt2sas_phy) /* this phy not on sas_host */ + return -EINVAL; + + /* sas_iounit page 1 */ + sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * + sizeof(Mpi2SasIOUnit1PhyData_t)); + sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); + if (!sas_iounit_pg1) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -ENOMEM; + goto out; + } + if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, + sas_iounit_pg1, sz))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -ENXIO; + goto out; + } + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -EIO; + goto out; + } + + if (enable) + sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags + &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; + else + sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags + |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; + + mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz); + + out: + kfree(sas_iounit_pg1); + return rc; +} + +/** + * _transport_phy_speed - set phy min/max link rates + * @phy: The sas phy object + * @rates: rates defined in sas_phy_linkrates + * + * Only support sas_host direct attached phys. + * Returns 0 for success, non-zero for failure. + */ +static int +_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) +{ + struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); + struct _sas_phy *mpt2sas_phy; + Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; + Mpi2SasPhyPage0_t phy_pg0; + Mpi2ConfigReply_t mpi_reply; + u16 ioc_status; + u16 sz; + int i; + int rc = 0; + + mpt2sas_phy = _transport_find_local_phy(ioc, phy); + + if (!mpt2sas_phy) /* this phy not on sas_host */ + return -EINVAL; + + if (!rates->minimum_linkrate) + rates->minimum_linkrate = phy->minimum_linkrate; + else if (rates->minimum_linkrate < phy->minimum_linkrate_hw) + rates->minimum_linkrate = phy->minimum_linkrate_hw; + + if (!rates->maximum_linkrate) + rates->maximum_linkrate = phy->maximum_linkrate; + else if (rates->maximum_linkrate > phy->maximum_linkrate_hw) + rates->maximum_linkrate = phy->maximum_linkrate_hw; + + /* sas_iounit page 1 */ + sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * + sizeof(Mpi2SasIOUnit1PhyData_t)); + sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); + if (!sas_iounit_pg1) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -ENOMEM; + goto out; + } + if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, + sas_iounit_pg1, sz))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -ENXIO; + goto out; + } + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -EIO; + goto out; + } + + for (i = 0; i < ioc->sas_hba.num_phys; i++) { + if (mpt2sas_phy->phy_id != i) { + sas_iounit_pg1->PhyData[i].MaxMinLinkRate = + (ioc->sas_hba.phy[i].phy->minimum_linkrate + + (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4)); + } else { + sas_iounit_pg1->PhyData[i].MaxMinLinkRate = + (rates->minimum_linkrate + + (rates->maximum_linkrate << 4)); + } + } + + if (mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, + sz)) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -ENXIO; + goto out; + } + + /* link reset */ + _transport_phy_reset(phy, 0); + + /* read phy page 0, then update the rates in the sas transport phy */ + if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, + mpt2sas_phy->phy_id)) { + phy->minimum_linkrate = _transport_convert_phy_link_rate( + phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); + phy->maximum_linkrate = _transport_convert_phy_link_rate( + phy_pg0.ProgrammedLinkRate >> 4); + phy->negotiated_linkrate = _transport_convert_phy_link_rate( + phy_pg0.NegotiatedLinkRate & + MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL); + } + + out: + kfree(sas_iounit_pg1); + return rc; +} + + /** * _transport_smp_handler - transport portal for smp passthru * @shost: shost object @@ -1207,6 +1373,8 @@ struct sas_function_template mpt2sas_transport_functions = { .get_enclosure_identifier = _transport_get_enclosure_identifier, .get_bay_identifier = _transport_get_bay_identifier, .phy_reset = _transport_phy_reset, + .phy_enable = _transport_phy_enable, + .set_phy_speed = _transport_phy_speed, .smp_handler = _transport_smp_handler, }; -- cgit v1.2.2 From f4af3c14113d1b0d98d5a5e717b8aa1f484065b6 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:55:54 +0530 Subject: [SCSI] mpt2sas: Update driver header to latest MPI Spec. Update header to latest MPI SPEC revision. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpi/mpi2.h | 16 ++++-- drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h | 25 ++++++++- drivers/scsi/mpt2sas/mpi/mpi2_history.txt | 93 +++++++++++++++++++++++-------- drivers/scsi/mpt2sas/mpi/mpi2_init.h | 24 +++++++- drivers/scsi/mpt2sas/mpi/mpi2_ioc.h | 77 ++++++++++++++++++++++--- drivers/scsi/mpt2sas/mpi/mpi2_sas.h | 6 +- 6 files changed, 201 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h index 914168105297..9958d847a88d 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2.h @@ -8,7 +8,7 @@ * scatter/gather formats. * Creation Date: June 21, 2006 * - * mpi2.h Version: 02.00.13 + * mpi2.h Version: 02.00.14 * * Version History * --------------- @@ -53,6 +53,10 @@ * bytes reserved. * Added RAID Accelerator functionality. * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT. + * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT. + * Added MSI-x index mask and shift for Reply Post Host + * Index register. + * Added function code for Host Based Discovery Action. * -------------------------------------------------------------------------- */ @@ -78,7 +82,7 @@ #define MPI2_VERSION_02_00 (0x0200) /* versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT (0x0D) +#define MPI2_HEADER_VERSION_UNIT (0x0E) #define MPI2_HEADER_VERSION_DEV (0x00) #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) @@ -232,9 +236,12 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS #define MPI2_REPLY_FREE_HOST_INDEX_OFFSET (0x00000048) /* - * Offset for the Reply Descriptor Post Queue + * Defines for the Reply Descriptor Post Queue */ #define MPI2_REPLY_POST_HOST_INDEX_OFFSET (0x0000006C) +#define MPI2_REPLY_POST_HOST_INDEX_MASK (0x00FFFFFF) +#define MPI2_RPHI_MSIX_INDEX_MASK (0xFF000000) +#define MPI2_RPHI_MSIX_INDEX_SHIFT (24) /* * Defines for the HCBSize and address @@ -497,12 +504,13 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION #define MPI2_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) /* Target Command Buffer Post Base */ #define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) /* Target Command Buffer Post List */ #define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) /* RAID Accelerator*/ +/* Host Based Discovery Action */ +#define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F) /* Doorbell functions */ #define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) -/* #define MPI2_FUNCTION_IO_UNIT_RESET (0x41) */ #define MPI2_FUNCTION_HANDSHAKE (0x42) diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h index 1611c57a6fdf..cf0ac9f40c97 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h @@ -6,7 +6,7 @@ * Title: MPI Configuration messages and pages * Creation Date: November 10, 2006 * - * mpi2_cnfg.h Version: 02.00.12 + * mpi2_cnfg.h Version: 02.00.13 * * Version History * --------------- @@ -107,6 +107,8 @@ * to SAS Device Page 0 Flags field. * Added PhyInfo defines for power condition. * Added Ethernet configuration pages. + * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY. + * Added SAS PHY Page 4 structure and defines. * -------------------------------------------------------------------------- */ @@ -712,6 +714,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1 #define MPI2_IOUNITPAGE1_PAGEVERSION (0x04) /* IO Unit Page 1 Flags defines */ +#define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY (0x00000800) #define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE (0x00000600) #define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE (0x00000000) #define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE (0x00000200) @@ -2291,6 +2294,26 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3 { #define MPI2_SASPHY3_PAGEVERSION (0x00) +/* SAS PHY Page 4 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_4 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U16 Reserved1; /* 0x08 */ + U8 Reserved2; /* 0x0A */ + U8 Flags; /* 0x0B */ + U8 InitialFrame[28]; /* 0x0C */ +} MPI2_CONFIG_PAGE_SAS_PHY_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_4, + Mpi2SasPhyPage4_t, MPI2_POINTER pMpi2SasPhyPage4_t; + +#define MPI2_SASPHY4_PAGEVERSION (0x00) + +/* values for the Flags field */ +#define MPI2_SASPHY4_FLAGS_FRAME_VALID (0x02) +#define MPI2_SASPHY4_FLAGS_SATA_FRAME (0x01) + + + + /**************************************************************************** * SAS Port Config Pages ****************************************************************************/ diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt index 65fcaa31cb30..c4adf76b49d9 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt +++ b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt @@ -5,23 +5,24 @@ Copyright (c) 2000-2009 LSI Corporation. --------------------------------------- - Header Set Release Version: 02.00.12 - Header Set Release Date: 05-06-09 + Header Set Release Version: 02.00.14 + Header Set Release Date: 10-28-09 --------------------------------------- Filename Current version Prior version ---------- --------------- ------------- - mpi2.h 02.00.12 02.00.11 - mpi2_cnfg.h 02.00.11 02.00.10 - mpi2_init.h 02.00.07 02.00.06 - mpi2_ioc.h 02.00.11 02.00.10 - mpi2_raid.h 02.00.03 02.00.03 - mpi2_sas.h 02.00.02 02.00.02 + mpi2.h 02.00.14 02.00.13 + mpi2_cnfg.h 02.00.13 02.00.12 + mpi2_init.h 02.00.08 02.00.07 + mpi2_ioc.h 02.00.13 02.00.12 + mpi2_raid.h 02.00.04 02.00.04 + mpi2_sas.h 02.00.03 02.00.02 mpi2_targ.h 02.00.03 02.00.03 - mpi2_tool.h 02.00.03 02.00.02 + mpi2_tool.h 02.00.04 02.00.04 mpi2_type.h 02.00.00 02.00.00 - mpi2_ra.h 02.00.00 - mpi2_history.txt 02.00.11 02.00.12 + mpi2_ra.h 02.00.00 02.00.00 + mpi2_hbd.h 02.00.00 + mpi2_history.txt 02.00.14 02.00.13 * Date Version Description @@ -65,6 +66,11 @@ mpi2.h * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those * bytes reserved. * Added RAID Accelerator functionality. + * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT. + * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT. + * Added MSI-x index mask and shift for Reply Post Host + * Index register. + * Added function code for Host Based Discovery Action. * -------------------------------------------------------------------------- mpi2_cnfg.h @@ -155,6 +161,15 @@ mpi2_cnfg.h * Added expander reduced functionality data to SAS * Expander Page 0. * Added SAS PHY Page 2 and SAS PHY Page 3. + * 07-30-09 02.00.12 Added IO Unit Page 7. + * Added new device ids. + * Added SAS IO Unit Page 5. + * Added partial and slumber power management capable flags + * to SAS Device Page 0 Flags field. + * Added PhyInfo defines for power condition. + * Added Ethernet configuration pages. + * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY. + * Added SAS PHY Page 4 structure and defines. * -------------------------------------------------------------------------- mpi2_init.h @@ -172,6 +187,10 @@ mpi2_init.h * Query Asynchronous Event. * Defined two new bits in the SlotStatus field of the SCSI * Enclosure Processor Request and Reply. + * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for + * both SCSI IO Error Reply and SCSI Task Management Reply. + * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY. + * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. * -------------------------------------------------------------------------- mpi2_ioc.h @@ -246,6 +265,20 @@ mpi2_ioc.h * Added two new reason codes for SAS Device Status Change * Event. * Added new event: SAS PHY Counter. + * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure. + * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. + * Added new product id family for 2208. + * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST. + * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY. + * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY. + * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY. + * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define. + * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define. + * Added Host Based Discovery Phy Event data. + * Added defines for ProductID Product field + * (MPI2_FW_HEADER_PID_). + * Modified values for SAS ProductID Family + * (MPI2_FW_HEADER_PID_FAMILY_). * -------------------------------------------------------------------------- mpi2_raid.h @@ -256,6 +289,8 @@ mpi2_raid.h * 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that * the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT * can be sized by the build environment. + * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of + * VolumeCreationFlags and marked the old one as obsolete. * -------------------------------------------------------------------------- mpi2_sas.h @@ -264,6 +299,8 @@ mpi2_sas.h * Control Request. * 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control * Request. + * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST + * to MPI2_SGE_IO_UNION since it supports chained SGLs. * -------------------------------------------------------------------------- mpi2_targ.h @@ -283,6 +320,10 @@ mpi2_tool.h * structures and defines. * 02-29-08 02.00.02 Modified various names to make them 32-character unique. * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool. + * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request + * and reply messages. + * Added MPI2_DIAG_BUF_TYPE_EXTENDED. + * Incremented MPI2_DIAG_BUF_TYPE_COUNT. * -------------------------------------------------------------------------- mpi2_type.h @@ -293,20 +334,26 @@ mpi2_ra.h * 05-06-09 02.00.00 Initial version. * -------------------------------------------------------------------------- +mpi2_hbd.h + * 10-28-09 02.00.00 Initial version. + * -------------------------------------------------------------------------- + + mpi2_history.txt Parts list history -Filename 02.00.12 ----------- -------- -mpi2.h 02.00.12 -mpi2_cnfg.h 02.00.11 -mpi2_init.h 02.00.07 -mpi2_ioc.h 02.00.11 -mpi2_raid.h 02.00.03 -mpi2_sas.h 02.00.02 -mpi2_targ.h 02.00.03 -mpi2_tool.h 02.00.03 -mpi2_type.h 02.00.00 -mpi2_ra.h 02.00.00 +Filename 02.00.14 02.00.13 02.00.12 +---------- -------- -------- -------- +mpi2.h 02.00.14 02.00.13 02.00.12 +mpi2_cnfg.h 02.00.13 02.00.12 02.00.11 +mpi2_init.h 02.00.08 02.00.07 02.00.07 +mpi2_ioc.h 02.00.13 02.00.12 02.00.11 +mpi2_raid.h 02.00.04 02.00.04 02.00.03 +mpi2_sas.h 02.00.03 02.00.02 02.00.02 +mpi2_targ.h 02.00.03 02.00.03 02.00.03 +mpi2_tool.h 02.00.04 02.00.04 02.00.03 +mpi2_type.h 02.00.00 02.00.00 02.00.00 +mpi2_ra.h 02.00.00 02.00.00 02.00.00 +mpi2_hbd.h 02.00.00 Filename 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06 ---------- -------- -------- -------- -------- -------- -------- diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h index 563e56d2e945..6541945e97c3 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h @@ -6,7 +6,7 @@ * Title: MPI SCSI initiator mode messages and structures * Creation Date: June 23, 2006 * - * mpi2_init.h Version: 02.00.07 + * mpi2_init.h Version: 02.00.08 * * Version History * --------------- @@ -27,6 +27,10 @@ * Query Asynchronous Event. * Defined two new bits in the SlotStatus field of the SCSI * Enclosure Processor Request and Reply. + * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for + * both SCSI IO Error Reply and SCSI Task Management Reply. + * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY. + * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. * -------------------------------------------------------------------------- */ @@ -254,6 +258,11 @@ typedef struct _MPI2_SCSI_IO_REPLY #define MPI2_SCSI_STATE_AUTOSENSE_FAILED (0x02) #define MPI2_SCSI_STATE_AUTOSENSE_VALID (0x01) +/* masks and shifts for the ResponseInfo field */ + +#define MPI2_SCSI_RI_MASK_REASONCODE (0x000000FF) +#define MPI2_SCSI_RI_SHIFT_REASONCODE (0) + #define MPI2_SCSI_TASKTAG_UNKNOWN (0xFFFF) @@ -327,6 +336,7 @@ typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY U16 IOCStatus; /* 0x0E */ U32 IOCLogInfo; /* 0x10 */ U32 TerminationCount; /* 0x14 */ + U32 ResponseInfo; /* 0x18 */ } MPI2_SCSI_TASK_MANAGE_REPLY, MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REPLY, Mpi2SCSITaskManagementReply_t, MPI2_POINTER pMpi2SCSIManagementReply_t; @@ -339,8 +349,20 @@ typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY #define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05) #define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08) #define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09) +#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG (0x0A) #define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80) +/* masks and shifts for the ResponseInfo field */ + +#define MPI2_SCSITASKMGMT_RI_MASK_REASONCODE (0x000000FF) +#define MPI2_SCSITASKMGMT_RI_SHIFT_REASONCODE (0) +#define MPI2_SCSITASKMGMT_RI_MASK_ARI2 (0x0000FF00) +#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI2 (8) +#define MPI2_SCSITASKMGMT_RI_MASK_ARI1 (0x00FF0000) +#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI1 (16) +#define MPI2_SCSITASKMGMT_RI_MASK_ARI0 (0xFF000000) +#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI0 (24) + /**************************************************************************** * SCSI Enclosure Processor messages diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h index ea51ce868690..754938422f6a 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h @@ -6,7 +6,7 @@ * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: October 11, 2006 * - * mpi2_ioc.h Version: 02.00.12 + * mpi2_ioc.h Version: 02.00.13 * * Version History * --------------- @@ -87,6 +87,17 @@ * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure. * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. * Added new product id family for 2208. + * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST. + * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY. + * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY. + * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY. + * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define. + * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define. + * Added Host Based Discovery Phy Event data. + * Added defines for ProductID Product field + * (MPI2_FW_HEADER_PID_). + * Modified values for SAS ProductID Family + * (MPI2_FW_HEADER_PID_FAMILY_). * -------------------------------------------------------------------------- */ @@ -119,8 +130,10 @@ typedef struct _MPI2_IOC_INIT_REQUEST U16 MsgVersion; /* 0x0C */ U16 HeaderVersion; /* 0x0E */ U32 Reserved5; /* 0x10 */ - U32 Reserved6; /* 0x14 */ - U16 Reserved7; /* 0x18 */ + U16 Reserved6; /* 0x14 */ + U8 Reserved7; /* 0x16 */ + U8 HostMSIxVectors; /* 0x17 */ + U16 Reserved8; /* 0x18 */ U16 SystemRequestFrameSize; /* 0x1A */ U16 ReplyDescriptorPostQueueDepth; /* 0x1C */ U16 ReplyFreeQueueDepth; /* 0x1E */ @@ -215,7 +228,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY U8 MaxChainDepth; /* 0x14 */ U8 WhoInit; /* 0x15 */ U8 NumberOfPorts; /* 0x16 */ - U8 Reserved2; /* 0x17 */ + U8 MaxMSIxVectors; /* 0x17 */ U16 RequestCredit; /* 0x18 */ U16 ProductID; /* 0x1A */ U32 IOCCapabilities; /* 0x1C */ @@ -233,7 +246,8 @@ typedef struct _MPI2_IOC_FACTS_REPLY U8 MaxVolumes; /* 0x37 */ U16 MaxDevHandle; /* 0x38 */ U16 MaxPersistentEntries; /* 0x3A */ - U32 Reserved4; /* 0x3C */ + U16 MinDevHandle; /* 0x3C */ + U16 Reserved4; /* 0x3E */ } MPI2_IOC_FACTS_REPLY, MPI2_POINTER PTR_MPI2_IOC_FACTS_REPLY, Mpi2IOCFactsReply_t, MPI2_POINTER pMpi2IOCFactsReply_t; @@ -269,6 +283,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY /* ProductID field uses MPI2_FW_HEADER_PID_ */ /* IOCCapabilities */ +#define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY (0x00010000) #define MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX (0x00008000) #define MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR (0x00004000) #define MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY (0x00002000) @@ -453,6 +468,7 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY #define MPI2_EVENT_LOG_ENTRY_ADDED (0x0021) #define MPI2_EVENT_SAS_PHY_COUNTER (0x0022) #define MPI2_EVENT_GPIO_INTERRUPT (0x0023) +#define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY (0x0024) /* Log Entry Added Event data */ @@ -793,6 +809,7 @@ typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST MPI2_POINTER pMpi2EventDataSasTopologyChangeList_t; /* values for the ExpStatus field */ +#define MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER (0x00) #define MPI2_EVENT_SAS_TOPO_ES_ADDED (0x01) #define MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING (0x02) #define MPI2_EVENT_SAS_TOPO_ES_RESPONDING (0x03) @@ -878,6 +895,44 @@ typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER { * */ +/* Host Based Discovery Phy Event data */ + +typedef struct _MPI2_EVENT_HBD_PHY_SAS { + U8 Flags; /* 0x00 */ + U8 NegotiatedLinkRate; /* 0x01 */ + U8 PhyNum; /* 0x02 */ + U8 PhysicalPort; /* 0x03 */ + U32 Reserved1; /* 0x04 */ + U8 InitialFrame[28]; /* 0x08 */ +} MPI2_EVENT_HBD_PHY_SAS, MPI2_POINTER PTR_MPI2_EVENT_HBD_PHY_SAS, + Mpi2EventHbdPhySas_t, MPI2_POINTER pMpi2EventHbdPhySas_t; + +/* values for the Flags field */ +#define MPI2_EVENT_HBD_SAS_FLAGS_FRAME_VALID (0x02) +#define MPI2_EVENT_HBD_SAS_FLAGS_SATA_FRAME (0x01) + +/* use MPI2_SAS_NEG_LINK_RATE_ defines from mpi2_cnfg.h for + * the NegotiatedLinkRate field */ + +typedef union _MPI2_EVENT_HBD_DESCRIPTOR { + MPI2_EVENT_HBD_PHY_SAS Sas; +} MPI2_EVENT_HBD_DESCRIPTOR, MPI2_POINTER PTR_MPI2_EVENT_HBD_DESCRIPTOR, + Mpi2EventHbdDescriptor_t, MPI2_POINTER pMpi2EventHbdDescriptor_t; + +typedef struct _MPI2_EVENT_DATA_HBD_PHY { + U8 DescriptorType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 Reserved3; /* 0x04 */ + MPI2_EVENT_HBD_DESCRIPTOR Descriptor; /* 0x08 */ +} MPI2_EVENT_DATA_HBD_PHY, MPI2_POINTER PTR_MPI2_EVENT_DATA_HBD_PHY, + Mpi2EventDataHbdPhy_t, MPI2_POINTER pMpi2EventDataMpi2EventDataHbdPhy_t; + +/* values for the DescriptorType field */ +#define MPI2_EVENT_HBD_DT_SAS (0x01) + + + /**************************************************************************** * EventAck message ****************************************************************************/ @@ -1126,13 +1181,17 @@ typedef struct _MPI2_FW_IMAGE_HEADER #define MPI2_FW_HEADER_PID_TYPE_MASK (0xF000) #define MPI2_FW_HEADER_PID_TYPE_SAS (0x2000) -#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) -#define MPI2_FW_HEADER_PID_PROD_A (0x0000) +#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) +#define MPI2_FW_HEADER_PID_PROD_A (0x0000) +#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) +#define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI (0x0200) +#define MPI2_FW_HEADER_PID_PROD_IR_SCSI (0x0700) + #define MPI2_FW_HEADER_PID_FAMILY_MASK (0x00FF) /* SAS */ -#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0010) -#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0011) +#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0013) +#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0014) /* use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */ diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h index 8a42b136cf53..2d8aeed51392 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h @@ -6,7 +6,7 @@ * Title: MPI Serial Attached SCSI structures and definitions * Creation Date: February 9, 2007 * - * mpi2.h Version: 02.00.02 + * mpi2.h Version: 02.00.03 * * Version History * --------------- @@ -18,6 +18,8 @@ * Control Request. * 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control * Request. + * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST + * to MPI2_SGE_IO_UNION since it supports chained SGLs. * -------------------------------------------------------------------------- */ @@ -160,7 +162,7 @@ typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST U32 Reserved4; /* 0x14 */ U32 DataLength; /* 0x18 */ U8 CommandFIS[20]; /* 0x1C */ - MPI2_SIMPLE_SGE_UNION SGL; /* 0x20 */ + MPI2_SGE_IO_UNION SGL; /* 0x20 */ } MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST, Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t; -- cgit v1.2.2 From 84f0b04a0e3b279a0b0a851b93eb403a626ca4b8 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:56:28 +0530 Subject: [SCSI] mpt2sas: Enable TLR for SSP TAPE drives (Added SAS Transport APIs) If TLR is supported for end device, MPT2SAS driver will enable the TLR bit in the SCSI_IO for every request. If there is a response with MPI2_SCSITASKMGMT_RSP_INVALID_FRAME, the driver will turn off the TLR logic. [jejb: updated to new transport class TLR API] Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 55 +++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index ca984cbc8e2f..344a22ad2f33 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -1309,7 +1309,6 @@ _scsih_slave_alloc(struct scsi_device *sdev) struct MPT2SAS_DEVICE *sas_device_priv_data; struct scsi_target *starget; struct _raid_device *raid_device; - struct _sas_device *sas_device; unsigned long flags; sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL); @@ -1336,21 +1335,8 @@ _scsih_slave_alloc(struct scsi_device *sdev) if (raid_device) raid_device->sdev = sdev; /* raid is single lun */ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - } else { - /* set TLR bit for SSP devices */ - if (!(ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_TLR)) - goto out; - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - sas_device_priv_data->sas_target->sas_address); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device && sas_device->device_info & - MPI2_SAS_DEVICE_INFO_SSP_TARGET) - sas_device_priv_data->flags |= MPT_DEVICE_TLR_ON; } - out: return 0; } @@ -1616,6 +1602,32 @@ _scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc, kfree(vol_pg0); } +/** + * _scsih_enable_tlr - setting TLR flags + * @ioc: per adapter object + * @sdev: scsi device struct + * + * Enabling Transaction Layer Retries for tape devices when + * vpd page 0x90 is present + * + */ +static void +_scsih_enable_tlr(struct MPT2SAS_ADAPTER *ioc, struct scsi_device *sdev) +{ + /* only for TAPE */ + if (sdev->type != TYPE_TAPE) + return; + + if (!(ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR)) + return; + + sas_enable_tlr(sdev); + sdev_printk(KERN_INFO, sdev, "TLR %s\n", + sas_is_tlr_enabled(sdev) ? "Enabled" : "Disabled"); + return; + +} + /** * _scsih_slave_configure - device configure routine. * @sdev: scsi device struct @@ -1761,8 +1773,10 @@ _scsih_slave_configure(struct scsi_device *sdev) _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); - if (ssp_target) + if (ssp_target) { sas_read_port_mode_page(sdev); + _scsih_enable_tlr(ioc, sdev); + } return 0; } @@ -3049,7 +3063,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) } else mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; - if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON)) + if (sas_is_tlr_enabled(scmd->device)) mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON; smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd); @@ -3438,10 +3452,11 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF; if (!sas_device_priv_data->tlr_snoop_check) { sas_device_priv_data->tlr_snoop_check++; - if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) && - response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) - sas_device_priv_data->flags &= - ~MPT_DEVICE_TLR_ON; + if (sas_is_tlr_enabled(scmd->device) && + response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) { + sas_disable_tlr(scmd->device); + sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n"); + } } xfer_cnt = le32_to_cpu(mpi_reply->TransferCount); -- cgit v1.2.2 From e4b8972c6172950ce226afdf7a921098f7672d5c Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:57:02 +0530 Subject: [SCSI] mpt2sas: Bump version 04.100.01.00 Version upgraded to 04.100.01.00. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 93c067f5dbbc..e18b0544c38f 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -69,10 +69,10 @@ #define MPT2SAS_DRIVER_NAME "mpt2sas" #define MPT2SAS_AUTHOR "LSI Corporation " #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION "03.100.03.00" -#define MPT2SAS_MAJOR_VERSION 03 +#define MPT2SAS_DRIVER_VERSION "04.100.01.00" +#define MPT2SAS_MAJOR_VERSION 04 #define MPT2SAS_MINOR_VERSION 100 -#define MPT2SAS_BUILD_VERSION 03 +#define MPT2SAS_BUILD_VERSION 01 #define MPT2SAS_RELEASE_VERSION 00 /* -- cgit v1.2.2 From 48bd86cf213a5780346b603b703c4b83978611a8 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 7 Jan 2010 01:50:19 +0530 Subject: [SCSI] be2iscsi: Fixing Bug for multiple SGEs The patch fixes a but where the sg_next is not assigned and hence the first sge was being resused wrongly Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 9fc4446b21e0..d611a13dabf0 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1711,7 +1711,8 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg, io_task->bhs_pa.u.a32.address_hi); l_sg = sg; - for (index = 0; (index < num_sg) && (index < 2); index++, sg_next(sg)) { + for (index = 0; (index < num_sg) && (index < 2); index++, + sg = sg_next(sg)) { if (index == 0) { sg_len = sg_dma_len(sg); addr = (u64) sg_dma_address(sg); @@ -1755,7 +1756,7 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg, psgl++; psgl++; offset = 0; - for (index = 0; index < num_sg; index++, sg_next(sg), psgl++) { + for (index = 0; index < num_sg; index++, sg = sg_next(sg), psgl++) { sg_len = sg_dma_len(sg); addr = (u64) sg_dma_address(sg); AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, -- cgit v1.2.2 From aa3590329fdf789902e3c1383589bad12a74fb09 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 7 Jan 2010 01:51:04 +0530 Subject: [SCSI] be2iscsi: Fixing the number of SGE's The number of SGE's supported is fixed to what the chip expects. Also, the max sectors set to tested values Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 4cde8f6eb5bc..13ff02c1fcaa 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -56,10 +56,10 @@ #define BE2_DEFPDU_DATA_SZ 8192 #define MAX_CPUS 31 -#define BEISCSI_SGLIST_ELEMENTS BE2_SGE +#define BEISCSI_SGLIST_ELEMENTS 30 #define BEISCSI_CMD_PER_LUN 128 /* scsi_host->cmd_per_lun */ -#define BEISCSI_MAX_SECTORS 2048 /* scsi_host->max_sectors */ +#define BEISCSI_MAX_SECTORS 256 /* scsi_host->max_sectors */ #define BEISCSI_MAX_CMD_LEN 16 /* scsi_host->max_cmd_len */ #define BEISCSI_NUM_MAX_LUN 256 /* scsi_host->max_lun */ -- cgit v1.2.2 From a3babda5b3b60b5d28dbab127b1ecc8ba707b6e7 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 7 Jan 2010 01:51:44 +0530 Subject: [SCSI] be2iscsi: Fix to allow driver to load when the FW allows more cids This fix allows the driver to load when the FW allows more cids than than the driver supports. The driver will limit the number of cid to what it can support. There was no reason to fail the driver load,so, correcting that Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_mgmt.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 18f80411aef6..b0bb54dafbe9 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -49,12 +49,12 @@ unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl, phba->fw_config.iscsi_cid_count = pfw_cfg->ulp[0].sq_count; if (phba->fw_config.iscsi_cid_count > (BE2_MAX_SESSIONS / 2)) { - status = 1; - shost_printk(KERN_WARNING, phba->shost, - "FW reported MAX CXNS as %d \t" - "Max Supported = %d. Failing to load \n", - phba->fw_config.iscsi_cid_count, - BE2_MAX_SESSIONS); + SE_DEBUG(DBG_LVL_8, + "FW reported MAX CXNS as %d \t" + "Max Supported = %d.\n", + phba->fw_config.iscsi_cid_count, + BE2_MAX_SESSIONS); + phba->fw_config.iscsi_cid_count = BE2_MAX_SESSIONS / 2; } } else { shost_printk(KERN_WARNING, phba->shost, -- cgit v1.2.2 From d44a6d2bbffd9e5c87f0a78cbe9c089e21289162 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Sun, 17 Jan 2010 16:15:57 +0100 Subject: [SCSI] lpfc: unify two if branches with the same code in lpfc_decode_firmware_rev() Regardless of the flag state, the branches execute the same code Signed-off-by: Roel Kluin Acked-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_ct.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 0ebcd9baca79..bf7bf62e81eb 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1843,12 +1843,7 @@ lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag) c = (rev & 0x0000ff00) >> 8; b4 = (rev & 0x000000ff); - if (flag) - sprintf(fwrevision, "%d.%d%d%c%d ", b1, - b2, b3, c, b4); - else - sprintf(fwrevision, "%d.%d%d%c%d ", b1, - b2, b3, c, b4); + sprintf(fwrevision, "%d.%d%d%c%d", b1, b2, b3, c, b4); } return; } -- cgit v1.2.2 From fa4698fcf59c3bd01c171e5e558bae9e8eb396f1 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Mon, 18 Jan 2010 18:43:18 -0500 Subject: [SCSI] sd: Combine DIF/DIX error handling DIF and DIX errors are handled identically at this point. Collapse the switch cases into one and let scsi_io_completion print result and sense data. Signed-off-by: Martin K. Petersen Signed-off-by: James Bottomley --- drivers/scsi/sd.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index c5e9a99d4066..908d400b601a 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1196,19 +1196,10 @@ static int sd_done(struct scsi_cmnd *SCpnt) SCpnt->result = 0; memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); break; - case ABORTED_COMMAND: - if (sshdr.asc == 0x10) { /* DIF: Disk detected corruption */ - scsi_print_result(SCpnt); - scsi_print_sense("sd", SCpnt); + case ABORTED_COMMAND: /* DIF: Target detected corruption */ + case ILLEGAL_REQUEST: /* DIX: Host detected corruption */ + if (sshdr.asc == 0x10) good_bytes = sd_completed_bytes(SCpnt); - } - break; - case ILLEGAL_REQUEST: - if (sshdr.asc == 0x10) { /* DIX: HBA detected corruption */ - scsi_print_result(SCpnt); - scsi_print_sense("sd", SCpnt); - good_bytes = sd_completed_bytes(SCpnt); - } break; default: break; -- cgit v1.2.2 From d0e2ddff7c4b493acff50a9000564b67cbe7d676 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 19 Jan 2010 10:24:40 -0800 Subject: [SCSI] vmw_pvscsi: fix signedness warning with newer compilers pvscsi_setup_msix() expects 'irq' argument to be an int but is being passed unsigned int. Unsigned int is more proper type for IRQ number so let's use it. This shuts off a compile warning with recent compilers. Signed-off-by: Dmitry Torokhov Acked-by: Alok Kataria Signed-off-by: James Bottomley --- drivers/scsi/vmw_pvscsi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index d2604c813a20..e4ac5829b637 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -1069,7 +1069,8 @@ static void pvscsi_free_sgls(const struct pvscsi_adapter *adapter) free_pages((unsigned long)ctx->sgl, get_order(SGL_SIZE)); } -static int pvscsi_setup_msix(const struct pvscsi_adapter *adapter, int *irq) +static int pvscsi_setup_msix(const struct pvscsi_adapter *adapter, + unsigned int *irq) { struct msix_entry entry = { 0, PVSCSI_VECTOR_COMPLETION }; int ret; -- cgit v1.2.2 From 32951dd8cd70e525eb523c9e2b62d79d9157fae9 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Sat, 23 Jan 2010 05:34:24 +0530 Subject: [SCSI] be2iscsi: Remove Ring mode from driver Ring mode is not used. This patch removes the code. Signed-off-by: Mike Christie Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 181 ++++++++-------------------------------- 1 file changed, 33 insertions(+), 148 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index d611a13dabf0..522e7d526331 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -40,7 +40,6 @@ static unsigned int be_iopoll_budget = 10; static unsigned int be_max_phys_size = 64; static unsigned int enable_msix = 1; -static unsigned int ring_mode; MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table); MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR); @@ -671,9 +670,7 @@ static void free_wrb_handle(struct beiscsi_hba *phba, struct hwi_wrb_context *pwrb_context, struct wrb_handle *pwrb_handle) { - if (!ring_mode) - pwrb_context->pwrb_handle_base[pwrb_context->free_index] = - pwrb_handle; + pwrb_context->pwrb_handle_base[pwrb_context->free_index] = pwrb_handle; pwrb_context->wrb_handles_available++; if (pwrb_context->free_index == (phba->params.wrbs_per_cxn - 1)) pwrb_context->free_index = 0; @@ -865,7 +862,6 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, { struct hwi_wrb_context *pwrb_context; struct wrb_handle *pwrb_handle = NULL; - struct sgl_handle *psgl_handle = NULL; struct hwi_controller *phwi_ctrlr; struct iscsi_task *task; struct beiscsi_io_task *io_task; @@ -873,23 +869,14 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, struct iscsi_session *session = conn->session; phwi_ctrlr = phba->phwi_ctrlr; - if (ring_mode) { - psgl_handle = phba->sgl_hndl_array[((psol-> - dw[offsetof(struct amap_sol_cqe_ring, icd_index) / - 32] & SOL_ICD_INDEX_MASK) >> 6)]; - pwrb_context = &phwi_ctrlr->wrb_context[psgl_handle->cid]; - task = psgl_handle->task; - pwrb_handle = NULL; - } else { - pwrb_context = &phwi_ctrlr->wrb_context[((psol-> + pwrb_context = &phwi_ctrlr->wrb_context[((psol-> dw[offsetof(struct amap_sol_cqe, cid) / 32] & SOL_CID_MASK) >> 6) - phba->fw_config.iscsi_cid_start]; - pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> + pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> dw[offsetof(struct amap_sol_cqe, wrb_index) / 32] & SOL_WRB_INDEX_MASK) >> 16)]; - task = pwrb_handle->pio_handle; - } + task = pwrb_handle->pio_handle; io_task = task->dd_data; spin_lock(&phba->mgmt_sgl_lock); @@ -930,32 +917,23 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, struct iscsi_wrb *pwrb = NULL; struct hwi_controller *phwi_ctrlr; struct iscsi_task *task; - struct sgl_handle *psgl_handle = NULL; unsigned int type; struct iscsi_conn *conn = beiscsi_conn->conn; struct iscsi_session *session = conn->session; phwi_ctrlr = phba->phwi_ctrlr; - if (ring_mode) { - psgl_handle = phba->sgl_hndl_array[((psol-> - dw[offsetof(struct amap_sol_cqe_ring, icd_index) / - 32] & SOL_ICD_INDEX_MASK) >> 6)]; - task = psgl_handle->task; - type = psgl_handle->type; - } else { - pwrb_context = &phwi_ctrlr-> - wrb_context[((psol->dw[offsetof + pwrb_context = &phwi_ctrlr->wrb_context[((psol->dw[offsetof (struct amap_sol_cqe, cid) / 32] & SOL_CID_MASK) >> 6) - phba->fw_config.iscsi_cid_start]; - pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> + pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> dw[offsetof(struct amap_sol_cqe, wrb_index) / 32] & SOL_WRB_INDEX_MASK) >> 16)]; - task = pwrb_handle->pio_handle; - pwrb = pwrb_handle->pwrb; - type = (pwrb->dw[offsetof(struct amap_iscsi_wrb, type) / 32] & - WRB_TYPE_MASK) >> 28; - } + task = pwrb_handle->pio_handle; + pwrb = pwrb_handle->pwrb; + type = (pwrb->dw[offsetof(struct amap_iscsi_wrb, type) / 32] & + WRB_TYPE_MASK) >> 28; + spin_lock_bh(&session->lock); switch (type) { case HWH_TYPE_IO: @@ -986,15 +964,7 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, break; default: - if (ring_mode) - shost_printk(KERN_WARNING, phba->shost, - "In hwi_complete_cmd, unknown type = %d" - "icd_index 0x%x CID 0x%x\n", type, - ((psol->dw[offsetof(struct amap_sol_cqe_ring, - icd_index) / 32] & SOL_ICD_INDEX_MASK) >> 6), - psgl_handle->cid); - else - shost_printk(KERN_WARNING, phba->shost, + shost_printk(KERN_WARNING, phba->shost, "In hwi_complete_cmd, unknown type = %d" "wrb_index 0x%x CID 0x%x\n", type, ((psol->dw[offsetof(struct amap_iscsi_wrb, @@ -1483,7 +1453,6 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) unsigned int num_processed = 0; unsigned int tot_nump = 0; struct beiscsi_conn *beiscsi_conn; - struct sgl_handle *psgl_handle = NULL; struct beiscsi_endpoint *beiscsi_ep; struct iscsi_endpoint *ep; struct beiscsi_hba *phba; @@ -1496,18 +1465,11 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) CQE_VALID_MASK) { be_dws_le_to_cpu(sol, sizeof(struct sol_cqe)); - if (ring_mode) { - psgl_handle = phba->sgl_hndl_array[((sol-> - dw[offsetof(struct amap_sol_cqe_ring, - icd_index) / 32] & SOL_ICD_INDEX_MASK) - >> 6)]; - ep = phba->ep_array[psgl_handle->cid]; - } else { - ep = phba->ep_array[(u32) ((sol-> + ep = phba->ep_array[(u32) ((sol-> dw[offsetof(struct amap_sol_cqe, cid) / 32] & SOL_CID_MASK) >> 6) - phba->fw_config.iscsi_cid_start]; - } + beiscsi_ep = ep->dd_data; beiscsi_conn = beiscsi_ep->conn; @@ -1553,21 +1515,13 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) case CMD_CXN_KILLED_ITT_INVALID: case CMD_CXN_KILLED_SEQ_OUTOFORDER: case CMD_CXN_KILLED_INVALID_DATASN_RCVD: - if (ring_mode) { - SE_DEBUG(DBG_LVL_1, - "CQ Error notification for cmd.. " - "code %d cid 0x%x\n", - sol->dw[offsetof(struct amap_sol_cqe, code) / - 32] & CQE_CODE_MASK, psgl_handle->cid); - } else { - SE_DEBUG(DBG_LVL_1, + SE_DEBUG(DBG_LVL_1, "CQ Error notification for cmd.. " "code %d cid 0x%x\n", sol->dw[offsetof(struct amap_sol_cqe, code) / 32] & CQE_CODE_MASK, (sol->dw[offsetof(struct amap_sol_cqe, cid) / 32] & SOL_CID_MASK)); - } break; case UNSOL_DATA_DIGEST_ERROR_NOTIFY: SE_DEBUG(DBG_LVL_1, @@ -1589,37 +1543,23 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) case CXN_KILLED_OVER_RUN_RESIDUAL: case CXN_KILLED_UNDER_RUN_RESIDUAL: case CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN: - if (ring_mode) { - SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset CID " - "0x%x...\n", - sol->dw[offsetof(struct amap_sol_cqe, code) / - 32] & CQE_CODE_MASK, psgl_handle->cid); - } else { - SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset CID " + SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset CID " "0x%x...\n", sol->dw[offsetof(struct amap_sol_cqe, code) / 32] & CQE_CODE_MASK, (sol->dw[offsetof(struct amap_sol_cqe, cid) / 32] & CQE_CID_MASK)); - } iscsi_conn_failure(beiscsi_conn->conn, ISCSI_ERR_CONN_FAILED); break; case CXN_KILLED_RST_SENT: case CXN_KILLED_RST_RCVD: - if (ring_mode) { - SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset" - "received/sent on CID 0x%x...\n", - sol->dw[offsetof(struct amap_sol_cqe, code) / - 32] & CQE_CODE_MASK, psgl_handle->cid); - } else { - SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset" + SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset" "received/sent on CID 0x%x...\n", sol->dw[offsetof(struct amap_sol_cqe, code) / 32] & CQE_CODE_MASK, (sol->dw[offsetof(struct amap_sol_cqe, cid) / 32] & CQE_CID_MASK)); - } iscsi_conn_failure(beiscsi_conn->conn, ISCSI_ERR_CONN_FAILED); break; @@ -2848,11 +2788,6 @@ static int hwi_init_port(struct beiscsi_hba *phba) goto error; } - if (phba->fw_config.iscsi_features == 0x1) - ring_mode = 1; - else - ring_mode = 0; - status = beiscsi_create_cqs(phba, phwi_context); if (status != 0) { shost_printk(KERN_ERR, phba->shost, "CQ not created\n"); @@ -2980,17 +2915,6 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba) phba->io_sgl_hndl_avbl = 0; phba->eh_sgl_hndl_avbl = 0; - if (ring_mode) { - phba->sgl_hndl_array = kzalloc(sizeof(struct sgl_handle *) * - phba->params.icds_per_ctrl, - GFP_KERNEL); - if (!phba->sgl_hndl_array) { - shost_printk(KERN_ERR, phba->shost, - "Mem Alloc Failed. Failing to load\n"); - return -ENOMEM; - } - } - mem_descr_sglh = phba->init_mem; mem_descr_sglh += HWI_MEM_SGLH; if (1 == mem_descr_sglh->num_elements) { @@ -2998,8 +2922,6 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba) phba->params.ios_per_ctrl, GFP_KERNEL); if (!phba->io_sgl_hndl_base) { - if (ring_mode) - kfree(phba->sgl_hndl_array); shost_printk(KERN_ERR, phba->shost, "Mem Alloc Failed. Failing to load\n"); return -ENOMEM; @@ -3184,8 +3106,6 @@ static int beiscsi_init_port(struct beiscsi_hba *phba) if (hba_setup_cid_tbls(phba)) { shost_printk(KERN_ERR, phba->shost, "Failed in hba_setup_cid_tbls\n"); - if (ring_mode) - kfree(phba->sgl_hndl_array); kfree(phba->io_sgl_hndl_base); kfree(phba->eh_sgl_hndl_base); goto do_cleanup_ctrlr; @@ -3242,8 +3162,6 @@ static void beiscsi_clean_port(struct beiscsi_hba *phba) hwi_purge_eq(phba); hwi_cleanup(phba); - if (ring_mode) - kfree(phba->sgl_hndl_array); kfree(phba->io_sgl_hndl_base); kfree(phba->eh_sgl_hndl_base); kfree(phba->cid_array); @@ -3329,8 +3247,7 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_target_context_update_wrb)); doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK; - if (!ring_mode) - doorbell |= (pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK) + doorbell |= (pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT; doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT; @@ -3417,15 +3334,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) itt = (itt_t) cpu_to_be32(((unsigned int)io_task->pwrb_handle-> wrb_index << 16) | (unsigned int) (io_task->psgl_handle->sgl_index)); - if (ring_mode) { - phba->sgl_hndl_array[io_task->psgl_handle->sgl_index - - phba->fw_config.iscsi_icd_start] = - io_task->psgl_handle; - io_task->psgl_handle->task = task; - io_task->psgl_handle->cid = beiscsi_conn->beiscsi_conn_cid - - phba->fw_config.iscsi_cid_start; - } else - io_task->pwrb_handle->pio_handle = task; + io_task->pwrb_handle->pio_handle = task; io_task->cmd_bhs->iscsi_hdr.itt = itt; return 0; @@ -3511,18 +3420,12 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg, ISCSI_OPCODE_SCSI_DATA_OUT); AMAP_SET_BITS(struct amap_pdu_data_out, final_bit, &io_task->cmd_bhs->iscsi_data_pdu, 1); - if (ring_mode) - io_task->psgl_handle->type = INI_WR_CMD; - else - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_WR_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + INI_WR_CMD); AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1); } else { - if (ring_mode) - io_task->psgl_handle->type = INI_RD_CMD; - else - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_RD_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + INI_RD_CMD); AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0); } memcpy(&io_task->cmd_bhs->iscsi_data_pdu. @@ -3547,8 +3450,7 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg, be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb)); doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK; - if (!ring_mode) - doorbell |= (io_task->pwrb_handle->wrb_index & + doorbell |= (io_task->pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT; doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT; @@ -3583,21 +3485,15 @@ static int beiscsi_mtask(struct iscsi_task *task) switch (task->hdr->opcode & ISCSI_OPCODE_MASK) { case ISCSI_OP_LOGIN: - if (ring_mode) - io_task->psgl_handle->type = TGT_DM_CMD; - else - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - TGT_DM_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + TGT_DM_CMD); AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, 1); hwi_write_buffer(pwrb, task); break; case ISCSI_OP_NOOP_OUT: - if (ring_mode) - io_task->psgl_handle->type = INI_RD_CMD; - else - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_RD_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + INI_RD_CMD); if (task->hdr->ttt == ISCSI_RESERVED_TAG) AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); else @@ -3605,11 +3501,8 @@ static int beiscsi_mtask(struct iscsi_task *task) hwi_write_buffer(pwrb, task); break; case ISCSI_OP_TEXT: - if (ring_mode) - io_task->psgl_handle->type = INI_WR_CMD; - else - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_WR_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + INI_WR_CMD); AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1); hwi_write_buffer(pwrb, task); @@ -3642,19 +3535,13 @@ static int beiscsi_mtask(struct iscsi_task *task) phba->ctrl.mcc_numtag[tag]); free_mcc_tag(&phba->ctrl, tag); } - if (ring_mode) - io_task->psgl_handle->type = INI_TMF_CMD; - else - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_TMF_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + INI_TMF_CMD); AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); hwi_write_buffer(pwrb, task); break; case ISCSI_OP_LOGOUT: AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); - if (ring_mode) - io_task->psgl_handle->type = HWH_TYPE_LOGOUT; - else AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, HWH_TYPE_LOGOUT); hwi_write_buffer(pwrb, task); @@ -3673,8 +3560,7 @@ static int beiscsi_mtask(struct iscsi_task *task) be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb)); doorbell |= cid & DB_WRB_POST_CID_MASK; - if (!ring_mode) - doorbell |= (io_task->pwrb_handle->wrb_index & + doorbell |= (io_task->pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT; doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT; iowrite32(doorbell, phba->db_va + DB_TXULP0_OFFSET); @@ -3999,7 +3885,6 @@ static int __init beiscsi_module_init(void) "beiscsi pci driver.\n"); goto unregister_iscsi_transport; } - ring_mode = 0; return 0; unregister_iscsi_transport: -- cgit v1.2.2 From d2eeb1ac35a7146cbd4b1f6bf09bb6384ccdfb0d Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Sat, 23 Jan 2010 05:35:15 +0530 Subject: [SCSI] be2iscsi: changing copyright to 2010 This patch replaces 2009 with 2010 in copyright statement Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be.h | 2 +- drivers/scsi/be2iscsi/be_cmds.c | 2 +- drivers/scsi/be2iscsi/be_cmds.h | 2 +- drivers/scsi/be2iscsi/be_iscsi.c | 2 +- drivers/scsi/be2iscsi/be_iscsi.h | 2 +- drivers/scsi/be2iscsi/be_main.c | 2 +- drivers/scsi/be2iscsi/be_main.h | 2 +- drivers/scsi/be2iscsi/be_mgmt.c | 2 +- drivers/scsi/be2iscsi/be_mgmt.h | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h index 3861cf44dc15..0063740bbccf 100644 --- a/drivers/scsi/be2iscsi/be.h +++ b/drivers/scsi/be2iscsi/be.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index 44e69bdf359a..67098578fba4 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index 69dddfaebe59..49fcc787ee8b 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 95694d3d2089..3847a587d2a8 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h index f92ffc5349fb..1f512c28cbf9 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.h +++ b/drivers/scsi/be2iscsi/be_iscsi.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 522e7d526331..2f0027c5605c 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 13ff02c1fcaa..8cbe9084bd3e 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index b0bb54dafbe9..39106da6f547 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index f873a66cd48f..ecead6a5aa56 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or -- cgit v1.2.2 From 230dceb4316da9c8e05c82b64f2527aee95da2ff Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Sat, 23 Jan 2010 05:36:10 +0530 Subject: [SCSI] be2iscsi: Fix for first_burst This patch fixes the first_burst being modified instead of max_burst Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_iscsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 3847a587d2a8..d5712bc19a71 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -274,8 +274,8 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn, conn->max_recv_dlength = 65536; break; case ISCSI_PARAM_MAX_BURST: - if (session->first_burst > 262144) - session->first_burst = 262144; + if (session->max_burst > 262144) + session->max_burst = 262144; break; default: return 0; -- cgit v1.2.2 From 5dc1c416b39531e3bcf0651ca4123e64228dd553 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Sat, 23 Jan 2010 05:36:52 +0530 Subject: [SCSI] be2iscsi: Proper checking of state This patch adds proper checking of value in for hba state. We would be adding more states later on Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_iscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index d5712bc19a71..29a3aaf35f9f 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -561,7 +561,7 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, return ERR_PTR(ret); } - if (phba->state) { + if (phba->state != BE_ADAPTER_UP) { ret = -EBUSY; SE_DEBUG(DBG_LVL_1, "The Adapter state is Not UP \n"); return ERR_PTR(ret); -- cgit v1.2.2 From f55a24f2c24b63f8b4329eb28b4aec02a4bcf5d0 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Sat, 23 Jan 2010 05:37:40 +0530 Subject: [SCSI] be2iscsi: correcting the return This patch fixes an issue where return was not called properly. Thanks to Mike Christie for spotting this Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 2f0027c5605c..6b700ad2bb47 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3873,7 +3873,7 @@ static int __init beiscsi_module_init(void) SE_DEBUG(DBG_LVL_1, "beiscsi_module_init - Unable to register beiscsi" "transport.\n"); - ret = -ENOMEM; + return -ENOMEM; } SE_DEBUG(DBG_LVL_8, "In beiscsi_module_init, tt=%p \n", &beiscsi_iscsi_transport); -- cgit v1.2.2 From caf818f118b1ea60226a884072f1c3a9d5714766 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Sat, 23 Jan 2010 05:38:18 +0530 Subject: [SCSI] be2iscsi: Ensure clean reuse of wrb This patch ensures that wrb is cleanly resued for io path and is memset to zero for non io path Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 6b700ad2bb47..85c0e80628a8 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1663,11 +1663,7 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg, AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb, sg_len); sge_len = sg_len; - AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, - 1); } else { - AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, - 0); AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_r2t_offset, pwrb, sge_len); sg_len = sg_dma_len(sg); @@ -1690,8 +1686,22 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg, AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, io_task->bhs_pa.u.a32.address_lo); - if (num_sg == 2) - AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, 1); + if (num_sg == 1) { + AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, + 1); + AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, + 0); + } else if (num_sg == 2) { + AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, + 0); + AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, + 1); + } else { + AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, + 0); + AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, + 0); + } sg = l_sg; psgl++; psgl++; @@ -3476,6 +3486,7 @@ static int beiscsi_mtask(struct iscsi_task *task) cid = beiscsi_conn->beiscsi_conn_cid; pwrb = io_task->pwrb_handle->pwrb; + memset(pwrb, 0, sizeof(*pwrb)); AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, be32_to_cpu(task->cmdsn)); AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb, -- cgit v1.2.2 From b30c6dab1d87cc638a7413dd0e778d8c9a5232eb Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Sat, 23 Jan 2010 05:38:56 +0530 Subject: [SCSI] be2iscsi: changing the chip opcode for TEXT This patch corrects the chipopcode for text and chooses correct paramters for that command Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 85c0e80628a8..932cb8ab8db6 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3513,9 +3513,8 @@ static int beiscsi_mtask(struct iscsi_task *task) break; case ISCSI_OP_TEXT: AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_WR_CMD); + TGT_DM_CMD); AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); - AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1); hwi_write_buffer(pwrb, task); break; case ISCSI_OP_SCSI_TMFUNC: -- cgit v1.2.2 From 7c56533cf4fb072abc39e850e7ef4fb6166cc83b Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Sat, 23 Jan 2010 05:39:37 +0530 Subject: [SCSI] be2iscsi: correction in the claculation for num_cxn_wrb This patch correct the math done for num_cxn_wrb Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 932cb8ab8db6..687d535894a9 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -2042,10 +2042,9 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba) } idx = 0; pwrb = mem_descr_wrb->mem_array[idx].virtual_address; - num_cxn_wrb = - ((mem_descr_wrb->mem_array[idx].size) / (sizeof(struct iscsi_wrb)) * - phba->params.wrbs_per_cxn); - + num_cxn_wrb = (mem_descr_wrb->mem_array[idx].size) / + ((sizeof(struct iscsi_wrb) * + phba->params.wrbs_per_cxn)); for (index = 0; index < phba->params.cxns_per_ctrl; index += 2) { pwrb_context = &phwi_ctrlr->wrb_context[index]; if (num_cxn_wrb) { @@ -2058,9 +2057,9 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba) } else { idx++; pwrb = mem_descr_wrb->mem_array[idx].virtual_address; - num_cxn_wrb = ((mem_descr_wrb->mem_array[idx].size) / - (sizeof(struct iscsi_wrb)) * - phba->params.wrbs_per_cxn); + num_cxn_wrb = (mem_descr_wrb->mem_array[idx].size) / + ((sizeof(struct iscsi_wrb) * + phba->params.wrbs_per_cxn)); for (j = 0; j < phba->params.wrbs_per_cxn; j++) { pwrb_handle = pwrb_context->pwrb_handle_base[j]; pwrb_handle->pwrb = pwrb; -- cgit v1.2.2 From 2cec802980727f1daa46d8c31b411e083d49d7a2 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 23 Jan 2010 18:40:29 +0000 Subject: [SCSI] qla1280: Drop host_lock while requesting firmware request_firmware() may sleep and it appears to be safe to release the spinlock here. Signed-off-by: Ben Hutchings Cc: stable@kernel.org Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 8371d917a9a2..49ac4148493b 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1640,8 +1640,10 @@ qla1280_load_firmware_pio(struct scsi_qla_host *ha) uint16_t mb[MAILBOX_REGISTER_COUNT], i; int err; + spin_unlock_irq(ha->host->host_lock); err = request_firmware(&fw, ql1280_board_tbl[ha->devnum].fwname, &ha->pdev->dev); + spin_lock_irq(ha->host->host_lock); if (err) { printk(KERN_ERR "Failed to load image \"%s\" err %d\n", ql1280_board_tbl[ha->devnum].fwname, err); @@ -1699,8 +1701,10 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha) return -ENOMEM; #endif + spin_unlock_irq(ha->host->host_lock); err = request_firmware(&fw, ql1280_board_tbl[ha->devnum].fwname, &ha->pdev->dev); + spin_lock_irq(ha->host->host_lock); if (err) { printk(KERN_ERR "Failed to load image \"%s\" err %d\n", ql1280_board_tbl[ha->devnum].fwname, err); -- cgit v1.2.2 From 341af10239c4c87192bf762f53c7bcb1f3a1e767 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 26 Jan 2010 23:07:37 -0500 Subject: [SCSI] lpfc 8.3.8: BugFixes: SLI relates changes Fix hardware/SLI relates issues: - Handle XB bit so that ELS XRIs are not prematurely released. - Handle XB bit so that FCP XRIs are not prematurely released. - Define new security SLI Commands. - Remove unused security SLI commands - Skip receive data size parameter check on received FLOGI. - Added LPFC_USE_FCPWQIDX flag to iocb to force SLI layer to submit abort WQE on same WQ as the command WQE. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_crtn.h | 2 +- drivers/scsi/lpfc/lpfc_els.c | 2 +- drivers/scsi/lpfc/lpfc_hw.h | 18 +++--- drivers/scsi/lpfc/lpfc_nportdisc.c | 83 ++++++++++++++------------- drivers/scsi/lpfc/lpfc_scsi.c | 29 ++++++---- drivers/scsi/lpfc/lpfc_scsi.h | 1 + drivers/scsi/lpfc/lpfc_sli.c | 112 ++++++++++++++++++++++++++++++------- drivers/scsi/lpfc/lpfc_sli.h | 10 ++-- 8 files changed, 170 insertions(+), 87 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 650494d622c1..14ee7d4f71ba 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -99,7 +99,7 @@ int lpfc_disc_state_machine(struct lpfc_vport *, struct lpfc_nodelist *, void *, void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *); int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *, - struct serv_parm *, uint32_t); + struct serv_parm *, uint32_t, int); int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *); void lpfc_more_plogi(struct lpfc_vport *); void lpfc_more_adisc(struct lpfc_vport *); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 2cc39684ce97..32e3c8df22c5 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -4385,7 +4385,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, did = Fabric_DID; - if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3))) { + if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) { /* For a FLOGI we accept, then if our portname is greater * then the remote portname we initiate Nport login. */ diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index c9faa1d8c3c8..44c258730b07 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1465,17 +1465,13 @@ typedef struct { /* FireFly BIU registers */ #define CMD_IOCB_LOGENTRY_CN 0x94 #define CMD_IOCB_LOGENTRY_ASYNC_CN 0x96 -/* Unhandled Data Security SLI Commands */ -#define DSSCMD_IWRITE64_CR 0xD8 -#define DSSCMD_IWRITE64_CX 0xD9 -#define DSSCMD_IREAD64_CR 0xDA -#define DSSCMD_IREAD64_CX 0xDB -#define DSSCMD_INVALIDATE_DEK 0xDC -#define DSSCMD_SET_KEK 0xDD -#define DSSCMD_GET_KEK_ID 0xDE -#define DSSCMD_GEN_XFER 0xDF - -#define CMD_MAX_IOCB_CMD 0xE6 +/* Data Security SLI Commands */ +#define DSSCMD_IWRITE64_CR 0xF8 +#define DSSCMD_IWRITE64_CX 0xF9 +#define DSSCMD_IREAD64_CR 0xFA +#define DSSCMD_IREAD64_CX 0xFB + +#define CMD_MAX_IOCB_CMD 0xFB #define CMD_IOCB_MASK 0xff #define MAX_MSG_DATA 28 /* max msg data in CMD_ADAPTER_MSG diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 2ed6af194932..293234a5a944 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -62,7 +62,7 @@ lpfc_check_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - struct serv_parm * sp, uint32_t class) + struct serv_parm *sp, uint32_t class, int flogi) { volatile struct serv_parm *hsp = &vport->fc_sparam; uint16_t hsp_value, ssp_value = 0; @@ -75,49 +75,56 @@ lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * correcting the byte values. */ if (sp->cls1.classValid) { - hsp_value = (hsp->cls1.rcvDataSizeMsb << 8) | - hsp->cls1.rcvDataSizeLsb; - ssp_value = (sp->cls1.rcvDataSizeMsb << 8) | - sp->cls1.rcvDataSizeLsb; - if (!ssp_value) - goto bad_service_param; - if (ssp_value > hsp_value) { - sp->cls1.rcvDataSizeLsb = hsp->cls1.rcvDataSizeLsb; - sp->cls1.rcvDataSizeMsb = hsp->cls1.rcvDataSizeMsb; + if (!flogi) { + hsp_value = ((hsp->cls1.rcvDataSizeMsb << 8) | + hsp->cls1.rcvDataSizeLsb); + ssp_value = ((sp->cls1.rcvDataSizeMsb << 8) | + sp->cls1.rcvDataSizeLsb); + if (!ssp_value) + goto bad_service_param; + if (ssp_value > hsp_value) { + sp->cls1.rcvDataSizeLsb = + hsp->cls1.rcvDataSizeLsb; + sp->cls1.rcvDataSizeMsb = + hsp->cls1.rcvDataSizeMsb; + } } - } else if (class == CLASS1) { + } else if (class == CLASS1) goto bad_service_param; - } - if (sp->cls2.classValid) { - hsp_value = (hsp->cls2.rcvDataSizeMsb << 8) | - hsp->cls2.rcvDataSizeLsb; - ssp_value = (sp->cls2.rcvDataSizeMsb << 8) | - sp->cls2.rcvDataSizeLsb; - if (!ssp_value) - goto bad_service_param; - if (ssp_value > hsp_value) { - sp->cls2.rcvDataSizeLsb = hsp->cls2.rcvDataSizeLsb; - sp->cls2.rcvDataSizeMsb = hsp->cls2.rcvDataSizeMsb; + if (!flogi) { + hsp_value = ((hsp->cls2.rcvDataSizeMsb << 8) | + hsp->cls2.rcvDataSizeLsb); + ssp_value = ((sp->cls2.rcvDataSizeMsb << 8) | + sp->cls2.rcvDataSizeLsb); + if (!ssp_value) + goto bad_service_param; + if (ssp_value > hsp_value) { + sp->cls2.rcvDataSizeLsb = + hsp->cls2.rcvDataSizeLsb; + sp->cls2.rcvDataSizeMsb = + hsp->cls2.rcvDataSizeMsb; + } } - } else if (class == CLASS2) { + } else if (class == CLASS2) goto bad_service_param; - } - if (sp->cls3.classValid) { - hsp_value = (hsp->cls3.rcvDataSizeMsb << 8) | - hsp->cls3.rcvDataSizeLsb; - ssp_value = (sp->cls3.rcvDataSizeMsb << 8) | - sp->cls3.rcvDataSizeLsb; - if (!ssp_value) - goto bad_service_param; - if (ssp_value > hsp_value) { - sp->cls3.rcvDataSizeLsb = hsp->cls3.rcvDataSizeLsb; - sp->cls3.rcvDataSizeMsb = hsp->cls3.rcvDataSizeMsb; + if (!flogi) { + hsp_value = ((hsp->cls3.rcvDataSizeMsb << 8) | + hsp->cls3.rcvDataSizeLsb); + ssp_value = ((sp->cls3.rcvDataSizeMsb << 8) | + sp->cls3.rcvDataSizeLsb); + if (!ssp_value) + goto bad_service_param; + if (ssp_value > hsp_value) { + sp->cls3.rcvDataSizeLsb = + hsp->cls3.rcvDataSizeLsb; + sp->cls3.rcvDataSizeMsb = + hsp->cls3.rcvDataSizeMsb; + } } - } else if (class == CLASS3) { + } else if (class == CLASS3) goto bad_service_param; - } /* * Preserve the upper four bits of the MSB from the PLOGI response. @@ -295,7 +302,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, NULL); return 0; } - if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3) == 0)) { + if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 0) == 0)) { /* Reject this request because invalid parameters */ stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; @@ -831,7 +838,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, "0142 PLOGI RSP: Invalid WWN.\n"); goto out; } - if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3)) + if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3, 0)) goto out; /* PLOGI chkparm OK */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index a246410ce9df..d5cc6b8d32f2 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -626,6 +626,7 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba, &phba->sli4_hba.lpfc_abts_scsi_buf_list, list) { if (psb->cur_iocbq.sli4_xritag == xri) { list_del(&psb->list); + psb->exch_busy = 0; psb->status = IOSTAT_SUCCESS; spin_unlock_irqrestore( &phba->sli4_hba.abts_scsi_buf_list_lock, @@ -688,11 +689,12 @@ lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba) list); if (status) { /* Put this back on the abort scsi list */ - psb->status = IOSTAT_LOCAL_REJECT; - psb->result = IOERR_ABORT_REQUESTED; + psb->exch_busy = 1; rc++; - } else + } else { + psb->exch_busy = 0; psb->status = IOSTAT_SUCCESS; + } /* Put it back into the SCSI buffer list */ lpfc_release_scsi_buf_s4(phba, psb); } @@ -839,11 +841,12 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) psb->cur_iocbq.sli4_xritag); if (status) { /* Put this back on the abort scsi list */ - psb->status = IOSTAT_LOCAL_REJECT; - psb->result = IOERR_ABORT_REQUESTED; + psb->exch_busy = 1; rc++; - } else + } else { + psb->exch_busy = 0; psb->status = IOSTAT_SUCCESS; + } /* Put it back into the SCSI buffer list */ lpfc_release_scsi_buf_s4(phba, psb); break; @@ -857,11 +860,12 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) list); if (status) { /* Put this back on the abort scsi list */ - psb->status = IOSTAT_LOCAL_REJECT; - psb->result = IOERR_ABORT_REQUESTED; + psb->exch_busy = 1; rc++; - } else + } else { + psb->exch_busy = 0; psb->status = IOSTAT_SUCCESS; + } /* Put it back into the SCSI buffer list */ lpfc_release_scsi_buf_s4(phba, psb); } @@ -951,8 +955,7 @@ lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) { unsigned long iflag = 0; - if (psb->status == IOSTAT_LOCAL_REJECT - && psb->result == IOERR_ABORT_REQUESTED) { + if (psb->exch_busy) { spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock, iflag); psb->pCmd = NULL; @@ -2221,6 +2224,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; lpfc_cmd->status = pIocbOut->iocb.ulpStatus; + /* pick up SLI4 exhange busy status from HBA */ + lpfc_cmd->exch_busy = pIocbOut->iocb_flag & LPFC_EXCHANGE_BUSY; + if (pnode && NLP_CHK_NODE_ACT(pnode)) atomic_dec(&pnode->cmd_pending); @@ -2990,6 +2996,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) /* ABTS WQE must go to the same WQ as the WQE to be aborted */ abtsiocb->fcp_wqidx = iocb->fcp_wqidx; + abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX; if (lpfc_is_link_up(phba)) icmd->ulpCommand = CMD_ABORT_XRI_CN; diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index 65dfc8bd5b49..5932273870a5 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h @@ -118,6 +118,7 @@ struct lpfc_scsi_buf { uint32_t timeout; + uint16_t exch_busy; /* SLI4 hba reported XB on complete WCQE */ uint16_t status; /* From IOCB Word 7- ulpStatus */ uint32_t result; /* From IOCB Word 4. */ diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 589549b2bf0e..dc7c5c1231df 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -580,10 +580,7 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) else sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_xritag); if (sglq) { - if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED - && ((iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT) - && (iocbq->iocb.un.ulpWord[4] - == IOERR_ABORT_REQUESTED))) { + if (iocbq->iocb_flag & LPFC_EXCHANGE_BUSY) { spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock, iflag); list_add(&sglq->list, @@ -764,10 +761,6 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd) case DSSCMD_IWRITE64_CX: case DSSCMD_IREAD64_CR: case DSSCMD_IREAD64_CX: - case DSSCMD_INVALIDATE_DEK: - case DSSCMD_SET_KEK: - case DSSCMD_GET_KEK_ID: - case DSSCMD_GEN_XFER: type = LPFC_SOL_IOCB; break; case CMD_ABORT_XRI_CN: @@ -2228,9 +2221,15 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * All other are passed to the completion callback. */ if (pring->ringno == LPFC_ELS_RING) { - if (cmdiocbp->iocb_flag & LPFC_DRIVER_ABORTED) { + if ((phba->sli_rev < LPFC_SLI_REV4) && + (cmdiocbp->iocb_flag & + LPFC_DRIVER_ABORTED)) { + spin_lock_irqsave(&phba->hbalock, + iflag); cmdiocbp->iocb_flag &= ~LPFC_DRIVER_ABORTED; + spin_unlock_irqrestore(&phba->hbalock, + iflag); saveq->iocb.ulpStatus = IOSTAT_LOCAL_REJECT; saveq->iocb.un.ulpWord[4] = @@ -2240,7 +2239,47 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * of DMAing payload, so don't free data * buffer till after a hbeat. */ + spin_lock_irqsave(&phba->hbalock, + iflag); saveq->iocb_flag |= LPFC_DELAY_MEM_FREE; + spin_unlock_irqrestore(&phba->hbalock, + iflag); + } + if ((phba->sli_rev == LPFC_SLI_REV4) && + (saveq->iocb_flag & LPFC_EXCHANGE_BUSY)) { + /* Set cmdiocb flag for the exchange + * busy so sgl (xri) will not be + * released until the abort xri is + * received from hba, clear the + * LPFC_DRIVER_ABORTED bit in case + * it was driver initiated abort. + */ + spin_lock_irqsave(&phba->hbalock, + iflag); + cmdiocbp->iocb_flag &= + ~LPFC_DRIVER_ABORTED; + cmdiocbp->iocb_flag |= + LPFC_EXCHANGE_BUSY; + spin_unlock_irqrestore(&phba->hbalock, + iflag); + cmdiocbp->iocb.ulpStatus = + IOSTAT_LOCAL_REJECT; + cmdiocbp->iocb.un.ulpWord[4] = + IOERR_ABORT_REQUESTED; + /* + * For SLI4, irsiocb contains NO_XRI + * in sli_xritag, it shall not affect + * releasing sgl (xri) process. + */ + saveq->iocb.ulpStatus = + IOSTAT_LOCAL_REJECT; + saveq->iocb.un.ulpWord[4] = + IOERR_SLI_ABORTED; + spin_lock_irqsave(&phba->hbalock, + iflag); + saveq->iocb_flag |= LPFC_DELAY_MEM_FREE; + spin_unlock_irqrestore(&phba->hbalock, + iflag); } } (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq); @@ -5987,12 +6026,10 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, else bf_set(abort_cmd_ia, &wqe->abort_cmd, 0); bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG); - abort_tag = iocbq->iocb.un.acxri.abortIoTag; wqe->words[5] = 0; bf_set(lpfc_wqe_gen_ct, &wqe->generic, ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l)); abort_tag = iocbq->iocb.un.acxri.abortIoTag; - wqe->generic.abort_tag = abort_tag; /* * The abort handler will send us CMD_ABORT_XRI_CN or * CMD_CLOSE_XRI_CN and the fw only accepts CMD_ABORT_XRI_CX @@ -6121,15 +6158,15 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, if (lpfc_sli4_iocb2wqe(phba, piocb, &wqe)) return IOCB_ERROR; - if (piocb->iocb_flag & LPFC_IO_FCP) { + if ((piocb->iocb_flag & LPFC_IO_FCP) || + (piocb->iocb_flag & LPFC_USE_FCPWQIDX)) { /* * For FCP command IOCB, get a new WQ index to distribute * WQE across the WQsr. On the other hand, for abort IOCB, * it carries the same WQ index to the original command * IOCB. */ - if ((piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) && - (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) + if (piocb->iocb_flag & LPFC_IO_FCP) piocb->fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba); if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[piocb->fcp_wqidx], &wqe)) @@ -7004,7 +7041,14 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, abort_iocb->iocb.ulpContext != abort_context || (abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) == 0) spin_unlock_irq(&phba->hbalock); - else { + else if (phba->sli_rev < LPFC_SLI_REV4) { + /* + * leave the SLI4 aborted command on the txcmplq + * list and the command complete WCQE's XB bit + * will tell whether the SGL (XRI) can be released + * immediately or to the aborted SGL list for the + * following abort XRI from the HBA. + */ list_del_init(&abort_iocb->list); pring->txcmplq_cnt--; spin_unlock_irq(&phba->hbalock); @@ -7013,11 +7057,13 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * payload, so don't free data buffer till after * a hbeat. */ + spin_lock_irq(&phba->hbalock); abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE; - abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED; + spin_unlock_irq(&phba->hbalock); + abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT; - abort_iocb->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED; + abort_iocb->iocb.un.ulpWord[4] = IOERR_ABORT_REQUESTED; (abort_iocb->iocb_cmpl)(phba, abort_iocb, abort_iocb); } } @@ -7106,7 +7152,7 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, return 0; /* This signals the response to set the correct status - * before calling the completion handler. + * before calling the completion handler */ cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED; @@ -7124,6 +7170,8 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, /* ABTS WQE must go to the same WQ as the WQE to be aborted */ abtsiocbp->fcp_wqidx = cmdiocb->fcp_wqidx; + if (cmdiocb->iocb_flag & LPFC_IO_FCP) + abtsiocbp->iocb_flag |= LPFC_USE_FCPWQIDX; if (phba->link_state >= LPFC_LINK_UP) iabt->ulpCommand = CMD_ABORT_XRI_CN; @@ -7330,6 +7378,8 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, /* ABTS WQE must go to the same WQ as the WQE to be aborted */ abtsiocb->fcp_wqidx = iocbq->fcp_wqidx; + if (iocbq->iocb_flag & LPFC_IO_FCP) + abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX; if (lpfc_is_link_up(phba)) abtsiocb->iocb.ulpCommand = CMD_ABORT_XRI_CN; @@ -8359,11 +8409,24 @@ void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba) } } +/** + * lpfc_sli4_iocb_param_transfer - Transfer pIocbOut and cmpl status to pIocbIn + * @phba: pointer to lpfc hba data structure + * @pIocbIn: pointer to the rspiocbq + * @pIocbOut: pointer to the cmdiocbq + * @wcqe: pointer to the complete wcqe + * + * This routine transfers the fields of a command iocbq to a response iocbq + * by copying all the IOCB fields from command iocbq and transferring the + * completion status information from the complete wcqe. + **/ static void -lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn, +lpfc_sli4_iocb_param_transfer(struct lpfc_hba *phba, + struct lpfc_iocbq *pIocbIn, struct lpfc_iocbq *pIocbOut, struct lpfc_wcqe_complete *wcqe) { + unsigned long iflags; size_t offset = offsetof(struct lpfc_iocbq, iocb); memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset, @@ -8379,6 +8442,13 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn, pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; else pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; + + /* Pick up HBA exchange busy condition */ + if (bf_get(lpfc_wcqe_c_xb, wcqe)) { + spin_lock_irqsave(&phba->hbalock, iflags); + pIocbIn->iocb_flag |= LPFC_EXCHANGE_BUSY; + spin_unlock_irqrestore(&phba->hbalock, iflags); + } } /** @@ -8419,7 +8489,7 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba, } /* Fake the irspiocbq and copy necessary response information */ - lpfc_sli4_iocb_param_transfer(irspiocbq, cmdiocbq, wcqe); + lpfc_sli4_iocb_param_transfer(phba, irspiocbq, cmdiocbq, wcqe); return irspiocbq; } @@ -8976,7 +9046,7 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, } /* Fake the irspiocb and copy necessary response information */ - lpfc_sli4_iocb_param_transfer(&irspiocbq, cmdiocbq, wcqe); + lpfc_sli4_iocb_param_transfer(phba, &irspiocbq, cmdiocbq, wcqe); /* Pass the cmd_iocb and the rsp state to the upper layer */ (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, &irspiocbq); diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index ba38de3c28f1..dfcf5437d1f5 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -53,17 +53,19 @@ struct lpfc_iocbq { IOCB_t iocb; /* IOCB cmd */ uint8_t retry; /* retry counter for IOCB cmd - if needed */ - uint8_t iocb_flag; + uint16_t iocb_flag; #define LPFC_IO_LIBDFC 1 /* libdfc iocb */ #define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */ #define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */ #define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */ #define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */ #define LPFC_DELAY_MEM_FREE 0x20 /* Defer free'ing of FC data */ -#define LPFC_FIP_ELS_ID_MASK 0xc0 /* ELS_ID range 0-3 */ -#define LPFC_FIP_ELS_ID_SHIFT 6 +#define LPFC_EXCHANGE_BUSY 0x40 /* SLI4 hba reported XB in response */ +#define LPFC_USE_FCPWQIDX 0x80 /* Submit to specified FCPWQ index */ + +#define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */ +#define LPFC_FIP_ELS_ID_SHIFT 14 - uint8_t abort_count; uint8_t rsvd2; uint32_t drvrTimeout; /* driver timeout in seconds */ uint32_t fcp_wqidx; /* index to FCP work queue */ -- cgit v1.2.2 From 695a814e18561c52456acf5051fac0ea4b8111da Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 26 Jan 2010 23:08:03 -0500 Subject: [SCSI] lpfc 8.3.8: BugFixes: Discovery relates changes Discovery relates changes: - Separated VPI_REGISTERED state of physical port into VFI_REGISTERED and VPI_REGISTERED state so that driver can unregister physical port VPI independent of VFI. - Add code to unregister, re-init and re-register physical port VPI when physical port NportID change. - Add code to unregister and re-register VPI of a vport when its Nport ID change. - Add code in FDISC completion path to re-start FLOGI discovery when a FDISC complete with LOGIN_REQUIRED reason code. - Fix a memory leak in lpfc_init_vpi_cmpl - Add code to start a timer for vport to retry FDISC when CVL is received by a vport or physical port. If all Nports receive CVLs, then all timers are cancelled and a logical link level discovery will be started after one second. - Flush ELS commands after killing all delayed ELS commands. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 3 + drivers/scsi/lpfc/lpfc_crtn.h | 5 ++ drivers/scsi/lpfc/lpfc_els.c | 129 +++++++++++++++++++++++++++++++++---- drivers/scsi/lpfc/lpfc_hbadisc.c | 36 ++++++++++- drivers/scsi/lpfc/lpfc_init.c | 44 ++++++++++++- drivers/scsi/lpfc/lpfc_nportdisc.c | 2 +- drivers/scsi/lpfc/lpfc_sli.c | 62 +++++++++++++++++- drivers/scsi/lpfc/lpfc_vport.c | 2 +- 8 files changed, 265 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 1cc23a69db5e..197dc3e3bdc9 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -315,6 +315,9 @@ struct lpfc_vport { #define FC_VPORT_NEEDS_REG_VPI 0x80000 /* Needs to have its vpi registered */ #define FC_RSCN_DEFERRED 0x100000 /* A deferred RSCN being processed */ #define FC_VPORT_NEEDS_INIT_VPI 0x200000 /* Need to INIT_VPI before FDISC */ +#define FC_VPORT_CVL_RCVD 0x400000 /* VLink failed due to CVL */ +#define FC_VFI_REGISTERED 0x800000 /* VFI is registered */ +#define FC_FDISC_COMPLETED 0x1000000/* FDISC completed */ uint32_t ct_flags; #define FC_CT_RFF_ID 0x1 /* RFF_ID accepted by switch */ diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 14ee7d4f71ba..b9e8cd5b818a 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -44,6 +44,8 @@ int lpfc_reg_rpi(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *, void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); void lpfc_reg_vpi(struct lpfc_vport *, LPFC_MBOXQ_t *); +void lpfc_register_new_vport(struct lpfc_hba *, struct lpfc_vport *, + struct lpfc_nodelist *); void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *); void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); void lpfc_request_features(struct lpfc_hba *, struct lpfcMboxq *); @@ -52,10 +54,13 @@ struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t); void lpfc_cleanup_rcv_buffers(struct lpfc_vport *); void lpfc_rcv_seq_check_edtov(struct lpfc_vport *); void lpfc_cleanup_rpis(struct lpfc_vport *, int); +void lpfc_cleanup_pending_mbox(struct lpfc_vport *); int lpfc_linkdown(struct lpfc_hba *); void lpfc_linkdown_port(struct lpfc_vport *); void lpfc_port_link_failure(struct lpfc_vport *); void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *); +void lpfc_init_vpi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); +void lpfc_retry_pport_discovery(struct lpfc_hba *); void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 32e3c8df22c5..2c62349a1041 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -50,9 +50,6 @@ static int lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint8_t retry); static int lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb); -static void lpfc_register_new_vport(struct lpfc_hba *phba, - struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp); static int lpfc_max_els_tries = 3; @@ -604,10 +601,13 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, } else { ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - if (vport->vpi_state & LPFC_VPI_REGISTERED) { + if ((!(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) && + (vport->vpi_state & LPFC_VPI_REGISTERED)) { lpfc_start_fdiscs(phba); lpfc_do_scr_ns_plogi(phba, vport); - } else + } else if (vport->fc_flag & FC_VFI_REGISTERED) + lpfc_register_new_vport(phba, vport, ndlp); + else lpfc_issue_reg_vfi(vport); } return 0; @@ -804,6 +804,9 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp->ulpTimeout); goto flogifail; } + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_VPORT_CVL_RCVD; + spin_unlock_irq(shost->host_lock); /* * The FLogI succeeded. Sync the data for the CPU before @@ -2720,7 +2723,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (did == FDMI_DID) retry = 1; - if ((cmd == ELS_CMD_FLOGI) && + if (((cmd == ELS_CMD_FLOGI) || (cmd == ELS_CMD_FDISC)) && (phba->fc_topology != TOPOLOGY_LOOP) && !lpfc_error_lost_link(irsp)) { /* FLOGI retry policy */ @@ -5915,6 +5918,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; MAILBOX_t *mb = &pmb->u.mb; + int rc; spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; @@ -5936,6 +5940,26 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) spin_unlock_irq(shost->host_lock); lpfc_can_disctmo(vport); break; + /* If reg_vpi fail with invalid VPI status, re-init VPI */ + case 0x20: + spin_lock_irq(shost->host_lock); + vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + spin_unlock_irq(shost->host_lock); + lpfc_init_vpi(phba, pmb, vport->vpi); + pmb->vport = vport; + pmb->mbox_cmpl = lpfc_init_vpi_cmpl; + rc = lpfc_sli_issue_mbox(phba, pmb, + MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + lpfc_printf_vlog(vport, + KERN_ERR, LOG_MBOX, + "2732 Failed to issue INIT_VPI" + " mailbox command\n"); + } else { + lpfc_nlp_put(ndlp); + return; + } + default: /* Try to recover from this error */ lpfc_mbx_unreg_vpi(vport); @@ -5949,13 +5973,17 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) break; } } else { + spin_lock_irq(shost->host_lock); vport->vpi_state |= LPFC_VPI_REGISTERED; - if (vport == phba->pport) + spin_unlock_irq(shost->host_lock); + if (vport == phba->pport) { if (phba->sli_rev < LPFC_SLI_REV4) lpfc_issue_fabric_reglogin(vport); - else - lpfc_issue_reg_vfi(vport); - else + else { + lpfc_start_fdiscs(phba); + lpfc_do_scr_ns_plogi(phba, vport); + } + } else lpfc_do_scr_ns_plogi(phba, vport); } @@ -5977,7 +6005,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * This routine registers the @vport as a new virtual port with a HBA. * It is done through a registering vpi mailbox command. **/ -static void +void lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { @@ -6017,6 +6045,78 @@ mbox_err_exit: return; } +/** + * lpfc_retry_pport_discovery - Start timer to retry FLOGI. + * @phba: pointer to lpfc hba data structure. + * + * This routine abort all pending discovery commands and + * start a timer to retry FLOGI for the physical port + * discovery. + **/ +void +lpfc_retry_pport_discovery(struct lpfc_hba *phba) +{ + struct lpfc_vport **vports; + struct lpfc_nodelist *ndlp; + struct Scsi_Host *shost; + int i; + uint32_t link_state; + + /* Treat this failure as linkdown for all vports */ + link_state = phba->link_state; + lpfc_linkdown(phba); + phba->link_state = link_state; + + vports = lpfc_create_vport_work_array(phba); + + if (vports) { + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { + ndlp = lpfc_findnode_did(vports[i], Fabric_DID); + if (ndlp) + lpfc_cancel_retry_delay_tmo(vports[i], ndlp); + lpfc_els_flush_cmd(vports[i]); + } + lpfc_destroy_vport_work_array(phba, vports); + } + + /* If fabric require FLOGI, then re-instantiate physical login */ + ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); + if (!ndlp) + return; + + + shost = lpfc_shost_from_vport(phba->pport); + mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag |= NLP_DELAY_TMO; + spin_unlock_irq(shost->host_lock); + ndlp->nlp_last_elscmd = ELS_CMD_FLOGI; + phba->pport->port_state = LPFC_FLOGI; + return; +} + +/** + * lpfc_fabric_login_reqd - Check if FLOGI required. + * @phba: pointer to lpfc hba data structure. + * @cmdiocb: pointer to FDISC command iocb. + * @rspiocb: pointer to FDISC response iocb. + * + * This routine checks if a FLOGI is reguired for FDISC + * to succeed. + **/ +static int +lpfc_fabric_login_reqd(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + + if ((rspiocb->iocb.ulpStatus != IOSTAT_FABRIC_RJT) || + (rspiocb->iocb.un.ulpWord[4] != RJT_LOGIN_REQUIRED)) + return 0; + else + return 1; +} + /** * lpfc_cmpl_els_fdisc - Completion function for fdisc iocb command * @phba: pointer to lpfc hba data structure. @@ -6066,6 +6166,12 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID); if (irsp->ulpStatus) { + + if (lpfc_fabric_login_reqd(phba, cmdiocb, rspiocb)) { + lpfc_retry_pport_discovery(phba); + goto out; + } + /* Check for retry */ if (lpfc_els_retry(phba, cmdiocb, rspiocb)) goto out; @@ -6076,6 +6182,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto fdisc_failed; } spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_VPORT_CVL_RCVD; vport->fc_flag |= FC_FABRIC; if (vport->phba->fc_topology == TOPOLOGY_LOOP) vport->fc_flag |= FC_PUBLIC_LOOP; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 2445e399fd60..7143d71c501f 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -706,6 +706,8 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) void lpfc_port_link_failure(struct lpfc_vport *vport) { + lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN); + /* Cleanup any outstanding received buffers */ lpfc_cleanup_rcv_buffers(vport); @@ -1695,10 +1697,11 @@ out: * * This function handles completion of init vpi mailbox command. */ -static void +void lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { struct lpfc_vport *vport = mboxq->vport; + struct lpfc_nodelist *ndlp; if (mboxq->u.mb.mbxStatus) { lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, @@ -1712,6 +1715,20 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI; spin_unlock_irq(&phba->hbalock); + /* If this port is physical port or FDISC is done, do reg_vpi */ + if ((phba->pport == vport) || (vport->port_state == LPFC_FDISC)) { + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp) + lpfc_printf_vlog(vport, KERN_ERR, + LOG_DISCOVERY, + "2731 Cannot find fabric " + "controller node\n"); + else + lpfc_register_new_vport(phba, vport, ndlp); + mempool_free(mboxq, phba->mbox_mem_pool); + return; + } + if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) lpfc_initial_fdisc(vport); else { @@ -1719,6 +1736,7 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, "2606 No NPIV Fabric support\n"); } + mempool_free(mboxq, phba->mbox_mem_pool); return; } @@ -1814,6 +1832,9 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) } /* The VPI is implicitly registered when the VFI is registered */ vport->vpi_state |= LPFC_VPI_REGISTERED; + vport->fc_flag |= FC_VFI_REGISTERED; + + vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; if (vport->port_state == LPFC_FABRIC_CFG_LINK) { lpfc_start_fdiscs(phba); @@ -2333,6 +2354,7 @@ lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } vport->vpi_state |= LPFC_VPI_REGISTERED; + vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; vport->num_disc_nodes = 0; /* go thru NPR list and issue ELS PLOGIs */ if (vport->fc_npr_cnt) @@ -4462,6 +4484,7 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba) int rc; struct lpfc_vport **vports; int i; + struct lpfc_nodelist *ndlp; spin_lock_irq(&phba->hbalock); /* @@ -4489,6 +4512,10 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba) if (vports && (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { + /* Stop FLOGI/FDISC retries */ + ndlp = lpfc_findnode_did(vports[i], Fabric_DID); + if (ndlp) + lpfc_cancel_retry_delay_tmo(vports[i], ndlp); lpfc_mbx_unreg_vpi(vports[i]); spin_lock_irq(&phba->hbalock); vports[i]->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; @@ -4497,6 +4524,9 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba) } lpfc_destroy_vport_work_array(phba, vports); + /* Cleanup any outstanding ELS commands */ + lpfc_els_flush_all_cmd(phba); + /* Unregister VFI */ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { @@ -4521,6 +4551,10 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba) return; } + spin_lock_irq(&phba->hbalock); + phba->pport->fc_flag &= ~FC_VFI_REGISTERED; + spin_unlock_irq(&phba->hbalock); + /* Unregister FCF */ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index b8eb1b6e5e77..4d20c4148fae 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -2246,6 +2246,9 @@ lpfc_offline_prep(struct lpfc_hba * phba) if (vports[i]->load_flag & FC_UNLOADING) continue; vports[i]->vpi_state &= ~LPFC_VPI_REGISTERED; + vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + vports[i]->fc_flag &= ~FC_VFI_REGISTERED; + shost = lpfc_shost_from_vport(vports[i]); list_for_each_entry_safe(ndlp, next_ndlp, &vports[i]->fc_nodes, @@ -3007,6 +3010,9 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp; struct Scsi_Host *shost; uint32_t link_state; + int active_vlink_present; + struct lpfc_vport **vports; + int i; phba->fc_eventTag = acqe_fcoe->event_tag; phba->fcoe_eventtag = acqe_fcoe->event_tag; @@ -3074,14 +3080,46 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, if (!ndlp) break; shost = lpfc_shost_from_vport(vport); + if (phba->pport->port_state <= LPFC_FLOGI) + break; + /* If virtual link is not yet instantiated ignore CVL */ + if (vport->port_state <= LPFC_FDISC) + break; + lpfc_linkdown_port(vport); - if (vport->port_type != LPFC_NPIV_PORT) { + lpfc_cleanup_pending_mbox(vport); + spin_lock_irq(shost->host_lock); + vport->fc_flag |= FC_VPORT_CVL_RCVD; + spin_unlock_irq(shost->host_lock); + active_vlink_present = 0; + + vports = lpfc_create_vport_work_array(phba); + if (vports) { + for (i = 0; i <= phba->max_vports && vports[i] != NULL; + i++) { + if ((!(vports[i]->fc_flag & + FC_VPORT_CVL_RCVD)) && + (vports[i]->port_state > LPFC_FDISC)) { + active_vlink_present = 1; + break; + } + } + lpfc_destroy_vport_work_array(phba, vports); + } + + if (active_vlink_present) { + /* + * If there are other active VLinks present, + * re-instantiate the Vlink using FDISC. + */ mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_DELAY_TMO; spin_unlock_irq(shost->host_lock); - ndlp->nlp_last_elscmd = ELS_CMD_FLOGI; - vport->port_state = LPFC_FLOGI; + ndlp->nlp_last_elscmd = ELS_CMD_FDISC; + vport->port_state = LPFC_FDISC; + } else { + lpfc_retry_pport_discovery(phba); } break; default: diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 293234a5a944..d20ae6b3b3cf 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -254,7 +254,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int rc; memset(&stat, 0, sizeof (struct ls_rjt)); - if (vport->port_state <= LPFC_FLOGI) { + if (vport->port_state <= LPFC_FDISC) { /* Before responding to PLOGI, check for pt2pt mode. * If we are pt2pt, with an outstanding FLOGI, abort * the FLOGI and resend it first. diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index dc7c5c1231df..8d666d9fabb4 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1710,6 +1710,7 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct lpfc_dmabuf *mp; uint16_t rpi, vpi; int rc; + struct lpfc_vport *vport = pmb->vport; mp = (struct lpfc_dmabuf *) (pmb->context1); @@ -1738,6 +1739,18 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) return; } + /* Unreg VPI, if the REG_VPI succeed after VLink failure */ + if ((pmb->u.mb.mbxCommand == MBX_REG_VPI) && + !(phba->pport->load_flag & FC_UNLOADING) && + !pmb->u.mb.mbxStatus) { + lpfc_unreg_vpi(phba, pmb->u.mb.un.varRegVpi.vpi, pmb); + pmb->vport = vport; + pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); + if (rc != MBX_NOT_FINISHED) + return; + } + if (bf_get(lpfc_mqe_command, &pmb->u.mqe) == MBX_SLI4_CONFIG) lpfc_sli4_mbox_cmd_free(phba, pmb); else @@ -8440,8 +8453,10 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_hba *phba, wcqe->total_data_placed; else pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; - else + else { pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; + pIocbIn->iocb.un.genreq64.bdl.bdeSize = wcqe->total_data_placed; + } /* Pick up HBA exchange busy condition */ if (bf_get(lpfc_wcqe_c_xb, wcqe)) { @@ -12139,3 +12154,48 @@ out: kfree(rgn23_data); return; } + +/** + * lpfc_cleanup_pending_mbox - Free up vport discovery mailbox commands. + * @vport: pointer to vport data structure. + * + * This function iterate through the mailboxq and clean up all REG_LOGIN + * and REG_VPI mailbox commands associated with the vport. This function + * is called when driver want to restart discovery of the vport due to + * a Clear Virtual Link event. + **/ +void +lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) +{ + struct lpfc_hba *phba = vport->phba; + LPFC_MBOXQ_t *mb, *nextmb; + struct lpfc_dmabuf *mp; + + spin_lock_irq(&phba->hbalock); + list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { + if (mb->vport != vport) + continue; + + if ((mb->u.mb.mbxCommand != MBX_REG_LOGIN64) && + (mb->u.mb.mbxCommand != MBX_REG_VPI)) + continue; + + if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) { + mp = (struct lpfc_dmabuf *) (mb->context1); + if (mp) { + __lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + } + } + list_del(&mb->list); + mempool_free(mb, phba->mbox_mem_pool); + } + mb = phba->sli.mbox_active; + if (mb && (mb->vport == vport)) { + if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) || + (mb->u.mb.mbxCommand == MBX_REG_VPI)) + mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + } + spin_unlock_irq(&phba->hbalock); +} + diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index e3c7fa642306..281ff033a7b2 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -389,7 +389,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) * by the port. */ if ((phba->sli_rev == LPFC_SLI_REV4) && - (pport->vpi_state & LPFC_VPI_REGISTERED)) { + (pport->fc_flag & FC_VFI_REGISTERED)) { rc = lpfc_sli4_init_vpi(phba, vpi); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, -- cgit v1.2.2 From 65467b6bdffd3efde111444663bc9de35b59b22a Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 26 Jan 2010 23:08:29 -0500 Subject: [SCSI] lpfc 8.3.8: Add code to display logical link speed Display Logical Link Speed when supported and is non-zero. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_hw4.h | 3 +++ drivers/scsi/lpfc/lpfc_init.c | 2 ++ drivers/scsi/lpfc/lpfc_scsi.c | 7 +++++++ drivers/scsi/lpfc/lpfc_sli4.h | 1 + 4 files changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 8a2a1c5935c6..c2bec6e6222f 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1959,6 +1959,9 @@ struct lpfc_acqe_link { #define LPFC_ASYNC_LINK_FAULT_NONE 0x0 #define LPFC_ASYNC_LINK_FAULT_LOCAL 0x1 #define LPFC_ASYNC_LINK_FAULT_REMOTE 0x2 +#define lpfc_acqe_qos_link_speed_SHIFT 16 +#define lpfc_acqe_qos_link_speed_MASK 0x0000FFFF +#define lpfc_acqe_qos_link_speed_WORD word1 uint32_t event_tag; uint32_t trailer; }; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 4d20c4148fae..e80e95d95cde 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -2981,6 +2981,8 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba, bf_get(lpfc_acqe_link_physical, acqe_link); phba->sli4_hba.link_state.fault = bf_get(lpfc_acqe_link_fault, acqe_link); + phba->sli4_hba.link_state.logical_speed = + bf_get(lpfc_acqe_qos_link_speed, acqe_link); /* Invoke the lpfc_handle_latt mailbox command callback function */ lpfc_mbx_cmpl_read_la(phba, pmb); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index d5cc6b8d32f2..8f4b90a9d151 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -2701,6 +2701,13 @@ lpfc_info(struct Scsi_Host *host) " port %s", phba->Port); } + len = strlen(lpfcinfobuf); + if (phba->sli4_hba.link_state.logical_speed) { + snprintf(lpfcinfobuf + len, + 384-len, + " Logical Link Speed: %d Mbps", + phba->sli4_hba.link_state.logical_speed * 10); + } } return lpfcinfobuf; } diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 44e5f574236b..2e5e40576864 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -126,6 +126,7 @@ struct lpfc_sli4_link { uint8_t status; uint8_t physical; uint8_t fault; + uint16_t logical_speed; }; struct lpfc_fcf { -- cgit v1.2.2 From 4fede78f7552479c4bb3bab221133ec5244e4154 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 26 Jan 2010 23:08:55 -0500 Subject: [SCSI] lpfc 8.3.8: (BSG1) Update BSG infrastructure Update BSG infrastructure to handle new vendor specific BSG commands. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 6 +++-- drivers/scsi/lpfc/lpfc_bsg.c | 52 ++++++++++++++++++++++++------------------- drivers/scsi/lpfc/lpfc_crtn.h | 4 ++-- drivers/scsi/lpfc/lpfc_ct.c | 8 ++++--- drivers/scsi/lpfc/lpfc_hw.h | 5 ++++- drivers/scsi/lpfc/lpfc_init.c | 4 ++-- drivers/scsi/lpfc/lpfc_nl.h | 22 +----------------- 7 files changed, 47 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 197dc3e3bdc9..a40a45b8aede 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2009 Emulex. All rights reserved. * + * Copyright (C) 2004-2010 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -451,6 +451,8 @@ struct unsol_rcv_ct_ctx { uint32_t ctxt_id; uint32_t SID; uint32_t oxid; + uint32_t flags; +#define UNSOL_VALID 0x00000001 }; struct lpfc_hba { @@ -793,7 +795,7 @@ struct lpfc_hba { uint16_t vlan_id; struct list_head fcf_conn_rec_list; - struct mutex ct_event_mutex; /* synchronize access to ct_ev_waiters */ + spinlock_t ct_ev_lock; /* synchronize access to ct_ev_waiters */ struct list_head ct_ev_waiters; struct unsol_rcv_ct_ctx ct_ctx[64]; uint32_t ctx_idx; diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index a5d9048235d9..dfb1f73252a1 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2009 Emulex. All rights reserved. * + * Copyright (C) 2009-2010 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -33,6 +33,7 @@ #include "lpfc_sli.h" #include "lpfc_sli4.h" #include "lpfc_nl.h" +#include "lpfc_bsg.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" #include "lpfc.h" @@ -476,7 +477,7 @@ enum ELX_LOOPBACK_CMD { * This function is called when an unsolicited CT command is received. It * forwards the event to any processes registerd to receive CT events. */ -void +int lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocbq) { @@ -496,6 +497,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; struct lpfc_hbq_entry *hbqe; struct lpfc_sli_ct_request *ct_req; + unsigned long flags; INIT_LIST_HEAD(&head); list_add_tail(&head, &piocbq->list); @@ -519,7 +521,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) lpfc_sli_ringpostbuf_put(phba, pring, dmabuf); - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, flags); list_for_each_entry(evt, &phba->ct_ev_waiters, node) { if (evt->req_id != evt_req_id) continue; @@ -535,7 +537,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; } - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { /* take accumulated byte count from the last iocbq */ @@ -556,9 +558,9 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, "CT event data, size %d\n", evt_dat->len); kfree(evt_dat); - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, flags); lpfc_ct_event_unref(evt); - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); goto error_ct_unsol_exit; } @@ -601,9 +603,11 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, iocbq); kfree(evt_dat->data); kfree(evt_dat); - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, + flags); lpfc_ct_event_unref(evt); - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore( + &phba->ct_ev_lock, flags); goto error_ct_unsol_exit; } memcpy((char *)(evt_dat->data) + offset, @@ -638,7 +642,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } } - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, flags); if (phba->sli_rev == LPFC_SLI_REV4) { evt_dat->immed_dat = phba->ctx_idx; phba->ctx_idx = (phba->ctx_idx + 1) % 64; @@ -656,13 +660,13 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (evt_req_id == SLI_CT_ELX_LOOPBACK) break; } - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); error_ct_unsol_exit: if (!list_empty(&head)) list_del(&head); - return; + return 1; } /** @@ -676,6 +680,7 @@ lpfc_bsg_set_event(struct fc_bsg_job *job) struct lpfc_hba *phba = vport->phba; struct set_ct_event *event_req; struct lpfc_ct_event *evt; + unsigned long flags; int rc = 0; if (job->request_len < @@ -689,7 +694,7 @@ lpfc_bsg_set_event(struct fc_bsg_job *job) event_req = (struct set_ct_event *) job->request->rqst_data.h_vendor.vendor_cmd; - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, flags); list_for_each_entry(evt, &phba->ct_ev_waiters, node) { if (evt->reg_id == event_req->ev_reg_id) { lpfc_ct_event_ref(evt); @@ -697,7 +702,7 @@ lpfc_bsg_set_event(struct fc_bsg_job *job) break; } } - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); if (&evt->node == &phba->ct_ev_waiters) { /* no event waiting struct yet - first call */ @@ -710,19 +715,19 @@ lpfc_bsg_set_event(struct fc_bsg_job *job) return -ENOMEM; } - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, flags); list_add(&evt->node, &phba->ct_ev_waiters); lpfc_ct_event_ref(evt); - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); } evt->waiting = 1; if (wait_event_interruptible(evt->wq, !list_empty(&evt->events_to_see))) { - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, flags); lpfc_ct_event_unref(evt); /* release ref */ lpfc_ct_event_unref(evt); /* delete */ - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); rc = -EINTR; goto set_event_out; } @@ -730,10 +735,10 @@ lpfc_bsg_set_event(struct fc_bsg_job *job) evt->wait_time_stamp = jiffies; evt->waiting = 0; - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, flags); list_move(evt->events_to_see.prev, &evt->events_to_get); lpfc_ct_event_unref(evt); /* release ref */ - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); set_event_out: /* set_event carries no reply payload */ @@ -759,6 +764,7 @@ lpfc_bsg_get_event(struct fc_bsg_job *job) struct get_ct_event_reply *event_reply; struct lpfc_ct_event *evt; struct event_data *evt_dat = NULL; + unsigned long flags; int rc = 0; if (job->request_len < @@ -775,7 +781,7 @@ lpfc_bsg_get_event(struct fc_bsg_job *job) event_reply = (struct get_ct_event_reply *) job->reply->reply_data.vendor_reply.vendor_rsp; - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, flags); list_for_each_entry(evt, &phba->ct_ev_waiters, node) { if (evt->reg_id == event_req->ev_reg_id) { if (list_empty(&evt->events_to_get)) @@ -788,7 +794,7 @@ lpfc_bsg_get_event(struct fc_bsg_job *job) break; } } - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); if (!evt_dat) { job->reply->reply_payload_rcv_len = 0; @@ -818,9 +824,9 @@ lpfc_bsg_get_event(struct fc_bsg_job *job) if (evt_dat) kfree(evt_dat->data); kfree(evt_dat); - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, flags); lpfc_ct_event_unref(evt); - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); error_get_event_exit: /* make error code available to userspace */ diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index b9e8cd5b818a..107899dc3f3e 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2008 Emulex. All rights reserved. * + * Copyright (C) 2004-2010 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -383,5 +383,5 @@ struct lpfc_vport *lpfc_find_vport_by_vpid(struct lpfc_hba *, uint16_t); /* functions to support SGIOv4/bsg interface */ int lpfc_bsg_request(struct fc_bsg_job *); int lpfc_bsg_timeout(struct fc_bsg_job *); -void lpfc_bsg_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, +int lpfc_bsg_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_iocbq *); diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index bf7bf62e81eb..c7e921973f66 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2009 Emulex. All rights reserved. * + * Copyright (C) 2004-2010 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -97,7 +97,8 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct list_head head; struct lpfc_dmabuf *bdeBuf; - lpfc_bsg_ct_unsol_event(phba, pring, piocbq); + if (lpfc_bsg_ct_unsol_event(phba, pring, piocbq) == 0) + return; if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) { lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); @@ -181,7 +182,8 @@ lpfc_sli4_ct_abort_unsol_event(struct lpfc_hba *phba, uint32_t size; /* Forward abort event to any process registered to receive ct event */ - lpfc_bsg_ct_unsol_event(phba, pring, piocbq); + if (lpfc_bsg_ct_unsol_event(phba, pring, piocbq) == 0) + return; /* If there is no BDE associated with IOCB, there is nothing to do */ if (icmd->ulpBdeCount == 0) diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 44c258730b07..89ff7c09e298 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2009 Emulex. All rights reserved. * + * Copyright (C) 2004-2010 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -1346,6 +1346,9 @@ typedef struct { /* FireFly BIU registers */ #define MBX_HEARTBEAT 0x31 #define MBX_WRITE_VPARMS 0x32 #define MBX_ASYNCEVT_ENABLE 0x33 +#define MBX_READ_EVENT_LOG_STATUS 0x37 +#define MBX_READ_EVENT_LOG 0x38 +#define MBX_WRITE_EVENT_LOG 0x39 #define MBX_PORT_CAPABILITIES 0x3B #define MBX_PORT_IOV_CONTROL 0x3C diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index e80e95d95cde..52fc758b8f77 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2009 Emulex. All rights reserved. * + * Copyright (C) 2004-2010 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -4331,7 +4331,7 @@ lpfc_hba_alloc(struct pci_dev *pdev) return NULL; } - mutex_init(&phba->ct_event_mutex); + spin_lock_init(&phba->ct_ev_lock); INIT_LIST_HEAD(&phba->ct_ev_waiters); return phba; diff --git a/drivers/scsi/lpfc/lpfc_nl.h b/drivers/scsi/lpfc/lpfc_nl.h index d655ed3eebef..f3cfbe2ce986 100644 --- a/drivers/scsi/lpfc/lpfc_nl.h +++ b/drivers/scsi/lpfc/lpfc_nl.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2008 Emulex. All rights reserved. * + * Copyright (C) 2010 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -177,23 +177,3 @@ struct temp_event { uint32_t data; }; -/* bsg definitions */ -#define LPFC_BSG_VENDOR_SET_CT_EVENT 1 -#define LPFC_BSG_VENDOR_GET_CT_EVENT 2 - -struct set_ct_event { - uint32_t command; - uint32_t ev_req_id; - uint32_t ev_reg_id; -}; - -struct get_ct_event { - uint32_t command; - uint32_t ev_reg_id; - uint32_t ev_req_id; -}; - -struct get_ct_event_reply { - uint32_t immed_data; - uint32_t type; -}; -- cgit v1.2.2 From c79c1292df87fa9c63383ca551fa719c0c2fda7c Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 26 Jan 2010 23:09:22 -0500 Subject: [SCSI] lpfc 8.3.8: (BSG2) Create lpfc_bsg.h Create lpfc_bsg.h - structures, etc used by bsg-related routines. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_bsg.h | 98 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 drivers/scsi/lpfc/lpfc_bsg.h (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h new file mode 100644 index 000000000000..6c8f87e39b98 --- /dev/null +++ b/drivers/scsi/lpfc/lpfc_bsg.h @@ -0,0 +1,98 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * + * Copyright (C) 2010 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of version 2 of the GNU General * + * Public License as published by the Free Software Foundation. * + * This program is distributed in the hope that it will be useful. * + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * + * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * + * TO BE LEGALLY INVALID. See the GNU General Public License for * + * more details, a copy of which can be found in the file COPYING * + * included with this package. * + *******************************************************************/ +/* bsg definitions + * No pointers to user data are allowed, all application buffers and sizes will + * derived through the bsg interface. + * + * These are the vendor unique structures passed in using the bsg + * FC_BSG_HST_VENDOR message code type. + */ +#define LPFC_BSG_VENDOR_SET_CT_EVENT 1 +#define LPFC_BSG_VENDOR_GET_CT_EVENT 2 +#define LPFC_BSG_VENDOR_SEND_MGMT_RESP 3 +#define LPFC_BSG_VENDOR_DIAG_MODE 4 +#define LPFC_BSG_VENDOR_DIAG_TEST 5 +#define LPFC_BSG_VENDOR_GET_MGMT_REV 6 +#define LPFC_BSG_VENDOR_MBOX 7 + +struct set_ct_event { + uint32_t command; + uint32_t type_mask; + uint32_t ev_req_id; + uint32_t ev_reg_id; +}; + +struct get_ct_event { + uint32_t command; + uint32_t ev_reg_id; + uint32_t ev_req_id; +}; + +struct get_ct_event_reply { + uint32_t immed_data; + uint32_t type; +}; + +struct send_mgmt_resp { + uint32_t command; + uint32_t tag; +}; + + +#define INTERNAL_LOOP_BACK 0x1 /* adapter short cuts the loop internally */ +#define EXTERNAL_LOOP_BACK 0x2 /* requires an external loopback plug */ + +struct diag_mode_set { + uint32_t command; + uint32_t type; + uint32_t timeout; +}; + +struct diag_mode_test { + uint32_t command; +}; + +#define LPFC_WWNN_TYPE 0 +#define LPFC_WWPN_TYPE 1 + +struct get_mgmt_rev { + uint32_t command; +}; + +#define MANAGEMENT_MAJOR_REV 1 +#define MANAGEMENT_MINOR_REV 0 + +/* the MgmtRevInfo structure */ +struct MgmtRevInfo { + uint32_t a_Major; + uint32_t a_Minor; +}; + +struct get_mgmt_rev_reply { + struct MgmtRevInfo info; +}; + +struct dfc_mbox_req { + uint32_t command; + uint32_t inExtWLen; + uint32_t outExtWLen; + uint8_t mbOffset; +}; + -- cgit v1.2.2 From 4cc0e56e977f12e6f400cbab3df7cf1e11d6f58a Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 26 Jan 2010 23:09:48 -0500 Subject: [SCSI] lpfc 8.3.8: (BSG3) Modify BSG commands to operate asynchronously Modify the following BSG commands to operate asynchronously. - FC_BSG_RPT_ELS - FC_BSG_RPT_CT - LPFC_BSG_VENDOR_GET_CT_EVENT - LPFC_BSG_VENDOR_SET_CT_EVENT Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_bsg.c | 863 +++++++++++++++++++++++++++++-------------- 1 file changed, 592 insertions(+), 271 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index dfb1f73252a1..a7e8921015eb 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -42,14 +42,169 @@ #include "lpfc_vport.h" #include "lpfc_version.h" +struct lpfc_bsg_event { + struct list_head node; + struct kref kref; + wait_queue_head_t wq; + + /* Event type and waiter identifiers */ + uint32_t type_mask; + uint32_t req_id; + uint32_t reg_id; + + /* next two flags are here for the auto-delete logic */ + unsigned long wait_time_stamp; + int waiting; + + /* seen and not seen events */ + struct list_head events_to_get; + struct list_head events_to_see; + + /* job waiting for this event to finish */ + struct fc_bsg_job *set_job; +}; + +struct lpfc_bsg_iocb { + struct lpfc_iocbq *cmdiocbq; + struct lpfc_iocbq *rspiocbq; + struct lpfc_dmabuf *bmp; + struct lpfc_nodelist *ndlp; + + /* job waiting for this iocb to finish */ + struct fc_bsg_job *set_job; +}; + +#define TYPE_EVT 1 +#define TYPE_IOCB 2 +struct bsg_job_data { + uint32_t type; + union { + struct lpfc_bsg_event *evt; + struct lpfc_bsg_iocb iocb; + } context_un; +}; + +struct event_data { + struct list_head node; + uint32_t type; + uint32_t immed_dat; + void *data; + uint32_t len; +}; + +#define SLI_CT_ELX_LOOPBACK 0x10 + +enum ELX_LOOPBACK_CMD { + ELX_LOOPBACK_XRI_SETUP, + ELX_LOOPBACK_DATA, +}; + +struct lpfc_dmabufext { + struct lpfc_dmabuf dma; + uint32_t size; + uint32_t flag; +}; + +/** + * lpfc_bsg_send_mgmt_cmd_cmp - lpfc_bsg_send_mgmt_cmd's completion handler + * @phba: Pointer to HBA context object. + * @cmdiocbq: Pointer to command iocb. + * @rspiocbq: Pointer to response iocb. + * + * This function is the completion handler for iocbs issued using + * lpfc_bsg_send_mgmt_cmd function. This function is called by the + * ring event handler function without any lock held. This function + * can be called from both worker thread context and interrupt + * context. This function also can be called from another thread which + * cleans up the SLI layer objects. + * This function copies the contents of the response iocb to the + * response iocb memory object provided by the caller of + * lpfc_sli_issue_iocb_wait and then wakes up the thread which + * sleeps for the iocb completion. + **/ +static void +lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdiocbq, + struct lpfc_iocbq *rspiocbq) +{ + unsigned long iflags; + struct bsg_job_data *dd_data; + struct fc_bsg_job *job; + IOCB_t *rsp; + struct lpfc_dmabuf *bmp; + struct lpfc_nodelist *ndlp; + struct lpfc_bsg_iocb *iocb; + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&phba->ct_ev_lock, flags); + dd_data = cmdiocbq->context1; + if (!dd_data) { + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + return; + } + + iocb = &dd_data->context_un.iocb; + job = iocb->set_job; + job->dd_data = NULL; /* so timeout handler does not reply */ + + spin_lock_irqsave(&phba->hbalock, iflags); + cmdiocbq->iocb_flag |= LPFC_IO_WAKE; + if (cmdiocbq->context2 && rspiocbq) + memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb, + &rspiocbq->iocb, sizeof(IOCB_t)); + spin_unlock_irqrestore(&phba->hbalock, iflags); + + bmp = iocb->bmp; + rspiocbq = iocb->rspiocbq; + rsp = &rspiocbq->iocb; + ndlp = iocb->ndlp; + + pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, + job->request_payload.sg_cnt, DMA_TO_DEVICE); + pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, + job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + + if (rsp->ulpStatus) { + if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { + switch (rsp->un.ulpWord[4] & 0xff) { + case IOERR_SEQUENCE_TIMEOUT: + rc = -ETIMEDOUT; + break; + case IOERR_INVALID_RPI: + rc = -EFAULT; + break; + default: + rc = -EACCES; + break; + } + } else + rc = -EACCES; + } else + job->reply->reply_payload_rcv_len = + rsp->un.genreq64.bdl.bdeSize; + + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); + lpfc_sli_release_iocbq(phba, rspiocbq); + lpfc_sli_release_iocbq(phba, cmdiocbq); + lpfc_nlp_put(ndlp); + kfree(bmp); + kfree(dd_data); + /* make error code available to userspace */ + job->reply->result = rc; + /* complete the job back to userspace */ + job->job_done(job); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + return; +} + /** - * lpfc_bsg_rport_ct - send a CT command from a bsg request + * lpfc_bsg_send_mgmt_cmd - send a CT command from a bsg request * @job: fc_bsg_job to handle */ static int -lpfc_bsg_rport_ct(struct fc_bsg_job *job) +lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job) { - struct Scsi_Host *shost = job->shost; struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; struct lpfc_hba *phba = vport->phba; struct lpfc_rport_data *rdata = job->rport->dd_data; @@ -66,57 +221,60 @@ lpfc_bsg_rport_ct(struct fc_bsg_job *job) struct scatterlist *sgel = NULL; int numbde; dma_addr_t busaddr; + struct bsg_job_data *dd_data; + uint32_t creg_val; int rc = 0; /* in case no data is transferred */ job->reply->reply_payload_rcv_len = 0; + /* allocate our bsg tracking structure */ + dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); + if (!dd_data) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2733 Failed allocation of dd_data\n"); + rc = -ENOMEM; + goto no_dd_data; + } + if (!lpfc_nlp_get(ndlp)) { - job->reply->result = -ENODEV; - return 0; + rc = -ENODEV; + goto no_ndlp; + } + + bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!bmp) { + rc = -ENOMEM; + goto free_ndlp; } if (ndlp->nlp_flag & NLP_ELS_SND_MASK) { rc = -ENODEV; - goto free_ndlp_exit; + goto free_bmp; } - spin_lock_irq(shost->host_lock); cmdiocbq = lpfc_sli_get_iocbq(phba); if (!cmdiocbq) { rc = -ENOMEM; - spin_unlock_irq(shost->host_lock); - goto free_ndlp_exit; + goto free_bmp; } - cmd = &cmdiocbq->iocb; + cmd = &cmdiocbq->iocb; rspiocbq = lpfc_sli_get_iocbq(phba); if (!rspiocbq) { rc = -ENOMEM; goto free_cmdiocbq; } - spin_unlock_irq(shost->host_lock); rsp = &rspiocbq->iocb; - - bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!bmp) { - rc = -ENOMEM; - spin_lock_irq(shost->host_lock); - goto free_rspiocbq; - } - - spin_lock_irq(shost->host_lock); bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); if (!bmp->virt) { rc = -ENOMEM; - goto free_bmp; + goto free_rspiocbq; } - spin_unlock_irq(shost->host_lock); INIT_LIST_HEAD(&bmp->list); bpl = (struct ulp_bde64 *) bmp->virt; - request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, job->request_payload.sg_cnt, DMA_TO_DEVICE); for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { @@ -158,72 +316,146 @@ lpfc_bsg_rport_ct(struct fc_bsg_job *job) cmd->ulpContext = ndlp->nlp_rpi; cmd->ulpOwner = OWN_CHIP; cmdiocbq->vport = phba->pport; - cmdiocbq->context1 = NULL; - cmdiocbq->context2 = NULL; + cmdiocbq->context3 = bmp; cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; - timeout = phba->fc_ratov * 2; - job->dd_data = cmdiocbq; - - rc = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, rspiocbq, - timeout + LPFC_DRVR_TIMEOUT); - - if (rc != IOCB_TIMEDOUT) { - pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, - job->request_payload.sg_cnt, DMA_TO_DEVICE); - pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, - job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + cmd->ulpTimeout = timeout; + + cmdiocbq->iocb_cmpl = lpfc_bsg_send_mgmt_cmd_cmp; + cmdiocbq->context1 = dd_data; + cmdiocbq->context2 = rspiocbq; + dd_data->type = TYPE_IOCB; + dd_data->context_un.iocb.cmdiocbq = cmdiocbq; + dd_data->context_un.iocb.rspiocbq = rspiocbq; + dd_data->context_un.iocb.set_job = job; + dd_data->context_un.iocb.bmp = bmp; + dd_data->context_un.iocb.ndlp = ndlp; + + if (phba->cfg_poll & DISABLE_FCP_RING_INT) { + creg_val = readl(phba->HCregaddr); + creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); + writel(creg_val, phba->HCregaddr); + readl(phba->HCregaddr); /* flush */ } - if (rc == IOCB_TIMEDOUT) { - lpfc_sli_release_iocbq(phba, rspiocbq); - rc = -EACCES; - goto free_ndlp_exit; - } + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); - if (rc != IOCB_SUCCESS) { - rc = -EACCES; - goto free_outdmp; - } + if (rc == IOCB_SUCCESS) + return 0; /* done for now */ - if (rsp->ulpStatus) { - if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { - switch (rsp->un.ulpWord[4] & 0xff) { - case IOERR_SEQUENCE_TIMEOUT: - rc = -ETIMEDOUT; - break; - case IOERR_INVALID_RPI: - rc = -EFAULT; - break; - default: - rc = -EACCES; - break; - } - goto free_outdmp; - } - } else - job->reply->reply_payload_rcv_len = - rsp->un.genreq64.bdl.bdeSize; + /* iocb failed so cleanup */ + pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, + job->request_payload.sg_cnt, DMA_TO_DEVICE); + pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, + job->reply_payload.sg_cnt, DMA_FROM_DEVICE); -free_outdmp: - spin_lock_irq(shost->host_lock); lpfc_mbuf_free(phba, bmp->virt, bmp->phys); -free_bmp: - kfree(bmp); + free_rspiocbq: lpfc_sli_release_iocbq(phba, rspiocbq); free_cmdiocbq: lpfc_sli_release_iocbq(phba, cmdiocbq); - spin_unlock_irq(shost->host_lock); -free_ndlp_exit: +free_bmp: + kfree(bmp); +free_ndlp: lpfc_nlp_put(ndlp); +no_ndlp: + kfree(dd_data); +no_dd_data: + /* make error code available to userspace */ + job->reply->result = rc; + job->dd_data = NULL; + return rc; +} + +/** + * lpfc_bsg_rport_els_cmp - lpfc_bsg_rport_els's completion handler + * @phba: Pointer to HBA context object. + * @cmdiocbq: Pointer to command iocb. + * @rspiocbq: Pointer to response iocb. + * + * This function is the completion handler for iocbs issued using + * lpfc_bsg_rport_els_cmp function. This function is called by the + * ring event handler function without any lock held. This function + * can be called from both worker thread context and interrupt + * context. This function also can be called from other thread which + * cleans up the SLI layer objects. + * This function copy the contents of the response iocb to the + * response iocb memory object provided by the caller of + * lpfc_sli_issue_iocb_wait and then wakes up the thread which + * sleeps for the iocb completion. + **/ +static void +lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdiocbq, + struct lpfc_iocbq *rspiocbq) +{ + struct bsg_job_data *dd_data; + struct fc_bsg_job *job; + IOCB_t *rsp; + struct lpfc_nodelist *ndlp; + struct lpfc_dmabuf *pbuflist = NULL; + struct fc_bsg_ctels_reply *els_reply; + uint8_t *rjt_data; + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&phba->ct_ev_lock, flags); + dd_data = cmdiocbq->context1; + /* normal completion and timeout crossed paths, already done */ + if (!dd_data) { + spin_unlock_irqrestore(&phba->hbalock, flags); + return; + } + + cmdiocbq->iocb_flag |= LPFC_IO_WAKE; + if (cmdiocbq->context2 && rspiocbq) + memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb, + &rspiocbq->iocb, sizeof(IOCB_t)); + + job = dd_data->context_un.iocb.set_job; + cmdiocbq = dd_data->context_un.iocb.cmdiocbq; + rspiocbq = dd_data->context_un.iocb.rspiocbq; + rsp = &rspiocbq->iocb; + ndlp = dd_data->context_un.iocb.ndlp; + + pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, + job->request_payload.sg_cnt, DMA_TO_DEVICE); + pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, + job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + + if (job->reply->result == -EAGAIN) + rc = -EAGAIN; + else if (rsp->ulpStatus == IOSTAT_SUCCESS) + job->reply->reply_payload_rcv_len = + rsp->un.elsreq64.bdl.bdeSize; + else if (rsp->ulpStatus == IOSTAT_LS_RJT) { + job->reply->reply_payload_rcv_len = + sizeof(struct fc_bsg_ctels_reply); + /* LS_RJT data returned in word 4 */ + rjt_data = (uint8_t *)&rsp->un.ulpWord[4]; + els_reply = &job->reply->reply_data.ctels_reply; + els_reply->status = FC_CTELS_STATUS_REJECT; + els_reply->rjt_data.action = rjt_data[3]; + els_reply->rjt_data.reason_code = rjt_data[2]; + els_reply->rjt_data.reason_explanation = rjt_data[1]; + els_reply->rjt_data.vendor_unique = rjt_data[0]; + } else + rc = -EIO; + pbuflist = (struct lpfc_dmabuf *) cmdiocbq->context3; + lpfc_mbuf_free(phba, pbuflist->virt, pbuflist->phys); + lpfc_sli_release_iocbq(phba, rspiocbq); + lpfc_sli_release_iocbq(phba, cmdiocbq); + lpfc_nlp_put(ndlp); + kfree(dd_data); /* make error code available to userspace */ job->reply->result = rc; + job->dd_data = NULL; /* complete the job back to userspace */ job->job_done(job); - - return 0; + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + return; } /** @@ -237,7 +469,6 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) struct lpfc_hba *phba = vport->phba; struct lpfc_rport_data *rdata = job->rport->dd_data; struct lpfc_nodelist *ndlp = rdata->pnode; - uint32_t elscmd; uint32_t cmdsize; uint32_t rspsize; @@ -249,20 +480,30 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) struct lpfc_dmabuf *prsp; struct lpfc_dmabuf *pbuflist = NULL; struct ulp_bde64 *bpl; - int iocb_status; int request_nseg; int reply_nseg; struct scatterlist *sgel = NULL; int numbde; dma_addr_t busaddr; + struct bsg_job_data *dd_data; + uint32_t creg_val; int rc = 0; /* in case no data is transferred */ job->reply->reply_payload_rcv_len = 0; + /* allocate our bsg tracking structure */ + dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); + if (!dd_data) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2735 Failed allocation of dd_data\n"); + rc = -ENOMEM; + goto no_dd_data; + } + if (!lpfc_nlp_get(ndlp)) { rc = -ENODEV; - goto out; + goto free_dd_data; } elscmd = job->request->rqst_data.r_els.els_code; @@ -272,24 +513,24 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) if (!rspiocbq) { lpfc_nlp_put(ndlp); rc = -ENOMEM; - goto out; + goto free_dd_data; } rsp = &rspiocbq->iocb; rpi = ndlp->nlp_rpi; - cmdiocbq = lpfc_prep_els_iocb(phba->pport, 1, cmdsize, 0, ndlp, + cmdiocbq = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, ndlp->nlp_DID, elscmd); - if (!cmdiocbq) { - lpfc_sli_release_iocbq(phba, rspiocbq); - return -EIO; + rc = -EIO; + goto free_rspiocbq; } - job->dd_data = cmdiocbq; + /* prep els iocb set context1 to the ndlp, context2 to the command + * dmabuf, context3 holds the data dmabuf + */ pcmd = (struct lpfc_dmabuf *) cmdiocbq->context2; prsp = (struct lpfc_dmabuf *) pcmd->list.next; - lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); kfree(pcmd); lpfc_mbuf_free(phba, prsp->virt, prsp->phys); @@ -301,7 +542,6 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, job->request_payload.sg_cnt, DMA_TO_DEVICE); - for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { busaddr = sg_dma_address(sgel); bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; @@ -323,7 +563,6 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); bpl++; } - cmdiocbq->iocb.un.elsreq64.bdl.bdeSize = (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); cmdiocbq->iocb.ulpContext = rpi; @@ -331,102 +570,54 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) cmdiocbq->context1 = NULL; cmdiocbq->context2 = NULL; - iocb_status = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, - rspiocbq, (phba->fc_ratov * 2) - + LPFC_DRVR_TIMEOUT); - - /* release the new ndlp once the iocb completes */ + cmdiocbq->iocb_cmpl = lpfc_bsg_rport_els_cmp; + cmdiocbq->context1 = dd_data; + cmdiocbq->context2 = rspiocbq; + dd_data->type = TYPE_IOCB; + dd_data->context_un.iocb.cmdiocbq = cmdiocbq; + dd_data->context_un.iocb.rspiocbq = rspiocbq; + dd_data->context_un.iocb.set_job = job; + dd_data->context_un.iocb.bmp = NULL;; + dd_data->context_un.iocb.ndlp = ndlp; + + if (phba->cfg_poll & DISABLE_FCP_RING_INT) { + creg_val = readl(phba->HCregaddr); + creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); + writel(creg_val, phba->HCregaddr); + readl(phba->HCregaddr); /* flush */ + } + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); lpfc_nlp_put(ndlp); - if (iocb_status != IOCB_TIMEDOUT) { - pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, - job->request_payload.sg_cnt, DMA_TO_DEVICE); - pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, - job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - } - - if (iocb_status == IOCB_SUCCESS) { - if (rsp->ulpStatus == IOSTAT_SUCCESS) { - job->reply->reply_payload_rcv_len = - rsp->un.elsreq64.bdl.bdeSize; - rc = 0; - } else if (rsp->ulpStatus == IOSTAT_LS_RJT) { - struct fc_bsg_ctels_reply *els_reply; - /* LS_RJT data returned in word 4 */ - uint8_t *rjt_data = (uint8_t *)&rsp->un.ulpWord[4]; - - els_reply = &job->reply->reply_data.ctels_reply; - job->reply->result = 0; - els_reply->status = FC_CTELS_STATUS_REJECT; - els_reply->rjt_data.action = rjt_data[0]; - els_reply->rjt_data.reason_code = rjt_data[1]; - els_reply->rjt_data.reason_explanation = rjt_data[2]; - els_reply->rjt_data.vendor_unique = rjt_data[3]; - } else - rc = -EIO; - } else - rc = -EIO; - - if (iocb_status != IOCB_TIMEDOUT) - lpfc_els_free_iocb(phba, cmdiocbq); - - lpfc_sli_release_iocbq(phba, rspiocbq); - -out: - /* make error code available to userspace */ - job->reply->result = rc; - /* complete the job back to userspace */ - job->job_done(job); - - return 0; -} - -struct lpfc_ct_event { - struct list_head node; - int ref; - wait_queue_head_t wq; - - /* Event type and waiter identifiers */ - uint32_t type_mask; - uint32_t req_id; - uint32_t reg_id; + if (rc == IOCB_SUCCESS) + return 0; /* done for now */ - /* next two flags are here for the auto-delete logic */ - unsigned long wait_time_stamp; - int waiting; + pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, + job->request_payload.sg_cnt, DMA_TO_DEVICE); + pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, + job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - /* seen and not seen events */ - struct list_head events_to_get; - struct list_head events_to_see; -}; + lpfc_mbuf_free(phba, pbuflist->virt, pbuflist->phys); -struct event_data { - struct list_head node; - uint32_t type; - uint32_t immed_dat; - void *data; - uint32_t len; -}; + lpfc_sli_release_iocbq(phba, cmdiocbq); -static struct lpfc_ct_event * -lpfc_ct_event_new(int ev_reg_id, uint32_t ev_req_id) -{ - struct lpfc_ct_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL); - if (!evt) - return NULL; +free_rspiocbq: + lpfc_sli_release_iocbq(phba, rspiocbq); - INIT_LIST_HEAD(&evt->events_to_get); - INIT_LIST_HEAD(&evt->events_to_see); - evt->req_id = ev_req_id; - evt->reg_id = ev_reg_id; - evt->wait_time_stamp = jiffies; - init_waitqueue_head(&evt->wq); +free_dd_data: + kfree(dd_data); - return evt; +no_dd_data: + /* make error code available to userspace */ + job->reply->result = rc; + job->dd_data = NULL; + return rc; } static void -lpfc_ct_event_free(struct lpfc_ct_event *evt) +lpfc_bsg_event_free(struct kref *kref) { + struct lpfc_bsg_event *evt = container_of(kref, struct lpfc_bsg_event, + kref); struct event_data *ed; list_del(&evt->node); @@ -449,24 +640,62 @@ lpfc_ct_event_free(struct lpfc_ct_event *evt) } static inline void -lpfc_ct_event_ref(struct lpfc_ct_event *evt) +lpfc_bsg_event_ref(struct lpfc_bsg_event *evt) { - evt->ref++; + kref_get(&evt->kref); } static inline void -lpfc_ct_event_unref(struct lpfc_ct_event *evt) +lpfc_bsg_event_unref(struct lpfc_bsg_event *evt) { - if (--evt->ref < 0) - lpfc_ct_event_free(evt); + kref_put(&evt->kref, lpfc_bsg_event_free); } -#define SLI_CT_ELX_LOOPBACK 0x10 +static struct lpfc_bsg_event * +lpfc_bsg_event_new(uint32_t ev_mask, int ev_reg_id, uint32_t ev_req_id) +{ + struct lpfc_bsg_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL); -enum ELX_LOOPBACK_CMD { - ELX_LOOPBACK_XRI_SETUP, - ELX_LOOPBACK_DATA, -}; + if (!evt) + return NULL; + + INIT_LIST_HEAD(&evt->events_to_get); + INIT_LIST_HEAD(&evt->events_to_see); + evt->type_mask = ev_mask; + evt->req_id = ev_req_id; + evt->reg_id = ev_reg_id; + evt->wait_time_stamp = jiffies; + init_waitqueue_head(&evt->wq); + kref_init(&evt->kref); + return evt; +} + +static int +dfc_cmd_data_free(struct lpfc_hba *phba, struct lpfc_dmabufext *mlist) +{ + struct lpfc_dmabufext *mlast; + struct pci_dev *pcidev; + struct list_head head, *curr, *next; + + if ((!mlist) || (!lpfc_is_link_up(phba) && + (phba->link_flag & LS_LOOPBACK_MODE))) { + return 0; + } + + pcidev = phba->pcidev; + list_add_tail(&head, &mlist->dma.list); + + list_for_each_safe(curr, next, &head) { + mlast = list_entry(curr, struct lpfc_dmabufext , dma.list); + if (mlast->dma.virt) + dma_free_coherent(&pcidev->dev, + mlast->size, + mlast->dma.virt, + mlast->dma.phys); + kfree(mlast); + } + return 0; +} /** * lpfc_bsg_ct_unsol_event - process an unsolicited CT command @@ -475,7 +704,7 @@ enum ELX_LOOPBACK_CMD { * @piocbq: * * This function is called when an unsolicited CT command is received. It - * forwards the event to any processes registerd to receive CT events. + * forwards the event to any processes registered to receive CT events. */ int lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, @@ -485,7 +714,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, uint32_t cmd; uint32_t len; struct lpfc_dmabuf *dmabuf = NULL; - struct lpfc_ct_event *evt; + struct lpfc_bsg_event *evt; struct event_data *evt_dat = NULL; struct lpfc_iocbq *iocbq; size_t offset = 0; @@ -497,7 +726,9 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; struct lpfc_hbq_entry *hbqe; struct lpfc_sli_ct_request *ct_req; + struct fc_bsg_job *job = NULL; unsigned long flags; + int size = 0; INIT_LIST_HEAD(&head); list_add_tail(&head, &piocbq->list); @@ -506,6 +737,10 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0) goto error_ct_unsol_exit; + if (phba->link_state == LPFC_HBA_ERROR || + (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) + goto error_ct_unsol_exit; + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) dmabuf = bdeBuf1; else { @@ -513,7 +748,8 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, piocbq->iocb.un.cont64[0].addrLow); dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, dma_addr); } - + if (dmabuf == NULL) + goto error_ct_unsol_exit; ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt; evt_req_id = ct_req->FsType; cmd = ct_req->CommandResponse.bits.CmdRsp; @@ -523,22 +759,22 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, spin_lock_irqsave(&phba->ct_ev_lock, flags); list_for_each_entry(evt, &phba->ct_ev_waiters, node) { - if (evt->req_id != evt_req_id) + if (!(evt->type_mask & FC_REG_CT_EVENT) || + evt->req_id != evt_req_id) continue; - lpfc_ct_event_ref(evt); - + lpfc_bsg_event_ref(evt); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); evt_dat = kzalloc(sizeof(*evt_dat), GFP_KERNEL); - if (!evt_dat) { - lpfc_ct_event_unref(evt); + if (evt_dat == NULL) { + spin_lock_irqsave(&phba->ct_ev_lock, flags); + lpfc_bsg_event_unref(evt); lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2614 Memory allocation failed for " "CT event\n"); break; } - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { /* take accumulated byte count from the last iocbq */ iocbq = list_entry(head.prev, typeof(*iocbq), list); @@ -552,25 +788,25 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } evt_dat->data = kzalloc(evt_dat->len, GFP_KERNEL); - if (!evt_dat->data) { + if (evt_dat->data == NULL) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2615 Memory allocation failed for " "CT event data, size %d\n", evt_dat->len); kfree(evt_dat); spin_lock_irqsave(&phba->ct_ev_lock, flags); - lpfc_ct_event_unref(evt); + lpfc_bsg_event_unref(evt); spin_unlock_irqrestore(&phba->ct_ev_lock, flags); goto error_ct_unsol_exit; } list_for_each_entry(iocbq, &head, list) { + size = 0; if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { bdeBuf1 = iocbq->context2; bdeBuf2 = iocbq->context3; } for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) { - int size = 0; if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { if (i == 0) { @@ -605,7 +841,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, kfree(evt_dat); spin_lock_irqsave(&phba->ct_ev_lock, flags); - lpfc_ct_event_unref(evt); + lpfc_bsg_event_unref(evt); spin_unlock_irqrestore( &phba->ct_ev_lock, flags); goto error_ct_unsol_exit; @@ -620,15 +856,24 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, dmabuf); } else { switch (cmd) { + case ELX_LOOPBACK_DATA: + dfc_cmd_data_free(phba, + (struct lpfc_dmabufext *) + dmabuf); + break; case ELX_LOOPBACK_XRI_SETUP: - if (!(phba->sli3_options & - LPFC_SLI3_HBQ_ENABLED)) + if ((phba->sli_rev == + LPFC_SLI_REV2) || + (phba->sli3_options & + LPFC_SLI3_HBQ_ENABLED + )) { + lpfc_in_buf_free(phba, + dmabuf); + } else { lpfc_post_buffer(phba, pring, 1); - else - lpfc_in_buf_free(phba, - dmabuf); + } break; default: if (!(phba->sli3_options & @@ -655,49 +900,79 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, evt_dat->type = FC_REG_CT_EVENT; list_add(&evt_dat->node, &evt->events_to_see); - wake_up_interruptible(&evt->wq); - lpfc_ct_event_unref(evt); - if (evt_req_id == SLI_CT_ELX_LOOPBACK) + if (evt_req_id == SLI_CT_ELX_LOOPBACK) { + wake_up_interruptible(&evt->wq); + lpfc_bsg_event_unref(evt); break; + } + + list_move(evt->events_to_see.prev, &evt->events_to_get); + lpfc_bsg_event_unref(evt); + + job = evt->set_job; + evt->set_job = NULL; + if (job) { + job->reply->reply_payload_rcv_len = size; + /* make error code available to userspace */ + job->reply->result = 0; + job->dd_data = NULL; + /* complete the job back to userspace */ + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + job->job_done(job); + spin_lock_irqsave(&phba->ct_ev_lock, flags); + } } spin_unlock_irqrestore(&phba->ct_ev_lock, flags); error_ct_unsol_exit: if (!list_empty(&head)) list_del(&head); - + if (evt_req_id == SLI_CT_ELX_LOOPBACK) + return 0; return 1; } /** - * lpfc_bsg_set_event - process a SET_EVENT bsg vendor command + * lpfc_bsg_hba_set_event - process a SET_EVENT bsg vendor command * @job: SET_EVENT fc_bsg_job */ static int -lpfc_bsg_set_event(struct fc_bsg_job *job) +lpfc_bsg_hba_set_event(struct fc_bsg_job *job) { struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; struct lpfc_hba *phba = vport->phba; struct set_ct_event *event_req; - struct lpfc_ct_event *evt; - unsigned long flags; + struct lpfc_bsg_event *evt; int rc = 0; + struct bsg_job_data *dd_data = NULL; + uint32_t ev_mask; + unsigned long flags; if (job->request_len < sizeof(struct fc_bsg_request) + sizeof(struct set_ct_event)) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2612 Received SET_CT_EVENT below minimum " "size\n"); - return -EINVAL; + rc = -EINVAL; + goto job_error; + } + + dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); + if (dd_data == NULL) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2734 Failed allocation of dd_data\n"); + rc = -ENOMEM; + goto job_error; } event_req = (struct set_ct_event *) job->request->rqst_data.h_vendor.vendor_cmd; - + ev_mask = ((uint32_t)(unsigned long)event_req->type_mask & + FC_REG_EVENT_MASK); spin_lock_irqsave(&phba->ct_ev_lock, flags); list_for_each_entry(evt, &phba->ct_ev_waiters, node) { if (evt->reg_id == event_req->ev_reg_id) { - lpfc_ct_event_ref(evt); + lpfc_bsg_event_ref(evt); evt->wait_time_stamp = jiffies; break; } @@ -706,73 +981,63 @@ lpfc_bsg_set_event(struct fc_bsg_job *job) if (&evt->node == &phba->ct_ev_waiters) { /* no event waiting struct yet - first call */ - evt = lpfc_ct_event_new(event_req->ev_reg_id, + evt = lpfc_bsg_event_new(ev_mask, event_req->ev_reg_id, event_req->ev_req_id); if (!evt) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2617 Failed allocation of event " "waiter\n"); - return -ENOMEM; + rc = -ENOMEM; + goto job_error; } spin_lock_irqsave(&phba->ct_ev_lock, flags); list_add(&evt->node, &phba->ct_ev_waiters); - lpfc_ct_event_ref(evt); + lpfc_bsg_event_ref(evt); + evt->wait_time_stamp = jiffies; spin_unlock_irqrestore(&phba->ct_ev_lock, flags); } - evt->waiting = 1; - if (wait_event_interruptible(evt->wq, - !list_empty(&evt->events_to_see))) { - spin_lock_irqsave(&phba->ct_ev_lock, flags); - lpfc_ct_event_unref(evt); /* release ref */ - lpfc_ct_event_unref(evt); /* delete */ - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - rc = -EINTR; - goto set_event_out; - } - - evt->wait_time_stamp = jiffies; - evt->waiting = 0; - spin_lock_irqsave(&phba->ct_ev_lock, flags); - list_move(evt->events_to_see.prev, &evt->events_to_get); - lpfc_ct_event_unref(evt); /* release ref */ + evt->waiting = 1; + dd_data->type = TYPE_EVT; + dd_data->context_un.evt = evt; + evt->set_job = job; /* for unsolicited command */ + job->dd_data = dd_data; /* for fc transport timeout callback*/ spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + return 0; /* call job done later */ -set_event_out: - /* set_event carries no reply payload */ - job->reply->reply_payload_rcv_len = 0; - /* make error code available to userspace */ - job->reply->result = rc; - /* complete the job back to userspace */ - job->job_done(job); +job_error: + if (dd_data != NULL) + kfree(dd_data); - return 0; + job->dd_data = NULL; + return rc; } /** - * lpfc_bsg_get_event - process a GET_EVENT bsg vendor command + * lpfc_bsg_hba_get_event - process a GET_EVENT bsg vendor command * @job: GET_EVENT fc_bsg_job */ static int -lpfc_bsg_get_event(struct fc_bsg_job *job) +lpfc_bsg_hba_get_event(struct fc_bsg_job *job) { struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; struct lpfc_hba *phba = vport->phba; struct get_ct_event *event_req; struct get_ct_event_reply *event_reply; - struct lpfc_ct_event *evt; + struct lpfc_bsg_event *evt; struct event_data *evt_dat = NULL; unsigned long flags; - int rc = 0; + uint32_t rc = 0; if (job->request_len < sizeof(struct fc_bsg_request) + sizeof(struct get_ct_event)) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2613 Received GET_CT_EVENT request below " "minimum size\n"); - return -EINVAL; + rc = -EINVAL; + goto job_error; } event_req = (struct get_ct_event *) @@ -780,13 +1045,12 @@ lpfc_bsg_get_event(struct fc_bsg_job *job) event_reply = (struct get_ct_event_reply *) job->reply->reply_data.vendor_reply.vendor_rsp; - spin_lock_irqsave(&phba->ct_ev_lock, flags); list_for_each_entry(evt, &phba->ct_ev_waiters, node) { if (evt->reg_id == event_req->ev_reg_id) { if (list_empty(&evt->events_to_get)) break; - lpfc_ct_event_ref(evt); + lpfc_bsg_event_ref(evt); evt->wait_time_stamp = jiffies; evt_dat = list_entry(evt->events_to_get.prev, struct event_data, node); @@ -796,44 +1060,49 @@ lpfc_bsg_get_event(struct fc_bsg_job *job) } spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - if (!evt_dat) { + /* The app may continue to ask for event data until it gets + * an error indicating that there isn't anymore + */ + if (evt_dat == NULL) { job->reply->reply_payload_rcv_len = 0; rc = -ENOENT; - goto error_get_event_exit; + goto job_error; } - if (evt_dat->len > job->reply_payload.payload_len) { - evt_dat->len = job->reply_payload.payload_len; - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2618 Truncated event data at %d " - "bytes\n", - job->reply_payload.payload_len); + if (evt_dat->len > job->request_payload.payload_len) { + evt_dat->len = job->request_payload.payload_len; + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2618 Truncated event data at %d " + "bytes\n", + job->request_payload.payload_len); } + event_reply->type = evt_dat->type; event_reply->immed_data = evt_dat->immed_dat; - if (evt_dat->len > 0) job->reply->reply_payload_rcv_len = - sg_copy_from_buffer(job->reply_payload.sg_list, - job->reply_payload.sg_cnt, + sg_copy_from_buffer(job->request_payload.sg_list, + job->request_payload.sg_cnt, evt_dat->data, evt_dat->len); else job->reply->reply_payload_rcv_len = 0; - rc = 0; - if (evt_dat) + if (evt_dat) { kfree(evt_dat->data); - kfree(evt_dat); + kfree(evt_dat); + } + spin_lock_irqsave(&phba->ct_ev_lock, flags); - lpfc_ct_event_unref(evt); + lpfc_bsg_event_unref(evt); spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - -error_get_event_exit: - /* make error code available to userspace */ - job->reply->result = rc; - /* complete the job back to userspace */ + job->dd_data = NULL; + job->reply->result = 0; job->job_done(job); + return 0; +job_error: + job->dd_data = NULL; + job->reply->result = rc; return rc; } @@ -845,19 +1114,25 @@ static int lpfc_bsg_hst_vendor(struct fc_bsg_job *job) { int command = job->request->rqst_data.h_vendor.vendor_cmd[0]; + int rc; switch (command) { case LPFC_BSG_VENDOR_SET_CT_EVENT: - return lpfc_bsg_set_event(job); + rc = lpfc_bsg_hba_set_event(job); break; case LPFC_BSG_VENDOR_GET_CT_EVENT: - return lpfc_bsg_get_event(job); + rc = lpfc_bsg_hba_get_event(job); break; - default: - return -EINVAL; + rc = -EINVAL; + job->reply->reply_payload_rcv_len = 0; + /* make error code available to userspace */ + job->reply->result = rc; + break; } + + return rc; } /** @@ -868,10 +1143,9 @@ int lpfc_bsg_request(struct fc_bsg_job *job) { uint32_t msgcode; - int rc = -EINVAL; + int rc; msgcode = job->request->msgcode; - switch (msgcode) { case FC_BSG_HST_VENDOR: rc = lpfc_bsg_hst_vendor(job); @@ -880,9 +1154,13 @@ lpfc_bsg_request(struct fc_bsg_job *job) rc = lpfc_bsg_rport_els(job); break; case FC_BSG_RPT_CT: - rc = lpfc_bsg_rport_ct(job); + rc = lpfc_bsg_send_mgmt_cmd(job); break; default: + rc = -EINVAL; + job->reply->reply_payload_rcv_len = 0; + /* make error code available to userspace */ + job->reply->result = rc; break; } @@ -901,11 +1179,54 @@ lpfc_bsg_timeout(struct fc_bsg_job *job) { struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *)job->dd_data; + struct lpfc_iocbq *cmdiocb; + struct lpfc_bsg_event *evt; + struct lpfc_bsg_iocb *iocb; struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; + struct bsg_job_data *dd_data; + unsigned long flags; - if (cmdiocb) + spin_lock_irqsave(&phba->ct_ev_lock, flags); + dd_data = (struct bsg_job_data *)job->dd_data; + /* timeout and completion crossed paths if no dd_data */ + if (!dd_data) { + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + return 0; + } + + switch (dd_data->type) { + case TYPE_IOCB: + iocb = &dd_data->context_un.iocb; + cmdiocb = iocb->cmdiocbq; + /* hint to completion handler that the job timed out */ + job->reply->result = -EAGAIN; + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + /* this will call our completion handler */ + spin_lock_irq(&phba->hbalock); lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); + spin_unlock_irq(&phba->hbalock); + break; + case TYPE_EVT: + evt = dd_data->context_un.evt; + /* this event has no job anymore */ + evt->set_job = NULL; + job->dd_data = NULL; + job->reply->reply_payload_rcv_len = 0; + /* Return -EAGAIN which is our way of signallying the + * app to retry. + */ + job->reply->result = -EAGAIN; + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + job->job_done(job); + break; + default: + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + break; + } + /* scsi transport fc fc_bsg_job_timeout expects a zero return code, + * otherwise an error message will be displayed on the console + * so always return success (zero) + */ return 0; } -- cgit v1.2.2 From 3b5dd52aaffd291edea9f939ed46a960b240bb45 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 26 Jan 2010 23:10:15 -0500 Subject: [SCSI] lpfc 8.3.8: (BSG4) Add new vendor specific BSG Commands Add the following new vendor specific BSG commands. - Add LPFC_BSG_VENDOR_GET_MGMT_REV command - Add LPFC_BSG_VENDOR_MBOX command - Add LPFC_BSG_VENDOR_DIAG_MODE command - Add LPFC_BSG_VENDOR_DIAG_TEST command Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_bsg.c | 1697 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 1626 insertions(+), 71 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index a7e8921015eb..64ab075a3656 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -74,13 +74,23 @@ struct lpfc_bsg_iocb { struct fc_bsg_job *set_job; }; +struct lpfc_bsg_mbox { + LPFC_MBOXQ_t *pmboxq; + MAILBOX_t *mb; + + /* job waiting for this mbox command to finish */ + struct fc_bsg_job *set_job; +}; + #define TYPE_EVT 1 #define TYPE_IOCB 2 +#define TYPE_MBOX 3 struct bsg_job_data { uint32_t type; union { struct lpfc_bsg_event *evt; struct lpfc_bsg_iocb iocb; + struct lpfc_bsg_mbox mbox; } context_un; }; @@ -92,6 +102,7 @@ struct event_data { uint32_t len; }; +#define BUF_SZ_4K 4096 #define SLI_CT_ELX_LOOPBACK 0x10 enum ELX_LOOPBACK_CMD { @@ -99,6 +110,9 @@ enum ELX_LOOPBACK_CMD { ELX_LOOPBACK_DATA, }; +#define ELX_LOOPBACK_HEADER_SZ \ + (size_t)(&((struct lpfc_sli_ct_request *)NULL)->un) + struct lpfc_dmabufext { struct lpfc_dmabuf dma; uint32_t size; @@ -201,7 +215,7 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba, /** * lpfc_bsg_send_mgmt_cmd - send a CT command from a bsg request * @job: fc_bsg_job to handle - */ + **/ static int lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job) { @@ -380,7 +394,7 @@ no_dd_data: * can be called from both worker thread context and interrupt * context. This function also can be called from other thread which * cleans up the SLI layer objects. - * This function copy the contents of the response iocb to the + * This function copies the contents of the response iocb to the * response iocb memory object provided by the caller of * lpfc_sli_issue_iocb_wait and then wakes up the thread which * sleeps for the iocb completion. @@ -461,7 +475,7 @@ lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba, /** * lpfc_bsg_rport_els - send an ELS command from a bsg request * @job: fc_bsg_job to handle - */ + **/ static int lpfc_bsg_rport_els(struct fc_bsg_job *job) { @@ -527,8 +541,8 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) } /* prep els iocb set context1 to the ndlp, context2 to the command - * dmabuf, context3 holds the data dmabuf - */ + * dmabuf, context3 holds the data dmabuf + */ pcmd = (struct lpfc_dmabuf *) cmdiocbq->context2; prsp = (struct lpfc_dmabuf *) pcmd->list.next; lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); @@ -613,6 +627,14 @@ no_dd_data: return rc; } +/** + * lpfc_bsg_event_free - frees an allocated event structure + * @kref: Pointer to a kref. + * + * Called from kref_put. Back cast the kref into an event structure address. + * Free any events to get, delete associated nodes, free any events to see, + * free any data then free the event itself. + **/ static void lpfc_bsg_event_free(struct kref *kref) { @@ -639,18 +661,32 @@ lpfc_bsg_event_free(struct kref *kref) kfree(evt); } +/** + * lpfc_bsg_event_ref - increments the kref for an event + * @evt: Pointer to an event structure. + **/ static inline void lpfc_bsg_event_ref(struct lpfc_bsg_event *evt) { kref_get(&evt->kref); } +/** + * lpfc_bsg_event_unref - Uses kref_put to free an event structure + * @evt: Pointer to an event structure. + **/ static inline void lpfc_bsg_event_unref(struct lpfc_bsg_event *evt) { kref_put(&evt->kref, lpfc_bsg_event_free); } +/** + * lpfc_bsg_event_new - allocate and initialize a event structure + * @ev_mask: Mask of events. + * @ev_reg_id: Event reg id. + * @ev_req_id: Event request id. + **/ static struct lpfc_bsg_event * lpfc_bsg_event_new(uint32_t ev_mask, int ev_reg_id, uint32_t ev_req_id) { @@ -670,8 +706,13 @@ lpfc_bsg_event_new(uint32_t ev_mask, int ev_reg_id, uint32_t ev_req_id) return evt; } +/** + * diag_cmd_data_free - Frees an lpfc dma buffer extension + * @phba: Pointer to HBA context object. + * @mlist: Pointer to an lpfc dma buffer extension. + **/ static int -dfc_cmd_data_free(struct lpfc_hba *phba, struct lpfc_dmabufext *mlist) +diag_cmd_data_free(struct lpfc_hba *phba, struct lpfc_dmabufext *mlist) { struct lpfc_dmabufext *mlast; struct pci_dev *pcidev; @@ -705,7 +746,7 @@ dfc_cmd_data_free(struct lpfc_hba *phba, struct lpfc_dmabufext *mlist) * * This function is called when an unsolicited CT command is received. It * forwards the event to any processes registered to receive CT events. - */ + **/ int lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocbq) @@ -857,7 +898,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } else { switch (cmd) { case ELX_LOOPBACK_DATA: - dfc_cmd_data_free(phba, + diag_cmd_data_free(phba, (struct lpfc_dmabufext *) dmabuf); break; @@ -935,7 +976,7 @@ error_ct_unsol_exit: /** * lpfc_bsg_hba_set_event - process a SET_EVENT bsg vendor command * @job: SET_EVENT fc_bsg_job - */ + **/ static int lpfc_bsg_hba_set_event(struct fc_bsg_job *job) { @@ -1018,7 +1059,7 @@ job_error: /** * lpfc_bsg_hba_get_event - process a GET_EVENT bsg vendor command * @job: GET_EVENT fc_bsg_job - */ + **/ static int lpfc_bsg_hba_get_event(struct fc_bsg_job *job) { @@ -1107,91 +1148,1595 @@ job_error: } /** - * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job - * @job: fc_bsg_job to handle - */ + * lpfc_issue_ct_rsp_cmp - lpfc_issue_ct_rsp's completion handler + * @phba: Pointer to HBA context object. + * @cmdiocbq: Pointer to command iocb. + * @rspiocbq: Pointer to response iocb. + * + * This function is the completion handler for iocbs issued using + * lpfc_issue_ct_rsp_cmp function. This function is called by the + * ring event handler function without any lock held. This function + * can be called from both worker thread context and interrupt + * context. This function also can be called from other thread which + * cleans up the SLI layer objects. + * This function copy the contents of the response iocb to the + * response iocb memory object provided by the caller of + * lpfc_sli_issue_iocb_wait and then wakes up the thread which + * sleeps for the iocb completion. + **/ +static void +lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdiocbq, + struct lpfc_iocbq *rspiocbq) +{ + struct bsg_job_data *dd_data; + struct fc_bsg_job *job; + IOCB_t *rsp; + struct lpfc_dmabuf *bmp; + struct lpfc_nodelist *ndlp; + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&phba->ct_ev_lock, flags); + dd_data = cmdiocbq->context1; + /* normal completion and timeout crossed paths, already done */ + if (!dd_data) { + spin_unlock_irqrestore(&phba->hbalock, flags); + return; + } + + job = dd_data->context_un.iocb.set_job; + bmp = dd_data->context_un.iocb.bmp; + rsp = &rspiocbq->iocb; + ndlp = dd_data->context_un.iocb.ndlp; + + pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, + job->request_payload.sg_cnt, DMA_TO_DEVICE); + + if (rsp->ulpStatus) { + if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { + switch (rsp->un.ulpWord[4] & 0xff) { + case IOERR_SEQUENCE_TIMEOUT: + rc = -ETIMEDOUT; + break; + case IOERR_INVALID_RPI: + rc = -EFAULT; + break; + default: + rc = -EACCES; + break; + } + } else + rc = -EACCES; + } else + job->reply->reply_payload_rcv_len = + rsp->un.genreq64.bdl.bdeSize; + + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); + lpfc_sli_release_iocbq(phba, cmdiocbq); + lpfc_nlp_put(ndlp); + kfree(bmp); + kfree(dd_data); + /* make error code available to userspace */ + job->reply->result = rc; + job->dd_data = NULL; + /* complete the job back to userspace */ + job->job_done(job); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + return; +} + +/** + * lpfc_issue_ct_rsp - issue a ct response + * @phba: Pointer to HBA context object. + * @job: Pointer to the job object. + * @tag: tag index value into the ports context exchange array. + * @bmp: Pointer to a dma buffer descriptor. + * @num_entry: Number of enties in the bde. + **/ static int -lpfc_bsg_hst_vendor(struct fc_bsg_job *job) +lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag, + struct lpfc_dmabuf *bmp, int num_entry) { - int command = job->request->rqst_data.h_vendor.vendor_cmd[0]; - int rc; + IOCB_t *icmd; + struct lpfc_iocbq *ctiocb = NULL; + int rc = 0; + struct lpfc_nodelist *ndlp = NULL; + struct bsg_job_data *dd_data; + uint32_t creg_val; - switch (command) { - case LPFC_BSG_VENDOR_SET_CT_EVENT: - rc = lpfc_bsg_hba_set_event(job); - break; + /* allocate our bsg tracking structure */ + dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); + if (!dd_data) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2736 Failed allocation of dd_data\n"); + rc = -ENOMEM; + goto no_dd_data; + } - case LPFC_BSG_VENDOR_GET_CT_EVENT: - rc = lpfc_bsg_hba_get_event(job); - break; - default: - rc = -EINVAL; - job->reply->reply_payload_rcv_len = 0; - /* make error code available to userspace */ - job->reply->result = rc; - break; + /* Allocate buffer for command iocb */ + ctiocb = lpfc_sli_get_iocbq(phba); + if (!ctiocb) { + rc = ENOMEM; + goto no_ctiocb; + } + + icmd = &ctiocb->iocb; + icmd->un.xseq64.bdl.ulpIoTag32 = 0; + icmd->un.xseq64.bdl.addrHigh = putPaddrHigh(bmp->phys); + icmd->un.xseq64.bdl.addrLow = putPaddrLow(bmp->phys); + icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; + icmd->un.xseq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64)); + icmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); + icmd->un.xseq64.w5.hcsw.Dfctl = 0; + icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_SOL_CTL; + icmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; + + /* Fill in rest of iocb */ + icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; + icmd->ulpBdeCount = 1; + icmd->ulpLe = 1; + icmd->ulpClass = CLASS3; + if (phba->sli_rev == LPFC_SLI_REV4) { + /* Do not issue unsol response if oxid not marked as valid */ + if (!(phba->ct_ctx[tag].flags & UNSOL_VALID)) { + rc = IOCB_ERROR; + goto issue_ct_rsp_exit; + } + icmd->ulpContext = phba->ct_ctx[tag].oxid; + ndlp = lpfc_findnode_did(phba->pport, phba->ct_ctx[tag].SID); + if (!ndlp) { + lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, + "2721 ndlp null for oxid %x SID %x\n", + icmd->ulpContext, + phba->ct_ctx[tag].SID); + rc = IOCB_ERROR; + goto issue_ct_rsp_exit; + } + icmd->un.ulpWord[3] = ndlp->nlp_rpi; + /* The exchange is done, mark the entry as invalid */ + phba->ct_ctx[tag].flags &= ~UNSOL_VALID; + } else + icmd->ulpContext = (ushort) tag; + + icmd->ulpTimeout = phba->fc_ratov * 2; + + /* Xmit CT response on exchange */ + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "2722 Xmit CT response on exchange x%x Data: x%x x%x\n", + icmd->ulpContext, icmd->ulpIoTag, phba->link_state); + + ctiocb->iocb_cmpl = NULL; + ctiocb->iocb_flag |= LPFC_IO_LIBDFC; + ctiocb->vport = phba->pport; + ctiocb->context3 = bmp; + + ctiocb->iocb_cmpl = lpfc_issue_ct_rsp_cmp; + ctiocb->context1 = dd_data; + ctiocb->context2 = NULL; + dd_data->type = TYPE_IOCB; + dd_data->context_un.iocb.cmdiocbq = ctiocb; + dd_data->context_un.iocb.rspiocbq = NULL; + dd_data->context_un.iocb.set_job = job; + dd_data->context_un.iocb.bmp = bmp; + dd_data->context_un.iocb.ndlp = ndlp; + + if (phba->cfg_poll & DISABLE_FCP_RING_INT) { + creg_val = readl(phba->HCregaddr); + creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); + writel(creg_val, phba->HCregaddr); + readl(phba->HCregaddr); /* flush */ } + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); + + if (rc == IOCB_SUCCESS) + return 0; /* done for now */ + +issue_ct_rsp_exit: + lpfc_sli_release_iocbq(phba, ctiocb); +no_ctiocb: + kfree(dd_data); +no_dd_data: return rc; } /** - * lpfc_bsg_request - handle a bsg request from the FC transport - * @job: fc_bsg_job to handle - */ -int -lpfc_bsg_request(struct fc_bsg_job *job) + * lpfc_bsg_send_mgmt_rsp - process a SEND_MGMT_RESP bsg vendor command + * @job: SEND_MGMT_RESP fc_bsg_job + **/ +static int +lpfc_bsg_send_mgmt_rsp(struct fc_bsg_job *job) { - uint32_t msgcode; - int rc; + struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct send_mgmt_resp *mgmt_resp = (struct send_mgmt_resp *) + job->request->rqst_data.h_vendor.vendor_cmd; + struct ulp_bde64 *bpl; + struct lpfc_dmabuf *bmp = NULL; + struct scatterlist *sgel = NULL; + int request_nseg; + int numbde; + dma_addr_t busaddr; + uint32_t tag = mgmt_resp->tag; + unsigned long reqbfrcnt = + (unsigned long)job->request_payload.payload_len; + int rc = 0; - msgcode = job->request->msgcode; - switch (msgcode) { - case FC_BSG_HST_VENDOR: - rc = lpfc_bsg_hst_vendor(job); - break; - case FC_BSG_RPT_ELS: - rc = lpfc_bsg_rport_els(job); - break; - case FC_BSG_RPT_CT: - rc = lpfc_bsg_send_mgmt_cmd(job); - break; - default: - rc = -EINVAL; - job->reply->reply_payload_rcv_len = 0; - /* make error code available to userspace */ - job->reply->result = rc; - break; + /* in case no data is transferred */ + job->reply->reply_payload_rcv_len = 0; + + if (!reqbfrcnt || (reqbfrcnt > (80 * BUF_SZ_4K))) { + rc = -ERANGE; + goto send_mgmt_rsp_exit; + } + + bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!bmp) { + rc = -ENOMEM; + goto send_mgmt_rsp_exit; + } + + bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); + if (!bmp->virt) { + rc = -ENOMEM; + goto send_mgmt_rsp_free_bmp; + } + + INIT_LIST_HEAD(&bmp->list); + bpl = (struct ulp_bde64 *) bmp->virt; + request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, + job->request_payload.sg_cnt, DMA_TO_DEVICE); + for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { + busaddr = sg_dma_address(sgel); + bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; + bpl->tus.f.bdeSize = sg_dma_len(sgel); + bpl->tus.w = cpu_to_le32(bpl->tus.w); + bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); + bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); + bpl++; } + rc = lpfc_issue_ct_rsp(phba, job, tag, bmp, request_nseg); + + if (rc == IOCB_SUCCESS) + return 0; /* done for now */ + + /* TBD need to handle a timeout */ + pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, + job->request_payload.sg_cnt, DMA_TO_DEVICE); + rc = -EACCES; + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); + +send_mgmt_rsp_free_bmp: + kfree(bmp); +send_mgmt_rsp_exit: + /* make error code available to userspace */ + job->reply->result = rc; + job->dd_data = NULL; return rc; } /** - * lpfc_bsg_timeout - handle timeout of a bsg request from the FC transport - * @job: fc_bsg_job that has timed out + * lpfc_bsg_diag_mode - process a LPFC_BSG_VENDOR_DIAG_MODE bsg vendor command + * @job: LPFC_BSG_VENDOR_DIAG_MODE * - * This function just aborts the job's IOCB. The aborted IOCB will return to - * the waiting function which will handle passing the error back to userspace + * This function is responsible for placing a port into diagnostic loopback + * mode in order to perform a diagnostic loopback test. + * All new scsi requests are blocked, a small delay is used to allow the + * scsi requests to complete then the link is brought down. If the link is + * is placed in loopback mode then scsi requests are again allowed + * so the scsi mid-layer doesn't give up on the port. + * All of this is done in-line. */ -int -lpfc_bsg_timeout(struct fc_bsg_job *job) +static int +lpfc_bsg_diag_mode(struct fc_bsg_job *job) { + struct Scsi_Host *shost = job->shost; struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *cmdiocb; - struct lpfc_bsg_event *evt; - struct lpfc_bsg_iocb *iocb; - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; - struct bsg_job_data *dd_data; - unsigned long flags; + struct diag_mode_set *loopback_mode; + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring = &psli->ring[LPFC_FCP_RING]; + uint32_t link_flags; + uint32_t timeout; + struct lpfc_vport **vports; + LPFC_MBOXQ_t *pmboxq; + int mbxstatus; + int i = 0; + int rc = 0; - spin_lock_irqsave(&phba->ct_ev_lock, flags); - dd_data = (struct bsg_job_data *)job->dd_data; - /* timeout and completion crossed paths if no dd_data */ - if (!dd_data) { - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - return 0; + /* no data to return just the return code */ + job->reply->reply_payload_rcv_len = 0; + + if (job->request_len < + sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_set)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2738 Received DIAG MODE request below minimum " + "size\n"); + rc = -EINVAL; + goto job_error; + } + + loopback_mode = (struct diag_mode_set *) + job->request->rqst_data.h_vendor.vendor_cmd; + link_flags = loopback_mode->type; + timeout = loopback_mode->timeout; + + if ((phba->link_state == LPFC_HBA_ERROR) || + (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || + (!(psli->sli_flag & LPFC_SLI_ACTIVE))) { + rc = -EACCES; + goto job_error; + } + + pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!pmboxq) { + rc = -ENOMEM; + goto job_error; + } + + vports = lpfc_create_vport_work_array(phba); + if (vports) { + for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { + shost = lpfc_shost_from_vport(vports[i]); + scsi_block_requests(shost); + } + + lpfc_destroy_vport_work_array(phba, vports); + } else { + shost = lpfc_shost_from_vport(phba->pport); + scsi_block_requests(shost); + } + + while (pring->txcmplq_cnt) { + if (i++ > 500) /* wait up to 5 seconds */ + break; + + msleep(10); + } + + memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t)); + pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK; + pmboxq->u.mb.mbxOwner = OWN_HOST; + + mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); + + if ((mbxstatus == MBX_SUCCESS) && (pmboxq->u.mb.mbxStatus == 0)) { + /* wait for link down before proceeding */ + i = 0; + while (phba->link_state != LPFC_LINK_DOWN) { + if (i++ > timeout) { + rc = -ETIMEDOUT; + goto loopback_mode_exit; + } + + msleep(10); + } + + memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t)); + if (link_flags == INTERNAL_LOOP_BACK) + pmboxq->u.mb.un.varInitLnk.link_flags = FLAGS_LOCAL_LB; + else + pmboxq->u.mb.un.varInitLnk.link_flags = + FLAGS_TOPOLOGY_MODE_LOOP; + + pmboxq->u.mb.mbxCommand = MBX_INIT_LINK; + pmboxq->u.mb.mbxOwner = OWN_HOST; + + mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, + LPFC_MBOX_TMO); + + if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) + rc = -ENODEV; + else { + phba->link_flag |= LS_LOOPBACK_MODE; + /* wait for the link attention interrupt */ + msleep(100); + + i = 0; + while (phba->link_state != LPFC_HBA_READY) { + if (i++ > timeout) { + rc = -ETIMEDOUT; + break; + } + + msleep(10); + } + } + + } else + rc = -ENODEV; + +loopback_mode_exit: + vports = lpfc_create_vport_work_array(phba); + if (vports) { + for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { + shost = lpfc_shost_from_vport(vports[i]); + scsi_unblock_requests(shost); + } + lpfc_destroy_vport_work_array(phba, vports); + } else { + shost = lpfc_shost_from_vport(phba->pport); + scsi_unblock_requests(shost); + } + + /* + * Let SLI layer release mboxq if mbox command completed after timeout. + */ + if (mbxstatus != MBX_TIMEOUT) + mempool_free(pmboxq, phba->mbox_mem_pool); + +job_error: + /* make error code available to userspace */ + job->reply->result = rc; + /* complete the job back to userspace if no error */ + if (rc == 0) + job->job_done(job); + return rc; +} + +/** + * lpfcdiag_loop_self_reg - obtains a remote port login id + * @phba: Pointer to HBA context object + * @rpi: Pointer to a remote port login id + * + * This function obtains a remote port login id so the diag loopback test + * can send and receive its own unsolicited CT command. + **/ +static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t * rpi) +{ + LPFC_MBOXQ_t *mbox; + struct lpfc_dmabuf *dmabuff; + int status; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return ENOMEM; + + status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID, + (uint8_t *)&phba->pport->fc_sparam, mbox, 0); + if (status) { + mempool_free(mbox, phba->mbox_mem_pool); + return ENOMEM; + } + + dmabuff = (struct lpfc_dmabuf *) mbox->context1; + mbox->context1 = NULL; + status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); + + if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { + lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); + kfree(dmabuff); + if (status != MBX_TIMEOUT) + mempool_free(mbox, phba->mbox_mem_pool); + return ENODEV; + } + + *rpi = mbox->u.mb.un.varWords[0]; + + lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); + kfree(dmabuff); + mempool_free(mbox, phba->mbox_mem_pool); + return 0; +} + +/** + * lpfcdiag_loop_self_unreg - unregs from the rpi + * @phba: Pointer to HBA context object + * @rpi: Remote port login id + * + * This function unregisters the rpi obtained in lpfcdiag_loop_self_reg + **/ +static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi) +{ + LPFC_MBOXQ_t *mbox; + int status; + + /* Allocate mboxq structure */ + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (mbox == NULL) + return ENOMEM; + + lpfc_unreg_login(phba, 0, rpi, mbox); + status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); + + if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { + if (status != MBX_TIMEOUT) + mempool_free(mbox, phba->mbox_mem_pool); + return EIO; + } + + mempool_free(mbox, phba->mbox_mem_pool); + return 0; +} + +/** + * lpfcdiag_loop_get_xri - obtains the transmit and receive ids + * @phba: Pointer to HBA context object + * @rpi: Remote port login id + * @txxri: Pointer to transmit exchange id + * @rxxri: Pointer to response exchabge id + * + * This function obtains the transmit and receive ids required to send + * an unsolicited ct command with a payload. A special lpfc FsType and CmdRsp + * flags are used to the unsolicted response handler is able to process + * the ct command sent on the same port. + **/ +static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, + uint16_t *txxri, uint16_t * rxxri) +{ + struct lpfc_bsg_event *evt; + struct lpfc_iocbq *cmdiocbq, *rspiocbq; + IOCB_t *cmd, *rsp; + struct lpfc_dmabuf *dmabuf; + struct ulp_bde64 *bpl = NULL; + struct lpfc_sli_ct_request *ctreq = NULL; + int ret_val = 0; + unsigned long flags; + + *txxri = 0; + *rxxri = 0; + evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, + SLI_CT_ELX_LOOPBACK); + if (!evt) + return ENOMEM; + + spin_lock_irqsave(&phba->ct_ev_lock, flags); + list_add(&evt->node, &phba->ct_ev_waiters); + lpfc_bsg_event_ref(evt); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + + cmdiocbq = lpfc_sli_get_iocbq(phba); + rspiocbq = lpfc_sli_get_iocbq(phba); + + dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (dmabuf) { + dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys); + INIT_LIST_HEAD(&dmabuf->list); + bpl = (struct ulp_bde64 *) dmabuf->virt; + memset(bpl, 0, sizeof(*bpl)); + ctreq = (struct lpfc_sli_ct_request *)(bpl + 1); + bpl->addrHigh = + le32_to_cpu(putPaddrHigh(dmabuf->phys + sizeof(*bpl))); + bpl->addrLow = + le32_to_cpu(putPaddrLow(dmabuf->phys + sizeof(*bpl))); + bpl->tus.f.bdeFlags = 0; + bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ; + bpl->tus.w = le32_to_cpu(bpl->tus.w); + } + + if (cmdiocbq == NULL || rspiocbq == NULL || + dmabuf == NULL || bpl == NULL || ctreq == NULL) { + ret_val = ENOMEM; + goto err_get_xri_exit; + } + + cmd = &cmdiocbq->iocb; + rsp = &rspiocbq->iocb; + + memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); + + ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; + ctreq->RevisionId.bits.InId = 0; + ctreq->FsType = SLI_CT_ELX_LOOPBACK; + ctreq->FsSubType = 0; + ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_XRI_SETUP; + ctreq->CommandResponse.bits.Size = 0; + + + cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(dmabuf->phys); + cmd->un.xseq64.bdl.addrLow = putPaddrLow(dmabuf->phys); + cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; + cmd->un.xseq64.bdl.bdeSize = sizeof(*bpl); + + cmd->un.xseq64.w5.hcsw.Fctl = LA; + cmd->un.xseq64.w5.hcsw.Dfctl = 0; + cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; + cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; + + cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CR; + cmd->ulpBdeCount = 1; + cmd->ulpLe = 1; + cmd->ulpClass = CLASS3; + cmd->ulpContext = rpi; + + cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; + cmdiocbq->vport = phba->pport; + + ret_val = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, + rspiocbq, + (phba->fc_ratov * 2) + + LPFC_DRVR_TIMEOUT); + if (ret_val) + goto err_get_xri_exit; + + *txxri = rsp->ulpContext; + + evt->waiting = 1; + evt->wait_time_stamp = jiffies; + ret_val = wait_event_interruptible_timeout( + evt->wq, !list_empty(&evt->events_to_see), + ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ); + if (list_empty(&evt->events_to_see)) + ret_val = (ret_val) ? EINTR : ETIMEDOUT; + else { + ret_val = IOCB_SUCCESS; + spin_lock_irqsave(&phba->ct_ev_lock, flags); + list_move(evt->events_to_see.prev, &evt->events_to_get); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + *rxxri = (list_entry(evt->events_to_get.prev, + typeof(struct event_data), + node))->immed_dat; + } + evt->waiting = 0; + +err_get_xri_exit: + spin_lock_irqsave(&phba->ct_ev_lock, flags); + lpfc_bsg_event_unref(evt); /* release ref */ + lpfc_bsg_event_unref(evt); /* delete */ + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + + if (dmabuf) { + if (dmabuf->virt) + lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); + kfree(dmabuf); + } + + if (cmdiocbq && (ret_val != IOCB_TIMEDOUT)) + lpfc_sli_release_iocbq(phba, cmdiocbq); + if (rspiocbq) + lpfc_sli_release_iocbq(phba, rspiocbq); + return ret_val; +} + +/** + * diag_cmd_data_alloc - fills in a bde struct with dma buffers + * @phba: Pointer to HBA context object + * @bpl: Pointer to 64 bit bde structure + * @size: Number of bytes to process + * @nocopydata: Flag to copy user data into the allocated buffer + * + * This function allocates page size buffers and populates an lpfc_dmabufext. + * If allowed the user data pointed to with indataptr is copied into the kernel + * memory. The chained list of page size buffers is returned. + **/ +static struct lpfc_dmabufext * +diag_cmd_data_alloc(struct lpfc_hba *phba, + struct ulp_bde64 *bpl, uint32_t size, + int nocopydata) +{ + struct lpfc_dmabufext *mlist = NULL; + struct lpfc_dmabufext *dmp; + int cnt, offset = 0, i = 0; + struct pci_dev *pcidev; + + pcidev = phba->pcidev; + + while (size) { + /* We get chunks of 4K */ + if (size > BUF_SZ_4K) + cnt = BUF_SZ_4K; + else + cnt = size; + + /* allocate struct lpfc_dmabufext buffer header */ + dmp = kmalloc(sizeof(struct lpfc_dmabufext), GFP_KERNEL); + if (!dmp) + goto out; + + INIT_LIST_HEAD(&dmp->dma.list); + + /* Queue it to a linked list */ + if (mlist) + list_add_tail(&dmp->dma.list, &mlist->dma.list); + else + mlist = dmp; + + /* allocate buffer */ + dmp->dma.virt = dma_alloc_coherent(&pcidev->dev, + cnt, + &(dmp->dma.phys), + GFP_KERNEL); + + if (!dmp->dma.virt) + goto out; + + dmp->size = cnt; + + if (nocopydata) { + bpl->tus.f.bdeFlags = 0; + pci_dma_sync_single_for_device(phba->pcidev, + dmp->dma.phys, LPFC_BPL_SIZE, PCI_DMA_TODEVICE); + + } else { + memset((uint8_t *)dmp->dma.virt, 0, cnt); + bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; + } + + /* build buffer ptr list for IOCB */ + bpl->addrLow = le32_to_cpu(putPaddrLow(dmp->dma.phys)); + bpl->addrHigh = le32_to_cpu(putPaddrHigh(dmp->dma.phys)); + bpl->tus.f.bdeSize = (ushort) cnt; + bpl->tus.w = le32_to_cpu(bpl->tus.w); + bpl++; + + i++; + offset += cnt; + size -= cnt; + } + + mlist->flag = i; + return mlist; +out: + diag_cmd_data_free(phba, mlist); + return NULL; +} + +/** + * lpfcdiag_loop_post_rxbufs - post the receive buffers for an unsol CT cmd + * @phba: Pointer to HBA context object + * @rxxri: Receive exchange id + * @len: Number of data bytes + * + * This function allocates and posts a data buffer of sufficient size to recieve + * an unsolicted CT command. + **/ +static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, + size_t len) +{ + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; + struct lpfc_iocbq *cmdiocbq; + IOCB_t *cmd = NULL; + struct list_head head, *curr, *next; + struct lpfc_dmabuf *rxbmp; + struct lpfc_dmabuf *dmp; + struct lpfc_dmabuf *mp[2] = {NULL, NULL}; + struct ulp_bde64 *rxbpl = NULL; + uint32_t num_bde; + struct lpfc_dmabufext *rxbuffer = NULL; + int ret_val = 0; + int i = 0; + + cmdiocbq = lpfc_sli_get_iocbq(phba); + rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (rxbmp != NULL) { + rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); + INIT_LIST_HEAD(&rxbmp->list); + rxbpl = (struct ulp_bde64 *) rxbmp->virt; + rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0); + } + + if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer) { + ret_val = ENOMEM; + goto err_post_rxbufs_exit; + } + + /* Queue buffers for the receive exchange */ + num_bde = (uint32_t)rxbuffer->flag; + dmp = &rxbuffer->dma; + + cmd = &cmdiocbq->iocb; + i = 0; + + INIT_LIST_HEAD(&head); + list_add_tail(&head, &dmp->list); + list_for_each_safe(curr, next, &head) { + mp[i] = list_entry(curr, struct lpfc_dmabuf, list); + list_del(curr); + + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { + mp[i]->buffer_tag = lpfc_sli_get_buffer_tag(phba); + cmd->un.quexri64cx.buff.bde.addrHigh = + putPaddrHigh(mp[i]->phys); + cmd->un.quexri64cx.buff.bde.addrLow = + putPaddrLow(mp[i]->phys); + cmd->un.quexri64cx.buff.bde.tus.f.bdeSize = + ((struct lpfc_dmabufext *)mp[i])->size; + cmd->un.quexri64cx.buff.buffer_tag = mp[i]->buffer_tag; + cmd->ulpCommand = CMD_QUE_XRI64_CX; + cmd->ulpPU = 0; + cmd->ulpLe = 1; + cmd->ulpBdeCount = 1; + cmd->unsli3.que_xri64cx_ext_words.ebde_count = 0; + + } else { + cmd->un.cont64[i].addrHigh = putPaddrHigh(mp[i]->phys); + cmd->un.cont64[i].addrLow = putPaddrLow(mp[i]->phys); + cmd->un.cont64[i].tus.f.bdeSize = + ((struct lpfc_dmabufext *)mp[i])->size; + cmd->ulpBdeCount = ++i; + + if ((--num_bde > 0) && (i < 2)) + continue; + + cmd->ulpCommand = CMD_QUE_XRI_BUF64_CX; + cmd->ulpLe = 1; + } + + cmd->ulpClass = CLASS3; + cmd->ulpContext = rxxri; + + ret_val = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); + + if (ret_val == IOCB_ERROR) { + diag_cmd_data_free(phba, + (struct lpfc_dmabufext *)mp[0]); + if (mp[1]) + diag_cmd_data_free(phba, + (struct lpfc_dmabufext *)mp[1]); + dmp = list_entry(next, struct lpfc_dmabuf, list); + ret_val = EIO; + goto err_post_rxbufs_exit; + } + + lpfc_sli_ringpostbuf_put(phba, pring, mp[0]); + if (mp[1]) { + lpfc_sli_ringpostbuf_put(phba, pring, mp[1]); + mp[1] = NULL; + } + + /* The iocb was freed by lpfc_sli_issue_iocb */ + cmdiocbq = lpfc_sli_get_iocbq(phba); + if (!cmdiocbq) { + dmp = list_entry(next, struct lpfc_dmabuf, list); + ret_val = EIO; + goto err_post_rxbufs_exit; + } + + cmd = &cmdiocbq->iocb; + i = 0; + } + list_del(&head); + +err_post_rxbufs_exit: + + if (rxbmp) { + if (rxbmp->virt) + lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys); + kfree(rxbmp); + } + + if (cmdiocbq) + lpfc_sli_release_iocbq(phba, cmdiocbq); + return ret_val; +} + +/** + * lpfc_bsg_diag_test - with a port in loopback issues a Ct cmd to itself + * @job: LPFC_BSG_VENDOR_DIAG_TEST fc_bsg_job + * + * This function receives a user data buffer to be transmitted and received on + * the same port, the link must be up and in loopback mode prior + * to being called. + * 1. A kernel buffer is allocated to copy the user data into. + * 2. The port registers with "itself". + * 3. The transmit and receive exchange ids are obtained. + * 4. The receive exchange id is posted. + * 5. A new els loopback event is created. + * 6. The command and response iocbs are allocated. + * 7. The cmd iocb FsType is set to elx loopback and the CmdRsp to looppback. + * + * This function is meant to be called n times while the port is in loopback + * so it is the apps responsibility to issue a reset to take the port out + * of loopback mode. + **/ +static int +lpfc_bsg_diag_test(struct fc_bsg_job *job) +{ + struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct diag_mode_test *diag_mode; + struct lpfc_bsg_event *evt; + struct event_data *evdat; + struct lpfc_sli *psli = &phba->sli; + uint32_t size; + uint32_t full_size; + size_t segment_len = 0, segment_offset = 0, current_offset = 0; + uint16_t rpi; + struct lpfc_iocbq *cmdiocbq, *rspiocbq; + IOCB_t *cmd, *rsp; + struct lpfc_sli_ct_request *ctreq; + struct lpfc_dmabuf *txbmp; + struct ulp_bde64 *txbpl = NULL; + struct lpfc_dmabufext *txbuffer = NULL; + struct list_head head; + struct lpfc_dmabuf *curr; + uint16_t txxri, rxxri; + uint32_t num_bde; + uint8_t *ptr = NULL, *rx_databuf = NULL; + int rc = 0; + unsigned long flags; + void *dataout = NULL; + uint32_t total_mem; + + /* in case no data is returned return just the return code */ + job->reply->reply_payload_rcv_len = 0; + + if (job->request_len < + sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_test)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2739 Received DIAG TEST request below minimum " + "size\n"); + rc = -EINVAL; + goto loopback_test_exit; + } + + if (job->request_payload.payload_len != + job->reply_payload.payload_len) { + rc = -EINVAL; + goto loopback_test_exit; + } + + diag_mode = (struct diag_mode_test *) + job->request->rqst_data.h_vendor.vendor_cmd; + + if ((phba->link_state == LPFC_HBA_ERROR) || + (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || + (!(psli->sli_flag & LPFC_SLI_ACTIVE))) { + rc = -EACCES; + goto loopback_test_exit; + } + + if (!lpfc_is_link_up(phba) || !(phba->link_flag & LS_LOOPBACK_MODE)) { + rc = -EACCES; + goto loopback_test_exit; + } + + size = job->request_payload.payload_len; + full_size = size + ELX_LOOPBACK_HEADER_SZ; /* plus the header */ + + if ((size == 0) || (size > 80 * BUF_SZ_4K)) { + rc = -ERANGE; + goto loopback_test_exit; + } + + if (size >= BUF_SZ_4K) { + /* + * Allocate memory for ioctl data. If buffer is bigger than 64k, + * then we allocate 64k and re-use that buffer over and over to + * xfer the whole block. This is because Linux kernel has a + * problem allocating more than 120k of kernel space memory. Saw + * problem with GET_FCPTARGETMAPPING... + */ + if (size <= (64 * 1024)) + total_mem = size; + else + total_mem = 64 * 1024; + } else + /* Allocate memory for ioctl data */ + total_mem = BUF_SZ_4K; + + dataout = kmalloc(total_mem, GFP_KERNEL); + if (dataout == NULL) { + rc = -ENOMEM; + goto loopback_test_exit; + } + + ptr = dataout; + ptr += ELX_LOOPBACK_HEADER_SZ; + sg_copy_to_buffer(job->request_payload.sg_list, + job->request_payload.sg_cnt, + ptr, size); + + rc = lpfcdiag_loop_self_reg(phba, &rpi); + if (rc) { + rc = -ENOMEM; + goto loopback_test_exit; + } + + rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri); + if (rc) { + lpfcdiag_loop_self_unreg(phba, rpi); + rc = -ENOMEM; + goto loopback_test_exit; + } + + rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size); + if (rc) { + lpfcdiag_loop_self_unreg(phba, rpi); + rc = -ENOMEM; + goto loopback_test_exit; + } + + evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, + SLI_CT_ELX_LOOPBACK); + if (!evt) { + lpfcdiag_loop_self_unreg(phba, rpi); + rc = -ENOMEM; + goto loopback_test_exit; + } + + spin_lock_irqsave(&phba->ct_ev_lock, flags); + list_add(&evt->node, &phba->ct_ev_waiters); + lpfc_bsg_event_ref(evt); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + + cmdiocbq = lpfc_sli_get_iocbq(phba); + rspiocbq = lpfc_sli_get_iocbq(phba); + txbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + + if (txbmp) { + txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys); + INIT_LIST_HEAD(&txbmp->list); + txbpl = (struct ulp_bde64 *) txbmp->virt; + if (txbpl) + txbuffer = diag_cmd_data_alloc(phba, + txbpl, full_size, 0); + } + + if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer) { + rc = -ENOMEM; + goto err_loopback_test_exit; + } + + cmd = &cmdiocbq->iocb; + rsp = &rspiocbq->iocb; + + INIT_LIST_HEAD(&head); + list_add_tail(&head, &txbuffer->dma.list); + list_for_each_entry(curr, &head, list) { + segment_len = ((struct lpfc_dmabufext *)curr)->size; + if (current_offset == 0) { + ctreq = curr->virt; + memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); + ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; + ctreq->RevisionId.bits.InId = 0; + ctreq->FsType = SLI_CT_ELX_LOOPBACK; + ctreq->FsSubType = 0; + ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_DATA; + ctreq->CommandResponse.bits.Size = size; + segment_offset = ELX_LOOPBACK_HEADER_SZ; + } else + segment_offset = 0; + + BUG_ON(segment_offset >= segment_len); + memcpy(curr->virt + segment_offset, + ptr + current_offset, + segment_len - segment_offset); + + current_offset += segment_len - segment_offset; + BUG_ON(current_offset > size); + } + list_del(&head); + + /* Build the XMIT_SEQUENCE iocb */ + + num_bde = (uint32_t)txbuffer->flag; + + cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(txbmp->phys); + cmd->un.xseq64.bdl.addrLow = putPaddrLow(txbmp->phys); + cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; + cmd->un.xseq64.bdl.bdeSize = (num_bde * sizeof(struct ulp_bde64)); + + cmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); + cmd->un.xseq64.w5.hcsw.Dfctl = 0; + cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; + cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; + + cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; + cmd->ulpBdeCount = 1; + cmd->ulpLe = 1; + cmd->ulpClass = CLASS3; + cmd->ulpContext = txxri; + + cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; + cmdiocbq->vport = phba->pport; + + rc = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, rspiocbq, + (phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT); + + if ((rc != IOCB_SUCCESS) || (rsp->ulpStatus != IOCB_SUCCESS)) { + rc = -EIO; + goto err_loopback_test_exit; + } + + evt->waiting = 1; + rc = wait_event_interruptible_timeout( + evt->wq, !list_empty(&evt->events_to_see), + ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ); + evt->waiting = 0; + if (list_empty(&evt->events_to_see)) + rc = (rc) ? -EINTR : -ETIMEDOUT; + else { + spin_lock_irqsave(&phba->ct_ev_lock, flags); + list_move(evt->events_to_see.prev, &evt->events_to_get); + evdat = list_entry(evt->events_to_get.prev, + typeof(*evdat), node); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + rx_databuf = evdat->data; + if (evdat->len != full_size) { + lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, + "1603 Loopback test did not receive expected " + "data length. actual length 0x%x expected " + "length 0x%x\n", + evdat->len, full_size); + rc = -EIO; + } else if (rx_databuf == NULL) + rc = -EIO; + else { + rc = IOCB_SUCCESS; + /* skip over elx loopback header */ + rx_databuf += ELX_LOOPBACK_HEADER_SZ; + job->reply->reply_payload_rcv_len = + sg_copy_from_buffer(job->reply_payload.sg_list, + job->reply_payload.sg_cnt, + rx_databuf, size); + job->reply->reply_payload_rcv_len = size; + } + } + +err_loopback_test_exit: + lpfcdiag_loop_self_unreg(phba, rpi); + + spin_lock_irqsave(&phba->ct_ev_lock, flags); + lpfc_bsg_event_unref(evt); /* release ref */ + lpfc_bsg_event_unref(evt); /* delete */ + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + + if (cmdiocbq != NULL) + lpfc_sli_release_iocbq(phba, cmdiocbq); + + if (rspiocbq != NULL) + lpfc_sli_release_iocbq(phba, rspiocbq); + + if (txbmp != NULL) { + if (txbpl != NULL) { + if (txbuffer != NULL) + diag_cmd_data_free(phba, txbuffer); + lpfc_mbuf_free(phba, txbmp->virt, txbmp->phys); + } + kfree(txbmp); + } + +loopback_test_exit: + kfree(dataout); + /* make error code available to userspace */ + job->reply->result = rc; + job->dd_data = NULL; + /* complete the job back to userspace if no error */ + if (rc == 0) + job->job_done(job); + return rc; +} + +/** + * lpfc_bsg_get_dfc_rev - process a GET_DFC_REV bsg vendor command + * @job: GET_DFC_REV fc_bsg_job + **/ +static int +lpfc_bsg_get_dfc_rev(struct fc_bsg_job *job) +{ + struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct get_mgmt_rev *event_req; + struct get_mgmt_rev_reply *event_reply; + int rc = 0; + + if (job->request_len < + sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2740 Received GET_DFC_REV request below " + "minimum size\n"); + rc = -EINVAL; + goto job_error; + } + + event_req = (struct get_mgmt_rev *) + job->request->rqst_data.h_vendor.vendor_cmd; + + event_reply = (struct get_mgmt_rev_reply *) + job->reply->reply_data.vendor_reply.vendor_rsp; + + if (job->reply_len < + sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev_reply)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2741 Received GET_DFC_REV reply below " + "minimum size\n"); + rc = -EINVAL; + goto job_error; + } + + event_reply->info.a_Major = MANAGEMENT_MAJOR_REV; + event_reply->info.a_Minor = MANAGEMENT_MINOR_REV; +job_error: + job->reply->result = rc; + if (rc == 0) + job->job_done(job); + return rc; +} + +/** + * lpfc_bsg_wake_mbox_wait - lpfc_bsg_issue_mbox mbox completion handler + * @phba: Pointer to HBA context object. + * @pmboxq: Pointer to mailbox command. + * + * This is completion handler function for mailbox commands issued from + * lpfc_bsg_issue_mbox function. This function is called by the + * mailbox event handler function with no lock held. This function + * will wake up thread waiting on the wait queue pointed by context1 + * of the mailbox. + **/ +void +lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) +{ + struct bsg_job_data *dd_data; + MAILBOX_t *pmb; + MAILBOX_t *mb; + struct fc_bsg_job *job; + uint32_t size; + unsigned long flags; + + spin_lock_irqsave(&phba->ct_ev_lock, flags); + dd_data = pmboxq->context1; + if (!dd_data) { + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + return; + } + + pmb = &dd_data->context_un.mbox.pmboxq->u.mb; + mb = dd_data->context_un.mbox.mb; + job = dd_data->context_un.mbox.set_job; + memcpy(mb, pmb, sizeof(*pmb)); + size = job->request_payload.payload_len; + job->reply->reply_payload_rcv_len = + sg_copy_from_buffer(job->reply_payload.sg_list, + job->reply_payload.sg_cnt, + mb, size); + job->reply->result = 0; + dd_data->context_un.mbox.set_job = NULL; + job->dd_data = NULL; + job->job_done(job); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool); + kfree(mb); + kfree(dd_data); + return; +} + +/** + * lpfc_bsg_check_cmd_access - test for a supported mailbox command + * @phba: Pointer to HBA context object. + * @mb: Pointer to a mailbox object. + * @vport: Pointer to a vport object. + * + * Some commands require the port to be offline, some may not be called from + * the application. + **/ +static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, + MAILBOX_t *mb, struct lpfc_vport *vport) +{ + /* return negative error values for bsg job */ + switch (mb->mbxCommand) { + /* Offline only */ + case MBX_INIT_LINK: + case MBX_DOWN_LINK: + case MBX_CONFIG_LINK: + case MBX_CONFIG_RING: + case MBX_RESET_RING: + case MBX_UNREG_LOGIN: + case MBX_CLEAR_LA: + case MBX_DUMP_CONTEXT: + case MBX_RUN_DIAGS: + case MBX_RESTART: + case MBX_SET_MASK: + if (!(vport->fc_flag & FC_OFFLINE_MODE)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2743 Command 0x%x is illegal in on-line " + "state\n", + mb->mbxCommand); + return -EPERM; + } + case MBX_WRITE_NV: + case MBX_WRITE_VPARMS: + case MBX_LOAD_SM: + case MBX_READ_NV: + case MBX_READ_CONFIG: + case MBX_READ_RCONFIG: + case MBX_READ_STATUS: + case MBX_READ_XRI: + case MBX_READ_REV: + case MBX_READ_LNK_STAT: + case MBX_DUMP_MEMORY: + case MBX_DOWN_LOAD: + case MBX_UPDATE_CFG: + case MBX_KILL_BOARD: + case MBX_LOAD_AREA: + case MBX_LOAD_EXP_ROM: + case MBX_BEACON: + case MBX_DEL_LD_ENTRY: + case MBX_SET_DEBUG: + case MBX_WRITE_WWN: + case MBX_SLI4_CONFIG: + case MBX_READ_EVENT_LOG_STATUS: + case MBX_WRITE_EVENT_LOG: + case MBX_PORT_CAPABILITIES: + case MBX_PORT_IOV_CONTROL: + break; + case MBX_SET_VARIABLE: + case MBX_RUN_BIU_DIAG64: + case MBX_READ_EVENT_LOG: + case MBX_READ_SPARM64: + case MBX_READ_LA: + case MBX_READ_LA64: + case MBX_REG_LOGIN: + case MBX_REG_LOGIN64: + case MBX_CONFIG_PORT: + case MBX_RUN_BIU_DIAG: + default: + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2742 Unknown Command 0x%x\n", + mb->mbxCommand); + return -EPERM; + } + + return 0; /* ok */ +} + +/** + * lpfc_bsg_issue_mbox - issues a mailbox command on behalf of an app + * @phba: Pointer to HBA context object. + * @mb: Pointer to a mailbox object. + * @vport: Pointer to a vport object. + * + * Allocate a tracking object, mailbox command memory, get a mailbox + * from the mailbox pool, copy the caller mailbox command. + * + * If offline and the sli is active we need to poll for the command (port is + * being reset) and com-plete the job, otherwise issue the mailbox command and + * let our completion handler finish the command. + **/ +static uint32_t +lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, + struct lpfc_vport *vport) +{ + LPFC_MBOXQ_t *pmboxq; + MAILBOX_t *pmb; + MAILBOX_t *mb; + struct bsg_job_data *dd_data; + uint32_t size; + int rc = 0; + + /* allocate our bsg tracking structure */ + dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); + if (!dd_data) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2727 Failed allocation of dd_data\n"); + return -ENOMEM; + } + + mb = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!mb) { + kfree(dd_data); + return -ENOMEM; + } + + pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!pmboxq) { + kfree(dd_data); + kfree(mb); + return -ENOMEM; + } + + size = job->request_payload.payload_len; + job->reply->reply_payload_rcv_len = + sg_copy_to_buffer(job->request_payload.sg_list, + job->request_payload.sg_cnt, + mb, size); + + rc = lpfc_bsg_check_cmd_access(phba, mb, vport); + if (rc != 0) { + kfree(dd_data); + kfree(mb); + mempool_free(pmboxq, phba->mbox_mem_pool); + return rc; /* must be negative */ + } + + memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); + pmb = &pmboxq->u.mb; + memcpy(pmb, mb, sizeof(*pmb)); + pmb->mbxOwner = OWN_HOST; + pmboxq->context1 = NULL; + pmboxq->vport = vport; + + if ((vport->fc_flag & FC_OFFLINE_MODE) || + (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) { + rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); + if (rc != MBX_SUCCESS) { + if (rc != MBX_TIMEOUT) { + kfree(dd_data); + kfree(mb); + mempool_free(pmboxq, phba->mbox_mem_pool); + } + return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; + } + + memcpy(mb, pmb, sizeof(*pmb)); + job->reply->reply_payload_rcv_len = + sg_copy_from_buffer(job->reply_payload.sg_list, + job->reply_payload.sg_cnt, + mb, size); + kfree(dd_data); + kfree(mb); + mempool_free(pmboxq, phba->mbox_mem_pool); + /* not waiting mbox already done */ + return 0; + } + + /* setup wake call as IOCB callback */ + pmboxq->mbox_cmpl = lpfc_bsg_wake_mbox_wait; + /* setup context field to pass wait_queue pointer to wake function */ + pmboxq->context1 = dd_data; + dd_data->type = TYPE_MBOX; + dd_data->context_un.mbox.pmboxq = pmboxq; + dd_data->context_un.mbox.mb = mb; + dd_data->context_un.mbox.set_job = job; + job->dd_data = dd_data; + rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); + if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) { + kfree(dd_data); + kfree(mb); + mempool_free(pmboxq, phba->mbox_mem_pool); + return -EIO; + } + + return 1; +} + +/** + * lpfc_bsg_mbox_cmd - process an fc bsg LPFC_BSG_VENDOR_MBOX command + * @job: MBOX fc_bsg_job for LPFC_BSG_VENDOR_MBOX. + **/ +static int +lpfc_bsg_mbox_cmd(struct fc_bsg_job *job) +{ + struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; + struct lpfc_hba *phba = vport->phba; + int rc = 0; + + /* in case no data is transferred */ + job->reply->reply_payload_rcv_len = 0; + if (job->request_len < + sizeof(struct fc_bsg_request) + sizeof(struct dfc_mbox_req)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2737 Received MBOX_REQ request below " + "minimum size\n"); + rc = -EINVAL; + goto job_error; + } + + if (job->request_payload.payload_len != PAGE_SIZE) { + rc = -EINVAL; + goto job_error; + } + + if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { + rc = -EAGAIN; + goto job_error; + } + + rc = lpfc_bsg_issue_mbox(phba, job, vport); + +job_error: + if (rc == 0) { + /* job done */ + job->reply->result = 0; + job->dd_data = NULL; + job->job_done(job); + } else if (rc == 1) + /* job submitted, will complete later*/ + rc = 0; /* return zero, no error */ + else { + /* some error occurred */ + job->reply->result = rc; + job->dd_data = NULL; + } + + return rc; +} + +/** + * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job + * @job: fc_bsg_job to handle + **/ +static int +lpfc_bsg_hst_vendor(struct fc_bsg_job *job) +{ + int command = job->request->rqst_data.h_vendor.vendor_cmd[0]; + int rc; + + switch (command) { + case LPFC_BSG_VENDOR_SET_CT_EVENT: + rc = lpfc_bsg_hba_set_event(job); + break; + case LPFC_BSG_VENDOR_GET_CT_EVENT: + rc = lpfc_bsg_hba_get_event(job); + break; + case LPFC_BSG_VENDOR_SEND_MGMT_RESP: + rc = lpfc_bsg_send_mgmt_rsp(job); + break; + case LPFC_BSG_VENDOR_DIAG_MODE: + rc = lpfc_bsg_diag_mode(job); + break; + case LPFC_BSG_VENDOR_DIAG_TEST: + rc = lpfc_bsg_diag_test(job); + break; + case LPFC_BSG_VENDOR_GET_MGMT_REV: + rc = lpfc_bsg_get_dfc_rev(job); + break; + case LPFC_BSG_VENDOR_MBOX: + rc = lpfc_bsg_mbox_cmd(job); + break; + default: + rc = -EINVAL; + job->reply->reply_payload_rcv_len = 0; + /* make error code available to userspace */ + job->reply->result = rc; + break; + } + + return rc; +} + +/** + * lpfc_bsg_request - handle a bsg request from the FC transport + * @job: fc_bsg_job to handle + **/ +int +lpfc_bsg_request(struct fc_bsg_job *job) +{ + uint32_t msgcode; + int rc; + + msgcode = job->request->msgcode; + switch (msgcode) { + case FC_BSG_HST_VENDOR: + rc = lpfc_bsg_hst_vendor(job); + break; + case FC_BSG_RPT_ELS: + rc = lpfc_bsg_rport_els(job); + break; + case FC_BSG_RPT_CT: + rc = lpfc_bsg_send_mgmt_cmd(job); + break; + default: + rc = -EINVAL; + job->reply->reply_payload_rcv_len = 0; + /* make error code available to userspace */ + job->reply->result = rc; + break; + } + + return rc; +} + +/** + * lpfc_bsg_timeout - handle timeout of a bsg request from the FC transport + * @job: fc_bsg_job that has timed out + * + * This function just aborts the job's IOCB. The aborted IOCB will return to + * the waiting function which will handle passing the error back to userspace + **/ +int +lpfc_bsg_timeout(struct fc_bsg_job *job) +{ + struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct lpfc_iocbq *cmdiocb; + struct lpfc_bsg_event *evt; + struct lpfc_bsg_iocb *iocb; + struct lpfc_bsg_mbox *mbox; + struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; + struct bsg_job_data *dd_data; + unsigned long flags; + + spin_lock_irqsave(&phba->ct_ev_lock, flags); + dd_data = (struct bsg_job_data *)job->dd_data; + /* timeout and completion crossed paths if no dd_data */ + if (!dd_data) { + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + return 0; } switch (dd_data->type) { @@ -1219,6 +2764,16 @@ lpfc_bsg_timeout(struct fc_bsg_job *job) spin_unlock_irqrestore(&phba->ct_ev_lock, flags); job->job_done(job); break; + case TYPE_MBOX: + mbox = &dd_data->context_un.mbox; + /* this mbox has no job anymore */ + mbox->set_job = NULL; + job->dd_data = NULL; + job->reply->reply_payload_rcv_len = 0; + job->reply->result = -EAGAIN; + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + job->job_done(job); + break; default: spin_unlock_irqrestore(&phba->ct_ev_lock, flags); break; -- cgit v1.2.2 From 7c0616b85ba23d0467bf0b5a6f288f5296eb05ff Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 26 Jan 2010 23:10:40 -0500 Subject: [SCSI] lpfc 8.3.8: Update Driver version to 8.3.8 Update Driver version to 8.3.8 Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 792f72263f1a..e550d02bb34a 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2009 Emulex. All rights reserved. * + * Copyright (C) 2004-2010 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.7" +#define LPFC_DRIVER_VERSION "8.3.8" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" #define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" -- cgit v1.2.2 From 8354be9c104db8e92bb079e29540fbafb7f09b5c Mon Sep 17 00:00:00 2001 From: Frans Pop Date: Sat, 6 Feb 2010 07:47:20 +0000 Subject: powerpc: Remove trailing space in messages Signed-off-by: Frans Pop Cc: linuxppc-dev@ozlabs.org Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt --- drivers/macintosh/therm_adt746x.c | 2 +- drivers/ps3/ps3av.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 58809b0510f9..c42eeb43042d 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -316,7 +316,7 @@ static void update_fans_speed (struct thermostat *th) if (verbose) printk(KERN_DEBUG "adt746x: Setting fans speed to %d " - "(limit exceeded by %d on %s) \n", + "(limit exceeded by %d on %s)\n", new_speed, var, sensor_location[fan_number+1]); write_both_fan_speed(th, new_speed); diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c index e82d8c9c6cda..95a689befc84 100644 --- a/drivers/ps3/ps3av.c +++ b/drivers/ps3/ps3av.c @@ -532,7 +532,7 @@ static void ps3av_set_videomode_packet(u32 id) res = ps3av_cmd_avb_param(&avb_param, len); if (res == PS3AV_STATUS_NO_SYNC_HEAD) printk(KERN_WARNING - "%s: Command failed. Please try your request again. \n", + "%s: Command failed. Please try your request again.\n", __func__); else if (res) dev_dbg(&ps3av->dev->core, "ps3av_cmd_avb_param failed\n"); -- cgit v1.2.2 From 577cd7584cf5199f1ea22cca0ad1fa129a98effa Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 9 Feb 2010 04:24:46 +0000 Subject: sh: extend INTC with struct intc_hw_desc This patch updates the INTC code by moving all vectors, groups and registers from struct intc_desc to struct intc_hw_desc. The idea is that INTC tables should go from using the macro(s) DECLARE_INTC_DESC..() only to using struct intc_desc with name and hw initialized using the macro INTC_HW_DESC(). This move makes it easy to initialize an extended struct intc_desc in the future. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/sh/intc.c | 88 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 45 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index d5d7f23c19a5..5ec0fffa7db4 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c @@ -400,11 +400,11 @@ static unsigned int __init intc_get_reg(struct intc_desc_int *d, static intc_enum __init intc_grp_id(struct intc_desc *desc, intc_enum enum_id) { - struct intc_group *g = desc->groups; + struct intc_group *g = desc->hw.groups; unsigned int i, j; - for (i = 0; g && enum_id && i < desc->nr_groups; i++) { - g = desc->groups + i; + for (i = 0; g && enum_id && i < desc->hw.nr_groups; i++) { + g = desc->hw.groups + i; for (j = 0; g->enum_ids[j]; j++) { if (g->enum_ids[j] != enum_id) @@ -421,12 +421,12 @@ static unsigned int __init intc_mask_data(struct intc_desc *desc, struct intc_desc_int *d, intc_enum enum_id, int do_grps) { - struct intc_mask_reg *mr = desc->mask_regs; + struct intc_mask_reg *mr = desc->hw.mask_regs; unsigned int i, j, fn, mode; unsigned long reg_e, reg_d; - for (i = 0; mr && enum_id && i < desc->nr_mask_regs; i++) { - mr = desc->mask_regs + i; + for (i = 0; mr && enum_id && i < desc->hw.nr_mask_regs; i++) { + mr = desc->hw.mask_regs + i; for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) { if (mr->enum_ids[j] != enum_id) @@ -469,12 +469,12 @@ static unsigned int __init intc_prio_data(struct intc_desc *desc, struct intc_desc_int *d, intc_enum enum_id, int do_grps) { - struct intc_prio_reg *pr = desc->prio_regs; + struct intc_prio_reg *pr = desc->hw.prio_regs; unsigned int i, j, fn, mode, bit; unsigned long reg_e, reg_d; - for (i = 0; pr && enum_id && i < desc->nr_prio_regs; i++) { - pr = desc->prio_regs + i; + for (i = 0; pr && enum_id && i < desc->hw.nr_prio_regs; i++) { + pr = desc->hw.prio_regs + i; for (j = 0; j < ARRAY_SIZE(pr->enum_ids); j++) { if (pr->enum_ids[j] != enum_id) @@ -517,12 +517,12 @@ static unsigned int __init intc_ack_data(struct intc_desc *desc, struct intc_desc_int *d, intc_enum enum_id) { - struct intc_mask_reg *mr = desc->ack_regs; + struct intc_mask_reg *mr = desc->hw.ack_regs; unsigned int i, j, fn, mode; unsigned long reg_e, reg_d; - for (i = 0; mr && enum_id && i < desc->nr_ack_regs; i++) { - mr = desc->ack_regs + i; + for (i = 0; mr && enum_id && i < desc->hw.nr_ack_regs; i++) { + mr = desc->hw.ack_regs + i; for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) { if (mr->enum_ids[j] != enum_id) @@ -549,11 +549,11 @@ static unsigned int __init intc_sense_data(struct intc_desc *desc, struct intc_desc_int *d, intc_enum enum_id) { - struct intc_sense_reg *sr = desc->sense_regs; + struct intc_sense_reg *sr = desc->hw.sense_regs; unsigned int i, j, fn, bit; - for (i = 0; sr && enum_id && i < desc->nr_sense_regs; i++) { - sr = desc->sense_regs + i; + for (i = 0; sr && enum_id && i < desc->hw.nr_sense_regs; i++) { + sr = desc->hw.sense_regs + i; for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) { if (sr->enum_ids[j] != enum_id) @@ -656,7 +656,7 @@ static void __init intc_register_irq(struct intc_desc *desc, /* irq should be disabled by default */ d->chip.mask(irq); - if (desc->ack_regs) + if (desc->hw.ack_regs) ack_handle[irq] = intc_ack_data(desc, d, enum_id); } @@ -684,6 +684,7 @@ static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc) void __init register_intc_controller(struct intc_desc *desc) { unsigned int i, k, smp; + struct intc_hw_desc *hw = &desc->hw; struct intc_desc_int *d; d = kzalloc(sizeof(*d), GFP_NOWAIT); @@ -691,10 +692,10 @@ void __init register_intc_controller(struct intc_desc *desc) INIT_LIST_HEAD(&d->list); list_add(&d->list, &intc_list); - d->nr_reg = desc->mask_regs ? desc->nr_mask_regs * 2 : 0; - d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0; - d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0; - d->nr_reg += desc->ack_regs ? desc->nr_ack_regs : 0; + d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0; + d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0; + d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0; + d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0; d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT); #ifdef CONFIG_SMP @@ -702,30 +703,31 @@ void __init register_intc_controller(struct intc_desc *desc) #endif k = 0; - if (desc->mask_regs) { - for (i = 0; i < desc->nr_mask_regs; i++) { - smp = IS_SMP(desc->mask_regs[i]); - k += save_reg(d, k, desc->mask_regs[i].set_reg, smp); - k += save_reg(d, k, desc->mask_regs[i].clr_reg, smp); + if (hw->mask_regs) { + for (i = 0; i < hw->nr_mask_regs; i++) { + smp = IS_SMP(hw->mask_regs[i]); + k += save_reg(d, k, hw->mask_regs[i].set_reg, smp); + k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp); } } - if (desc->prio_regs) { - d->prio = kzalloc(desc->nr_vectors * sizeof(*d->prio), GFP_NOWAIT); + if (hw->prio_regs) { + d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio), + GFP_NOWAIT); - for (i = 0; i < desc->nr_prio_regs; i++) { - smp = IS_SMP(desc->prio_regs[i]); - k += save_reg(d, k, desc->prio_regs[i].set_reg, smp); - k += save_reg(d, k, desc->prio_regs[i].clr_reg, smp); + for (i = 0; i < hw->nr_prio_regs; i++) { + smp = IS_SMP(hw->prio_regs[i]); + k += save_reg(d, k, hw->prio_regs[i].set_reg, smp); + k += save_reg(d, k, hw->prio_regs[i].clr_reg, smp); } } - if (desc->sense_regs) { - d->sense = kzalloc(desc->nr_vectors * sizeof(*d->sense), GFP_NOWAIT); + if (hw->sense_regs) { + d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense), + GFP_NOWAIT); - for (i = 0; i < desc->nr_sense_regs; i++) { - k += save_reg(d, k, desc->sense_regs[i].reg, 0); - } + for (i = 0; i < hw->nr_sense_regs; i++) + k += save_reg(d, k, hw->sense_regs[i].reg, 0); } d->chip.name = desc->name; @@ -738,9 +740,9 @@ void __init register_intc_controller(struct intc_desc *desc) d->chip.set_type = intc_set_sense; d->chip.set_wake = intc_set_wake; - if (desc->ack_regs) { - for (i = 0; i < desc->nr_ack_regs; i++) - k += save_reg(d, k, desc->ack_regs[i].set_reg, 0); + if (hw->ack_regs) { + for (i = 0; i < hw->nr_ack_regs; i++) + k += save_reg(d, k, hw->ack_regs[i].set_reg, 0); d->chip.mask_ack = intc_mask_ack; } @@ -748,8 +750,8 @@ void __init register_intc_controller(struct intc_desc *desc) BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */ /* register the vectors one by one */ - for (i = 0; i < desc->nr_vectors; i++) { - struct intc_vect *vect = desc->vectors + i; + for (i = 0; i < hw->nr_vectors; i++) { + struct intc_vect *vect = hw->vectors + i; unsigned int irq = evt2irq(vect->vect); struct irq_desc *irq_desc; @@ -764,8 +766,8 @@ void __init register_intc_controller(struct intc_desc *desc) intc_register_irq(desc, d, vect->enum_id, irq); - for (k = i + 1; k < desc->nr_vectors; k++) { - struct intc_vect *vect2 = desc->vectors + k; + for (k = i + 1; k < hw->nr_vectors; k++) { + struct intc_vect *vect2 = hw->vectors + k; unsigned int irq2 = evt2irq(vect2->vect); if (vect->enum_id != vect2->enum_id) -- cgit v1.2.2 From d519095344fda705c9840a579acf6aa6205c37cc Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 9 Feb 2010 04:29:22 +0000 Subject: sh: extend INTC with force_enable Extend the shared INTC code with force_enable support to allow keeping mask bits statically enabled. Needed by upcoming INTC SDHI patches that mux together a bunch of vectors to a single linux interrupt which is masked by a priority register, but needs individual mask bits constantly enabled. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/sh/intc.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 132 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index 5ec0fffa7db4..ccee18945d91 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c @@ -259,6 +259,43 @@ static void intc_disable(unsigned int irq) } } +static void (*intc_enable_noprio_fns[])(unsigned long addr, + unsigned long handle, + void (*fn)(unsigned long, + unsigned long, + unsigned long), + unsigned int irq) = { + [MODE_ENABLE_REG] = intc_mode_field, + [MODE_MASK_REG] = intc_mode_zero, + [MODE_DUAL_REG] = intc_mode_field, + [MODE_PRIO_REG] = intc_mode_field, + [MODE_PCLR_REG] = intc_mode_field, +}; + +static void intc_enable_disable(struct intc_desc_int *d, + unsigned long handle, int do_enable) +{ + unsigned long addr; + unsigned int cpu; + void (*fn)(unsigned long, unsigned long, + void (*)(unsigned long, unsigned long, unsigned long), + unsigned int); + + if (do_enable) { + for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) { + addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu); + fn = intc_enable_noprio_fns[_INTC_MODE(handle)]; + fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0); + } + } else { + for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) { + addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu); + fn = intc_disable_fns[_INTC_MODE(handle)]; + fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0); + } + } +} + static int intc_set_wake(unsigned int irq, unsigned int on) { return 0; /* allow wakeup, but setup hardware in intc_suspend() */ @@ -417,19 +454,21 @@ static intc_enum __init intc_grp_id(struct intc_desc *desc, return 0; } -static unsigned int __init intc_mask_data(struct intc_desc *desc, - struct intc_desc_int *d, - intc_enum enum_id, int do_grps) +static unsigned int __init _intc_mask_data(struct intc_desc *desc, + struct intc_desc_int *d, + intc_enum enum_id, + unsigned int *reg_idx, + unsigned int *fld_idx) { struct intc_mask_reg *mr = desc->hw.mask_regs; - unsigned int i, j, fn, mode; + unsigned int fn, mode; unsigned long reg_e, reg_d; - for (i = 0; mr && enum_id && i < desc->hw.nr_mask_regs; i++) { - mr = desc->hw.mask_regs + i; + while (mr && enum_id && *reg_idx < desc->hw.nr_mask_regs) { + mr = desc->hw.mask_regs + *reg_idx; - for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) { - if (mr->enum_ids[j] != enum_id) + for (; *fld_idx < ARRAY_SIZE(mr->enum_ids); (*fld_idx)++) { + if (mr->enum_ids[*fld_idx] != enum_id) continue; if (mr->set_reg && mr->clr_reg) { @@ -455,29 +494,49 @@ static unsigned int __init intc_mask_data(struct intc_desc *desc, intc_get_reg(d, reg_e), intc_get_reg(d, reg_d), 1, - (mr->reg_width - 1) - j); + (mr->reg_width - 1) - *fld_idx); } + + *fld_idx = 0; + (*reg_idx)++; } + return 0; +} + +static unsigned int __init intc_mask_data(struct intc_desc *desc, + struct intc_desc_int *d, + intc_enum enum_id, int do_grps) +{ + unsigned int i = 0; + unsigned int j = 0; + unsigned int ret; + + ret = _intc_mask_data(desc, d, enum_id, &i, &j); + if (ret) + return ret; + if (do_grps) return intc_mask_data(desc, d, intc_grp_id(desc, enum_id), 0); return 0; } -static unsigned int __init intc_prio_data(struct intc_desc *desc, - struct intc_desc_int *d, - intc_enum enum_id, int do_grps) +static unsigned int __init _intc_prio_data(struct intc_desc *desc, + struct intc_desc_int *d, + intc_enum enum_id, + unsigned int *reg_idx, + unsigned int *fld_idx) { struct intc_prio_reg *pr = desc->hw.prio_regs; - unsigned int i, j, fn, mode, bit; + unsigned int fn, n, mode, bit; unsigned long reg_e, reg_d; - for (i = 0; pr && enum_id && i < desc->hw.nr_prio_regs; i++) { - pr = desc->hw.prio_regs + i; + while (pr && enum_id && *reg_idx < desc->hw.nr_prio_regs) { + pr = desc->hw.prio_regs + *reg_idx; - for (j = 0; j < ARRAY_SIZE(pr->enum_ids); j++) { - if (pr->enum_ids[j] != enum_id) + for (; *fld_idx < ARRAY_SIZE(pr->enum_ids); (*fld_idx)++) { + if (pr->enum_ids[*fld_idx] != enum_id) continue; if (pr->set_reg && pr->clr_reg) { @@ -495,24 +554,69 @@ static unsigned int __init intc_prio_data(struct intc_desc *desc, } fn += (pr->reg_width >> 3) - 1; + n = *fld_idx + 1; - BUG_ON((j + 1) * pr->field_width > pr->reg_width); + BUG_ON(n * pr->field_width > pr->reg_width); - bit = pr->reg_width - ((j + 1) * pr->field_width); + bit = pr->reg_width - (n * pr->field_width); return _INTC_MK(fn, mode, intc_get_reg(d, reg_e), intc_get_reg(d, reg_d), pr->field_width, bit); } + + *fld_idx = 0; + (*reg_idx)++; } + return 0; +} + +static unsigned int __init intc_prio_data(struct intc_desc *desc, + struct intc_desc_int *d, + intc_enum enum_id, int do_grps) +{ + unsigned int i = 0; + unsigned int j = 0; + unsigned int ret; + + ret = _intc_prio_data(desc, d, enum_id, &i, &j); + if (ret) + return ret; + if (do_grps) return intc_prio_data(desc, d, intc_grp_id(desc, enum_id), 0); return 0; } +static void __init intc_enable_disable_enum(struct intc_desc *desc, + struct intc_desc_int *d, + intc_enum enum_id, int enable) +{ + unsigned int i, j, data; + + /* go through and enable/disable all mask bits */ + i = j = 0; + do { + data = _intc_mask_data(desc, d, enum_id, &i, &j); + if (data) + intc_enable_disable(d, data, enable); + j++; + } while (data); + + /* go through and enable/disable all priority fields */ + i = j = 0; + do { + data = _intc_prio_data(desc, d, enum_id, &i, &j); + if (data) + intc_enable_disable(d, data, enable); + + j++; + } while (data); +} + static unsigned int __init intc_ack_data(struct intc_desc *desc, struct intc_desc_int *d, intc_enum enum_id) @@ -747,6 +851,11 @@ void __init register_intc_controller(struct intc_desc *desc) d->chip.mask_ack = intc_mask_ack; } + + /* disable bits matching force_enable before registering irqs */ + if (desc->force_enable) + intc_enable_disable_enum(desc, d, desc->force_enable, 0); + BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */ /* register the vectors one by one */ @@ -792,6 +901,10 @@ void __init register_intc_controller(struct intc_desc *desc) set_irq_data(irq2, (void *)irq); } } + + /* enable bits matching force_enable after registering irqs */ + if (desc->force_enable) + intc_enable_disable_enum(desc, d, desc->force_enable, 1); } static int intc_suspend(struct sys_device *dev, pm_message_t state) -- cgit v1.2.2 From e6f077592d1de2f6a4fc760e7b5d6f20b37d3a27 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 9 Feb 2010 07:17:20 +0000 Subject: sh: fix INTC to use set_irq_chained_handler() for redirects This patch updates the shared INTC code to use set_irq_chained_handler() for intc_redirect_irq(). With this in place request_irq() on a merged irq which has been redirected will now return -EINVAL instead of 0 together with a crash. This thanks to the protection of the IRQ_NOREQUEST flag set for chained interrupt handlers. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/sh/intc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index 3a687396dfa2..66594eb4477d 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c @@ -896,8 +896,8 @@ void __init register_intc_controller(struct intc_desc *desc) vect2->enum_id = 0; /* redirect this interrupts to the first one */ - set_irq_chip_and_handler_name(irq2, &d->chip, - intc_redirect_irq, "redirect"); + set_irq_chained_handler(irq2, intc_redirect_irq); + set_irq_chip(irq2, &d->chip); set_irq_data(irq2, (void *)irq); } } -- cgit v1.2.2 From 0690535d6bcec5eb28573824df5c8a49ec85b696 Mon Sep 17 00:00:00 2001 From: Leo P White Date: Mon, 8 Feb 2010 13:02:05 +0000 Subject: HID: add mapping for "AL Network Chat" usage Adding a mapping for the 'AL Network Chat' usage from the 'Consumer' usage page (USB HID Usage Tables v1.11). This usage is used by some keyboards for a multimedia key. Signed-off-by: Leo P White Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 8430d626511c..a01a1b0de1c3 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -405,6 +405,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x192: map_key_clear(KEY_CALC); break; case 0x194: map_key_clear(KEY_FILE); break; case 0x196: map_key_clear(KEY_WWW); break; + case 0x199: map_key_clear(KEY_CHAT); break; case 0x19c: map_key_clear(KEY_LOGOFF); break; case 0x19e: map_key_clear(KEY_COFFEE); break; case 0x1a6: map_key_clear(KEY_HELP); break; -- cgit v1.2.2 From eabe5c90580a065aed8ce6a5ba53eb443d317fae Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Tue, 9 Feb 2010 11:43:19 +0100 Subject: HID: fix typo in error message Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 4e8450228a24..96d723ea5131 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -81,7 +81,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) sc = kzalloc(sizeof(*sc), GFP_KERNEL); if (sc == NULL) { - dev_err(&hdev->dev, "can't alloc apple descriptor\n"); + dev_err(&hdev->dev, "can't alloc sony descriptor\n"); return -ENOMEM; } -- cgit v1.2.2 From fcdeb7fedf89f4bbc2e11959794968080cd8426e Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 29 Jan 2010 05:04:33 -0700 Subject: of: merge of_attach_node() & of_detach_node() Merge common code between PowerPC and Microblaze Signed-off-by: Grant Likely Tested-by: Wolfram Sang Acked-by: Benjamin Herrenschmidt --- drivers/of/Kconfig | 4 +++ drivers/of/base.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) (limited to 'drivers') diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 462825e03123..7cecc8fea9bd 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -2,6 +2,10 @@ config OF_FLATTREE bool depends on OF +config OF_DYNAMIC + def_bool y + depends on OF && PPC_OF + config OF_DEVICE def_bool y depends on OF && (SPARC || PPC_OF || MICROBLAZE) diff --git a/drivers/of/base.c b/drivers/of/base.c index cf89ee6253f3..2ce58be314af 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -870,3 +870,74 @@ int prom_update_property(struct device_node *np, return 0; } + +#if defined(CONFIG_OF_DYNAMIC) +/* + * Support for dynamic device trees. + * + * On some platforms, the device tree can be manipulated at runtime. + * The routines in this section support adding, removing and changing + * device tree nodes. + */ + +/** + * of_attach_node - Plug a device node into the tree and global list. + */ +void of_attach_node(struct device_node *np) +{ + unsigned long flags; + + write_lock_irqsave(&devtree_lock, flags); + np->sibling = np->parent->child; + np->allnext = allnodes; + np->parent->child = np; + allnodes = np; + write_unlock_irqrestore(&devtree_lock, flags); +} + +/** + * of_detach_node - "Unplug" a node from the device tree. + * + * The caller must hold a reference to the node. The memory associated with + * the node is not freed until its refcount goes to zero. + */ +void of_detach_node(struct device_node *np) +{ + struct device_node *parent; + unsigned long flags; + + write_lock_irqsave(&devtree_lock, flags); + + parent = np->parent; + if (!parent) + goto out_unlock; + + if (allnodes == np) + allnodes = np->allnext; + else { + struct device_node *prev; + for (prev = allnodes; + prev->allnext != np; + prev = prev->allnext) + ; + prev->allnext = np->allnext; + } + + if (parent->child == np) + parent->child = np->sibling; + else { + struct device_node *prevsib; + for (prevsib = np->parent->child; + prevsib->sibling != np; + prevsib = prevsib->sibling) + ; + prevsib->sibling = np->sibling; + } + + of_node_set_flag(np, OF_DETACHED); + +out_unlock: + write_unlock_irqrestore(&devtree_lock, flags); +} +#endif /* defined(CONFIG_OF_DYNAMIC) */ + -- cgit v1.2.2 From 89751a7cb70a20f0d604dd7c4be29dd7b0011718 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 1 Feb 2010 21:34:11 -0700 Subject: of: merge of_find_node_by_phandle Merge common function between powerpc, sparc and microblaze. Code is identical for powerpc and microblaze, but adds a lock (and release) of the devtree_lock on sparc. Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely --- drivers/of/base.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index 2ce58be314af..785e9cc1b207 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -614,6 +614,27 @@ int of_modalias_node(struct device_node *node, char *modalias, int len) } EXPORT_SYMBOL_GPL(of_modalias_node); +/** + * of_find_node_by_phandle - Find a node given a phandle + * @handle: phandle of the node to find + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct device_node *of_find_node_by_phandle(phandle handle) +{ + struct device_node *np; + + read_lock(&devtree_lock); + for (np = allnodes; np; np = np->allnext) + if (np->phandle == handle) + break; + of_node_get(np); + read_unlock(&devtree_lock); + return np; +} +EXPORT_SYMBOL(of_find_node_by_phandle); + /** * of_parse_phandle - Resolve a phandle property to a device_node pointer * @np: Pointer to device node holding phandle property -- cgit v1.2.2 From 71a157e8edca55198e808f8561dd49017a54ee34 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Feb 2010 21:34:14 -0700 Subject: of: add 'of_' prefix to machine_is_compatible() machine is compatible is an OF-specific call. It should have the of_ prefix to protect the global namespace. Signed-off-by: Grant Likely Acked-by: Michal Simek --- drivers/char/hvc_beat.c | 2 +- drivers/gpu/drm/radeon/radeon_combios.c | 44 ++++++++++++++--------------- drivers/macintosh/adb.c | 4 +-- drivers/macintosh/therm_pm72.c | 8 +++--- drivers/macintosh/therm_windtunnel.c | 2 +- drivers/macintosh/via-pmu-backlight.c | 8 +++--- drivers/macintosh/via-pmu.c | 8 +++--- drivers/macintosh/windfarm_core.c | 6 ++-- drivers/macintosh/windfarm_cpufreq_clamp.c | 6 ++-- drivers/macintosh/windfarm_lm75_sensor.c | 6 ++-- drivers/macintosh/windfarm_max6690_sensor.c | 6 ++-- drivers/macintosh/windfarm_pm112.c | 2 +- drivers/macintosh/windfarm_pm121.c | 2 +- drivers/macintosh/windfarm_pm81.c | 4 +-- drivers/macintosh/windfarm_pm91.c | 2 +- drivers/macintosh/windfarm_smu_sensors.c | 6 ++-- drivers/net/mace.c | 2 +- drivers/of/base.c | 6 ++-- drivers/serial/pmac_zilog.c | 6 ++-- drivers/video/aty/aty128fb.c | 14 ++++----- drivers/video/aty/atyfb_base.c | 8 +++--- drivers/video/aty/radeon_backlight.c | 6 ++-- 22 files changed, 79 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvc_beat.c b/drivers/char/hvc_beat.c index 0afc8b82212e..9b397c5ee1d7 100644 --- a/drivers/char/hvc_beat.c +++ b/drivers/char/hvc_beat.c @@ -99,7 +99,7 @@ static int hvc_beat_config(char *p) static int __init hvc_beat_console_init(void) { - if (hvc_beat_useit && machine_is_compatible("Beat")) { + if (hvc_beat_useit && of_machine_is_compatible("Beat")) { hvc_instantiate(0, 0, &hvc_beat_get_put_ops); } return 0; diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 579c8920e081..13826a534065 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -1280,47 +1280,47 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) rdev->mode_info.connector_table = radeon_connector_table; if (rdev->mode_info.connector_table == CT_NONE) { #ifdef CONFIG_PPC_PMAC - if (machine_is_compatible("PowerBook3,3")) { + if (of_machine_is_compatible("PowerBook3,3")) { /* powerbook with VGA */ rdev->mode_info.connector_table = CT_POWERBOOK_VGA; - } else if (machine_is_compatible("PowerBook3,4") || - machine_is_compatible("PowerBook3,5")) { + } else if (of_machine_is_compatible("PowerBook3,4") || + of_machine_is_compatible("PowerBook3,5")) { /* powerbook with internal tmds */ rdev->mode_info.connector_table = CT_POWERBOOK_INTERNAL; - } else if (machine_is_compatible("PowerBook5,1") || - machine_is_compatible("PowerBook5,2") || - machine_is_compatible("PowerBook5,3") || - machine_is_compatible("PowerBook5,4") || - machine_is_compatible("PowerBook5,5")) { + } else if (of_machine_is_compatible("PowerBook5,1") || + of_machine_is_compatible("PowerBook5,2") || + of_machine_is_compatible("PowerBook5,3") || + of_machine_is_compatible("PowerBook5,4") || + of_machine_is_compatible("PowerBook5,5")) { /* powerbook with external single link tmds (sil164) */ rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL; - } else if (machine_is_compatible("PowerBook5,6")) { + } else if (of_machine_is_compatible("PowerBook5,6")) { /* powerbook with external dual or single link tmds */ rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL; - } else if (machine_is_compatible("PowerBook5,7") || - machine_is_compatible("PowerBook5,8") || - machine_is_compatible("PowerBook5,9")) { + } else if (of_machine_is_compatible("PowerBook5,7") || + of_machine_is_compatible("PowerBook5,8") || + of_machine_is_compatible("PowerBook5,9")) { /* PowerBook6,2 ? */ /* powerbook with external dual link tmds (sil1178?) */ rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL; - } else if (machine_is_compatible("PowerBook4,1") || - machine_is_compatible("PowerBook4,2") || - machine_is_compatible("PowerBook4,3") || - machine_is_compatible("PowerBook6,3") || - machine_is_compatible("PowerBook6,5") || - machine_is_compatible("PowerBook6,7")) { + } else if (of_machine_is_compatible("PowerBook4,1") || + of_machine_is_compatible("PowerBook4,2") || + of_machine_is_compatible("PowerBook4,3") || + of_machine_is_compatible("PowerBook6,3") || + of_machine_is_compatible("PowerBook6,5") || + of_machine_is_compatible("PowerBook6,7")) { /* ibook */ rdev->mode_info.connector_table = CT_IBOOK; - } else if (machine_is_compatible("PowerMac4,4")) { + } else if (of_machine_is_compatible("PowerMac4,4")) { /* emac */ rdev->mode_info.connector_table = CT_EMAC; - } else if (machine_is_compatible("PowerMac10,1")) { + } else if (of_machine_is_compatible("PowerMac10,1")) { /* mini with internal tmds */ rdev->mode_info.connector_table = CT_MINI_INTERNAL; - } else if (machine_is_compatible("PowerMac10,2")) { + } else if (of_machine_is_compatible("PowerMac10,2")) { /* mini with external tmds */ rdev->mode_info.connector_table = CT_MINI_EXTERNAL; - } else if (machine_is_compatible("PowerMac12,1")) { + } else if (of_machine_is_compatible("PowerMac12,1")) { /* PowerMac8,1 ? */ /* imac g5 isight */ rdev->mode_info.connector_table = CT_IMAC_G5_ISIGHT; diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 23741cec45e3..d840a109f833 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -322,8 +322,8 @@ static int __init adb_init(void) adb_controller = NULL; } else { #ifdef CONFIG_PPC - if (machine_is_compatible("AAPL,PowerBook1998") || - machine_is_compatible("PowerBook1,1")) + if (of_machine_is_compatible("AAPL,PowerBook1998") || + of_machine_is_compatible("PowerBook1,1")) sleepy_trackpad = 1; #endif /* CONFIG_PPC */ diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index 454bc501df3c..5738d8bf2d97 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c @@ -1899,7 +1899,7 @@ static int create_control_loops(void) */ if (rackmac) cpu_pid_type = CPU_PID_TYPE_RACKMAC; - else if (machine_is_compatible("PowerMac7,3") + else if (of_machine_is_compatible("PowerMac7,3") && (cpu_count > 1) && fcu_fans[CPUA_PUMP_RPM_INDEX].id != FCU_FAN_ABSENT_ID && fcu_fans[CPUB_PUMP_RPM_INDEX].id != FCU_FAN_ABSENT_ID) { @@ -2234,10 +2234,10 @@ static int __init therm_pm72_init(void) { struct device_node *np; - rackmac = machine_is_compatible("RackMac3,1"); + rackmac = of_machine_is_compatible("RackMac3,1"); - if (!machine_is_compatible("PowerMac7,2") && - !machine_is_compatible("PowerMac7,3") && + if (!of_machine_is_compatible("PowerMac7,2") && + !of_machine_is_compatible("PowerMac7,3") && !rackmac) return -ENODEV; diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index ba48fd76396e..7fb8b4da35a7 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -490,7 +490,7 @@ g4fan_init( void ) info = of_get_property(np, "thermal-info", NULL); of_node_put(np); - if( !info || !machine_is_compatible("PowerMac3,6") ) + if( !info || !of_machine_is_compatible("PowerMac3,6") ) return -ENODEV; if( info->id != 3 ) { diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c index a348bb0791d3..4f3c4479c16a 100644 --- a/drivers/macintosh/via-pmu-backlight.c +++ b/drivers/macintosh/via-pmu-backlight.c @@ -150,13 +150,13 @@ void __init pmu_backlight_init() /* Special case for the old PowerBook since I can't test on it */ autosave = - machine_is_compatible("AAPL,3400/2400") || - machine_is_compatible("AAPL,3500"); + of_machine_is_compatible("AAPL,3400/2400") || + of_machine_is_compatible("AAPL,3500"); if (!autosave && !pmac_has_backlight_type("pmu") && - !machine_is_compatible("AAPL,PowerBook1998") && - !machine_is_compatible("PowerBook1,1")) + !of_machine_is_compatible("AAPL,PowerBook1998") && + !of_machine_is_compatible("PowerBook1,1")) return; snprintf(name, sizeof(name), "pmubl"); diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index db379c381432..42764849eb78 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -463,8 +463,8 @@ static int __init via_pmu_dev_init(void) #endif #ifdef CONFIG_PPC32 - if (machine_is_compatible("AAPL,3400/2400") || - machine_is_compatible("AAPL,3500")) { + if (of_machine_is_compatible("AAPL,3400/2400") || + of_machine_is_compatible("AAPL,3500")) { int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_MODEL, 0); pmu_battery_count = 1; @@ -472,8 +472,8 @@ static int __init via_pmu_dev_init(void) pmu_batteries[0].flags |= PMU_BATT_TYPE_COMET; else pmu_batteries[0].flags |= PMU_BATT_TYPE_HOOPER; - } else if (machine_is_compatible("AAPL,PowerBook1998") || - machine_is_compatible("PowerBook1,1")) { + } else if (of_machine_is_compatible("AAPL,PowerBook1998") || + of_machine_is_compatible("PowerBook1,1")) { pmu_battery_count = 2; pmu_batteries[0].flags |= PMU_BATT_TYPE_SMART; pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART; diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c index 075b4d99e354..437f55c5d18d 100644 --- a/drivers/macintosh/windfarm_core.c +++ b/drivers/macintosh/windfarm_core.c @@ -468,9 +468,9 @@ static int __init windfarm_core_init(void) DBG("wf: core loaded\n"); /* Don't register on old machines that use therm_pm72 for now */ - if (machine_is_compatible("PowerMac7,2") || - machine_is_compatible("PowerMac7,3") || - machine_is_compatible("RackMac3,1")) + if (of_machine_is_compatible("PowerMac7,2") || + of_machine_is_compatible("PowerMac7,3") || + of_machine_is_compatible("RackMac3,1")) return -ENODEV; platform_device_register(&wf_platform_device); return 0; diff --git a/drivers/macintosh/windfarm_cpufreq_clamp.c b/drivers/macintosh/windfarm_cpufreq_clamp.c index 900aade06198..1a77a7c97d0e 100644 --- a/drivers/macintosh/windfarm_cpufreq_clamp.c +++ b/drivers/macintosh/windfarm_cpufreq_clamp.c @@ -76,9 +76,9 @@ static int __init wf_cpufreq_clamp_init(void) struct wf_control *clamp; /* Don't register on old machines that use therm_pm72 for now */ - if (machine_is_compatible("PowerMac7,2") || - machine_is_compatible("PowerMac7,3") || - machine_is_compatible("RackMac3,1")) + if (of_machine_is_compatible("PowerMac7,2") || + of_machine_is_compatible("PowerMac7,3") || + of_machine_is_compatible("RackMac3,1")) return -ENODEV; clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL); diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c index ed6426a10773..d8257d35afde 100644 --- a/drivers/macintosh/windfarm_lm75_sensor.c +++ b/drivers/macintosh/windfarm_lm75_sensor.c @@ -239,9 +239,9 @@ static struct i2c_driver wf_lm75_driver = { static int __init wf_lm75_sensor_init(void) { /* Don't register on old machines that use therm_pm72 for now */ - if (machine_is_compatible("PowerMac7,2") || - machine_is_compatible("PowerMac7,3") || - machine_is_compatible("RackMac3,1")) + if (of_machine_is_compatible("PowerMac7,2") || + of_machine_is_compatible("PowerMac7,3") || + of_machine_is_compatible("RackMac3,1")) return -ENODEV; return i2c_add_driver(&wf_lm75_driver); } diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c index a67b349319e9..b486eb929fde 100644 --- a/drivers/macintosh/windfarm_max6690_sensor.c +++ b/drivers/macintosh/windfarm_max6690_sensor.c @@ -188,9 +188,9 @@ static struct i2c_driver wf_max6690_driver = { static int __init wf_max6690_sensor_init(void) { /* Don't register on old machines that use therm_pm72 for now */ - if (machine_is_compatible("PowerMac7,2") || - machine_is_compatible("PowerMac7,3") || - machine_is_compatible("RackMac3,1")) + if (of_machine_is_compatible("PowerMac7,2") || + of_machine_is_compatible("PowerMac7,3") || + of_machine_is_compatible("RackMac3,1")) return -ENODEV; return i2c_add_driver(&wf_max6690_driver); } diff --git a/drivers/macintosh/windfarm_pm112.c b/drivers/macintosh/windfarm_pm112.c index 73d695dc9e50..e0ee80700cde 100644 --- a/drivers/macintosh/windfarm_pm112.c +++ b/drivers/macintosh/windfarm_pm112.c @@ -676,7 +676,7 @@ static int __init wf_pm112_init(void) { struct device_node *cpu; - if (!machine_is_compatible("PowerMac11,2")) + if (!of_machine_is_compatible("PowerMac11,2")) return -ENODEV; /* Count the number of CPU cores */ diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c index 66ec4fb115bb..947d4afa25ca 100644 --- a/drivers/macintosh/windfarm_pm121.c +++ b/drivers/macintosh/windfarm_pm121.c @@ -1008,7 +1008,7 @@ static int __init pm121_init(void) { int rc = -ENODEV; - if (machine_is_compatible("PowerMac12,1")) + if (of_machine_is_compatible("PowerMac12,1")) rc = pm121_init_pm(); if (rc == 0) { diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c index abbe206474f5..565d5b2adc95 100644 --- a/drivers/macintosh/windfarm_pm81.c +++ b/drivers/macintosh/windfarm_pm81.c @@ -779,8 +779,8 @@ static int __init wf_smu_init(void) { int rc = -ENODEV; - if (machine_is_compatible("PowerMac8,1") || - machine_is_compatible("PowerMac8,2")) + if (of_machine_is_compatible("PowerMac8,1") || + of_machine_is_compatible("PowerMac8,2")) rc = wf_init_pm(); if (rc == 0) { diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c index 764c525b2117..bea99168ff35 100644 --- a/drivers/macintosh/windfarm_pm91.c +++ b/drivers/macintosh/windfarm_pm91.c @@ -711,7 +711,7 @@ static int __init wf_smu_init(void) { int rc = -ENODEV; - if (machine_is_compatible("PowerMac9,1")) + if (of_machine_is_compatible("PowerMac9,1")) rc = wf_init_pm(); if (rc == 0) { diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c index 9c567b93f417..3c193504bb80 100644 --- a/drivers/macintosh/windfarm_smu_sensors.c +++ b/drivers/macintosh/windfarm_smu_sensors.c @@ -363,9 +363,9 @@ smu_cpu_power_create(struct wf_sensor *volts, struct wf_sensor *amps) * I yet have to figure out what's up with 8,2 and will have to * adjust for later, unless we can 100% trust the SDB partition... */ - if ((machine_is_compatible("PowerMac8,1") || - machine_is_compatible("PowerMac8,2") || - machine_is_compatible("PowerMac9,1")) && + if ((of_machine_is_compatible("PowerMac8,1") || + of_machine_is_compatible("PowerMac8,2") || + of_machine_is_compatible("PowerMac9,1")) && cpuvcp_version >= 2) { pow->quadratic = 1; DBG("windfarm: CPU Power using quadratic transform\n"); diff --git a/drivers/net/mace.c b/drivers/net/mace.c index d9fbad386389..43aea91e3369 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -206,7 +206,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i mp->port_aaui = port_aaui; else { /* Apple Network Server uses the AAUI port */ - if (machine_is_compatible("AAPL,ShinerESB")) + if (of_machine_is_compatible("AAPL,ShinerESB")) mp->port_aaui = 1; else { #ifdef CONFIG_MACE_AAUI_PORT diff --git a/drivers/of/base.c b/drivers/of/base.c index 785e9cc1b207..6bc8740c21ad 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -219,13 +219,13 @@ int of_device_is_compatible(const struct device_node *device, EXPORT_SYMBOL(of_device_is_compatible); /** - * machine_is_compatible - Test root of device tree for a given compatible value + * of_machine_is_compatible - Test root of device tree for a given compatible value * @compat: compatible string to look for in root node's compatible property. * * Returns true if the root node has the given value in its * compatible property. */ -int machine_is_compatible(const char *compat) +int of_machine_is_compatible(const char *compat) { struct device_node *root; int rc = 0; @@ -237,7 +237,7 @@ int machine_is_compatible(const char *compat) } return rc; } -EXPORT_SYMBOL(machine_is_compatible); +EXPORT_SYMBOL(of_machine_is_compatible); /** * of_device_is_available - check if a device is available for use diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c index 683e66f18e8c..3e2ae4807ae2 100644 --- a/drivers/serial/pmac_zilog.c +++ b/drivers/serial/pmac_zilog.c @@ -2031,9 +2031,9 @@ static int __init pmz_console_setup(struct console *co, char *options) /* * XServe's default to 57600 bps */ - if (machine_is_compatible("RackMac1,1") - || machine_is_compatible("RackMac1,2") - || machine_is_compatible("MacRISC4")) + if (of_machine_is_compatible("RackMac1,1") + || of_machine_is_compatible("RackMac1,2") + || of_machine_is_compatible("MacRISC4")) baud = 57600; /* diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index e4e4d433b007..9ee67d6da710 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -1931,22 +1931,22 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i * PowerMac2,2 summer 2000 iMacs * PowerMac4,1 january 2001 iMacs "flower power" */ - if (machine_is_compatible("PowerMac2,1") || - machine_is_compatible("PowerMac2,2") || - machine_is_compatible("PowerMac4,1")) + if (of_machine_is_compatible("PowerMac2,1") || + of_machine_is_compatible("PowerMac2,2") || + of_machine_is_compatible("PowerMac4,1")) default_vmode = VMODE_1024_768_75; /* iBook SE */ - if (machine_is_compatible("PowerBook2,2")) + if (of_machine_is_compatible("PowerBook2,2")) default_vmode = VMODE_800_600_60; /* PowerBook Firewire (Pismo), iBook Dual USB */ - if (machine_is_compatible("PowerBook3,1") || - machine_is_compatible("PowerBook4,1")) + if (of_machine_is_compatible("PowerBook3,1") || + of_machine_is_compatible("PowerBook4,1")) default_vmode = VMODE_1024_768_60; /* PowerBook Titanium */ - if (machine_is_compatible("PowerBook3,2")) + if (of_machine_is_compatible("PowerBook3,2")) default_vmode = VMODE_1152_768_60; if (default_cmode > 16) diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 5f1b5807a48f..e45ab8db2ddc 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2439,7 +2439,7 @@ static int __devinit aty_init(struct fb_info *info) * The Apple iBook1 uses non-standard memory frequencies. * We detect it and set the frequency manually. */ - if (machine_is_compatible("PowerBook2,1")) { + if (of_machine_is_compatible("PowerBook2,1")) { par->pll_limits.mclk = 70; par->pll_limits.xclk = 53; } @@ -2659,7 +2659,7 @@ static int __devinit aty_init(struct fb_info *info) FBINFO_HWACCEL_YPAN; #ifdef CONFIG_PMAC_BACKLIGHT - if (M64_HAS(G3_PB_1_1) && machine_is_compatible("PowerBook1,1")) { + if (M64_HAS(G3_PB_1_1) && of_machine_is_compatible("PowerBook1,1")) { /* * these bits let the 101 powerbook * wake up from sleep -- paulus @@ -2690,9 +2690,9 @@ static int __devinit aty_init(struct fb_info *info) if (M64_HAS(G3_PB_1024x768)) /* G3 PowerBook with 1024x768 LCD */ default_vmode = VMODE_1024_768_60; - else if (machine_is_compatible("iMac")) + else if (of_machine_is_compatible("iMac")) default_vmode = VMODE_1024_768_75; - else if (machine_is_compatible("PowerBook2,1")) + else if (of_machine_is_compatible("PowerBook2,1")) /* iBook with 800x600 LCD */ default_vmode = VMODE_800_600_60; else diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c index 1a056adb61c8..fa1198c4ccc5 100644 --- a/drivers/video/aty/radeon_backlight.c +++ b/drivers/video/aty/radeon_backlight.c @@ -175,9 +175,9 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo) #ifdef CONFIG_PMAC_BACKLIGHT pdata->negative = pdata->negative || - machine_is_compatible("PowerBook4,3") || - machine_is_compatible("PowerBook6,3") || - machine_is_compatible("PowerBook6,5"); + of_machine_is_compatible("PowerBook4,3") || + of_machine_is_compatible("PowerBook6,3") || + of_machine_is_compatible("PowerBook6,5"); #endif rinfo->info->bl_dev = bd; -- cgit v1.2.2 From 51975db0b7333cf389b64b5040c2a910341d241a Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Feb 2010 21:34:14 -0700 Subject: of/flattree: merge early_init_dt_scan_memory() common code Merge common code between PowerPC and Microblaze architectures. Signed-off-by: Grant Likely Acked-by: Michal Simek --- drivers/of/fdt.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 7f8861121a31..f84152d112b0 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -15,6 +15,7 @@ #include #include + #ifdef CONFIG_PPC #include #endif /* CONFIG_PPC */ @@ -443,6 +444,55 @@ u64 __init dt_mem_next_cell(int s, u32 **cellp) return of_read_number(p, s); } +/** + * early_init_dt_scan_memory - Look for an parse memory nodes + */ +int __init early_init_dt_scan_memory(unsigned long node, const char *uname, + int depth, void *data) +{ + char *type = of_get_flat_dt_prop(node, "device_type", NULL); + __be32 *reg, *endp; + unsigned long l; + + /* We are scanning "memory" nodes only */ + if (type == NULL) { + /* + * The longtrail doesn't have a device_type on the + * /memory node, so look for the node called /memory@0. + */ + if (depth != 1 || strcmp(uname, "memory@0") != 0) + return 0; + } else if (strcmp(type, "memory") != 0) + return 0; + + reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l); + if (reg == NULL) + reg = of_get_flat_dt_prop(node, "reg", &l); + if (reg == NULL) + return 0; + + endp = reg + (l / sizeof(__be32)); + + pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n", + uname, l, reg[0], reg[1], reg[2], reg[3]); + + while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { + u64 base, size; + + base = dt_mem_next_cell(dt_root_addr_cells, ®); + size = dt_mem_next_cell(dt_root_size_cells, ®); + + if (size == 0) + continue; + pr_debug(" - %llx , %llx\n", (unsigned long long)base, + (unsigned long long)size); + + early_init_dt_add_memory_arch(base, size); + } + + return 0; +} + int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, int depth, void *data) { -- cgit v1.2.2 From a9f2f63a671d5e91ed89ade408d87f1692a373de Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 1 Feb 2010 21:34:14 -0700 Subject: of: include linux/proc_fs.h We use a few procfs-specific functions (eg, proc_device_tree_*) which aren't covered by the current includes. This causes the following build error on arm: drivers/of/base.c: In function 'prom_add_property': drivers/of/base.c:861: error: implicit declaration of function 'proc_device_tree_add_prop' drivers/of/base.c: In function 'prom_remove_property': drivers/of/base.c:902: error: implicit declaration of function 'proc_device_tree_remove_prop' drivers/of/base.c: In function 'prom_update_property': drivers/of/base.c:946: error: implicit declaration of function 'proc_device_tree_update_prop' Add proc_fs.h for these prototypes. Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely --- drivers/of/base.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index 6bc8740c21ad..524645ab42a4 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -20,6 +20,7 @@ #include #include #include +#include struct device_node *allnodes; -- cgit v1.2.2 From 1406bc2f57787797d1f6a3675c019a7093769275 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Sat, 30 Jan 2010 01:31:21 -0700 Subject: of/flattree: use callback to setup initrd from /chosen At present, the fdt code sets the kernel-wide initrd_start and initrd_end variables when parsing /chosen. On ARM, we only set these once the bootmem has been reserved. This change adds an arch hook to setup the initrd from the device tree: void early_init_dt_setup_initrd_arch(unsigned long start, unsigned long end); The arch-specific code can then setup the initrd however it likes. Compiled on powerpc, with CONFIG_BLK_DEV_INITRD=y and =n. Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely --- drivers/of/fdt.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index f84152d112b0..9290ca5aa892 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -384,28 +384,23 @@ unsigned long __init unflatten_dt_node(unsigned long mem, */ void __init early_init_dt_check_for_initrd(unsigned long node) { - unsigned long len; + unsigned long start, end, len; u32 *prop; pr_debug("Looking for initrd properties... "); prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len); - if (prop) { - initrd_start = (unsigned long) - __va(of_read_ulong(prop, len/4)); - - prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len); - if (prop) { - initrd_end = (unsigned long) - __va(of_read_ulong(prop, len/4)); - initrd_below_start_ok = 1; - } else { - initrd_start = 0; - } - } + if (!prop) + return; + start = of_read_ulong(prop, len/4); + + prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len); + if (!prop) + return; + end = of_read_ulong(prop, len/4); - pr_debug("initrd_start=0x%lx initrd_end=0x%lx\n", - initrd_start, initrd_end); + early_init_dt_setup_initrd_arch(start, end); + pr_debug("initrd_start=0x%lx initrd_end=0x%lx\n", start, end); } #else inline void early_init_dt_check_for_initrd(unsigned long node) -- cgit v1.2.2 From 36b9d3070d653af5807cef74ff129721d9047107 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 1 Feb 2010 21:34:14 -0700 Subject: of/flattree: use OF_ROOT_NODE_{SIZE,ADDR}_CELLS DEFAULT for fdt parsing At present we're using hard-coded values for defaults when parsing the FDT. This change uses the #defines instead. Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely --- drivers/of/fdt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 9290ca5aa892..56fbd6e3122a 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -420,11 +420,11 @@ int __init early_init_dt_scan_root(unsigned long node, const char *uname, return 0; prop = of_get_flat_dt_prop(node, "#size-cells", NULL); - dt_root_size_cells = (prop == NULL) ? 1 : *prop; + dt_root_size_cells = prop ? *prop : OF_ROOT_NODE_SIZE_CELLS_DEFAULT; pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells); prop = of_get_flat_dt_prop(node, "#address-cells", NULL); - dt_root_addr_cells = (prop == NULL) ? 2 : *prop; + dt_root_addr_cells = prop ? *prop : OF_ROOT_NODE_ADDR_CELLS_DEFAULT; pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells); /* break now */ -- cgit v1.2.2 From 2e89e685a8fd0e8334de967739d11e2e28c1a4dd Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Sat, 30 Jan 2010 01:41:49 -0700 Subject: of: use __be32 for cell value accessors Currently, we're using u32 for cell values, and hence assuming host-endian device trees. As we'd like to support little-endian platforms, use a __be32 for cell values, and convert in the cell accessors. Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely --- drivers/of/fdt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 56fbd6e3122a..968a86af5301 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -431,9 +431,9 @@ int __init early_init_dt_scan_root(unsigned long node, const char *uname, return 1; } -u64 __init dt_mem_next_cell(int s, u32 **cellp) +u64 __init dt_mem_next_cell(int s, __be32 **cellp) { - u32 *p = *cellp; + __be32 *p = *cellp; *cellp = p + s; return of_read_number(p, s); -- cgit v1.2.2 From 337148812f97368a8ec4a69f1691e4c5ce3af494 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Sat, 30 Jan 2010 01:45:26 -0700 Subject: of: assume big-endian properties, adding conversions where necessary Properties in the device tree are specified as big-endian. At present, the only platforms to support device trees are also big-endian, so we've been acessing the properties as raw values. We'd like to add device tree support to little-endian platforms too, so add endian conversion to the sites where we access property values in the common of code. Compiled on powerpc (ppc44x_defconfig & ppc64_defconfig) and arm (fdt support only for now). Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely --- drivers/of/base.c | 12 ++++++------ drivers/of/fdt.c | 45 +++++++++++++++++++++++++-------------------- drivers/of/gpio.c | 13 +++++++------ drivers/of/of_i2c.c | 4 ++-- drivers/of/of_mdio.c | 8 ++++---- drivers/of/of_spi.c | 6 +++--- 6 files changed, 47 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index 524645ab42a4..873479a21c80 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -38,7 +38,7 @@ int of_n_addr_cells(struct device_node *np) np = np->parent; ip = of_get_property(np, "#address-cells", NULL); if (ip) - return *ip; + return be32_to_cpup(ip); } while (np->parent); /* No #address-cells property for the root node */ return OF_ROOT_NODE_ADDR_CELLS_DEFAULT; @@ -54,7 +54,7 @@ int of_n_size_cells(struct device_node *np) np = np->parent; ip = of_get_property(np, "#size-cells", NULL); if (ip) - return *ip; + return be32_to_cpup(ip); } while (np->parent); /* No #size-cells property for the root node */ return OF_ROOT_NODE_SIZE_CELLS_DEFAULT; @@ -696,8 +696,8 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name, const void **out_args) { int ret = -EINVAL; - const u32 *list; - const u32 *list_end; + const __be32 *list; + const __be32 *list_end; int size; int cur_index = 0; struct device_node *node = NULL; @@ -711,7 +711,7 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name, list_end = list + size / sizeof(*list); while (list < list_end) { - const u32 *cells; + const __be32 *cells; const phandle *phandle; phandle = list++; @@ -735,7 +735,7 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name, goto err1; } - list += *cells; + list += be32_to_cpup(cells); if (list > list_end) { pr_debug("%s: insufficient arguments length\n", np->full_name); diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 968a86af5301..5c5f03ef7f06 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -51,7 +51,7 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, int depth = -1; do { - u32 tag = *((u32 *)p); + u32 tag = be32_to_cpup((__be32 *)p); char *pathp; p += 4; @@ -64,7 +64,7 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, if (tag == OF_DT_END) break; if (tag == OF_DT_PROP) { - u32 sz = *((u32 *)p); + u32 sz = be32_to_cpup((__be32 *)p); p += 8; if (initial_boot_params->version < 0x10) p = _ALIGN(p, sz >= 8 ? 8 : 4); @@ -103,9 +103,9 @@ unsigned long __init of_get_flat_dt_root(void) unsigned long p = ((unsigned long)initial_boot_params) + initial_boot_params->off_dt_struct; - while (*((u32 *)p) == OF_DT_NOP) + while (be32_to_cpup((__be32 *)p) == OF_DT_NOP) p += 4; - BUG_ON(*((u32 *)p) != OF_DT_BEGIN_NODE); + BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE); p += 4; return _ALIGN(p + strlen((char *)p) + 1, 4); } @@ -122,7 +122,7 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name, unsigned long p = node; do { - u32 tag = *((u32 *)p); + u32 tag = be32_to_cpup((__be32 *)p); u32 sz, noff; const char *nstr; @@ -132,8 +132,8 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name, if (tag != OF_DT_PROP) return NULL; - sz = *((u32 *)p); - noff = *((u32 *)(p + 4)); + sz = be32_to_cpup((__be32 *)p); + noff = be32_to_cpup((__be32 *)(p + 4)); p += 8; if (initial_boot_params->version < 0x10) p = _ALIGN(p, sz >= 8 ? 8 : 4); @@ -210,7 +210,7 @@ unsigned long __init unflatten_dt_node(unsigned long mem, int has_name = 0; int new_format = 0; - tag = *((u32 *)(*p)); + tag = be32_to_cpup((__be32 *)(*p)); if (tag != OF_DT_BEGIN_NODE) { pr_err("Weird tag at start of node: %x\n", tag); return mem; @@ -285,7 +285,7 @@ unsigned long __init unflatten_dt_node(unsigned long mem, u32 sz, noff; char *pname; - tag = *((u32 *)(*p)); + tag = be32_to_cpup((__be32 *)(*p)); if (tag == OF_DT_NOP) { *p += 4; continue; @@ -293,8 +293,8 @@ unsigned long __init unflatten_dt_node(unsigned long mem, if (tag != OF_DT_PROP) break; *p += 4; - sz = *((u32 *)(*p)); - noff = *((u32 *)((*p) + 4)); + sz = be32_to_cpup((__be32 *)(*p)); + noff = be32_to_cpup((__be32 *)((*p) + 4)); *p += 8; if (initial_boot_params->version < 0x10) *p = _ALIGN(*p, sz >= 8 ? 8 : 4); @@ -367,7 +367,7 @@ unsigned long __init unflatten_dt_node(unsigned long mem, } while (tag == OF_DT_BEGIN_NODE) { mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); - tag = *((u32 *)(*p)); + tag = be32_to_cpup((__be32 *)(*p)); } if (tag != OF_DT_END_NODE) { pr_err("Weird tag at end of node: %x\n", tag); @@ -385,7 +385,7 @@ unsigned long __init unflatten_dt_node(unsigned long mem, void __init early_init_dt_check_for_initrd(unsigned long node) { unsigned long start, end, len; - u32 *prop; + __be32 *prop; pr_debug("Looking for initrd properties... "); @@ -414,17 +414,22 @@ inline void early_init_dt_check_for_initrd(unsigned long node) int __init early_init_dt_scan_root(unsigned long node, const char *uname, int depth, void *data) { - u32 *prop; + __be32 *prop; if (depth != 0) return 0; + dt_root_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT; + dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT; + prop = of_get_flat_dt_prop(node, "#size-cells", NULL); - dt_root_size_cells = prop ? *prop : OF_ROOT_NODE_SIZE_CELLS_DEFAULT; + if (prop) + dt_root_size_cells = be32_to_cpup(prop); pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells); prop = of_get_flat_dt_prop(node, "#address-cells", NULL); - dt_root_addr_cells = prop ? *prop : OF_ROOT_NODE_ADDR_CELLS_DEFAULT; + if (prop) + dt_root_addr_cells = be32_to_cpup(prop); pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells); /* break now */ @@ -549,7 +554,7 @@ void __init unflatten_device_tree(void) mem = lmb_alloc(size + 4, __alignof__(struct device_node)); mem = (unsigned long) __va(mem); - ((u32 *)mem)[size / 4] = 0xdeadbeef; + ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef); pr_debug(" unflattening %lx...\n", mem); @@ -557,11 +562,11 @@ void __init unflatten_device_tree(void) start = ((unsigned long)initial_boot_params) + initial_boot_params->off_dt_struct; unflatten_dt_node(mem, &start, NULL, &allnextp, 0); - if (*((u32 *)start) != OF_DT_END) + if (be32_to_cpup((__be32 *)start) != OF_DT_END) pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start)); - if (((u32 *)mem)[size / 4] != 0xdeadbeef) + if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef) pr_warning("End of tree marker overwritten: %08x\n", - ((u32 *)mem)[size / 4]); + be32_to_cpu(((__be32 *)mem)[size / 4])); *allnextp = NULL; /* Get pointer to OF "/chosen" node for use everywhere */ diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c index 6eea601a9204..24c3606217f8 100644 --- a/drivers/of/gpio.c +++ b/drivers/of/gpio.c @@ -36,7 +36,7 @@ int of_get_gpio_flags(struct device_node *np, int index, struct of_gpio_chip *of_gc = NULL; int size; const void *gpio_spec; - const u32 *gpio_cells; + const __be32 *gpio_cells; ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index, &gc, &gpio_spec); @@ -55,7 +55,7 @@ int of_get_gpio_flags(struct device_node *np, int index, gpio_cells = of_get_property(gc, "#gpio-cells", &size); if (!gpio_cells || size != sizeof(*gpio_cells) || - *gpio_cells != of_gc->gpio_cells) { + be32_to_cpup(gpio_cells) != of_gc->gpio_cells) { pr_debug("%s: wrong #gpio-cells for %s\n", np->full_name, gc->full_name); ret = -EINVAL; @@ -127,7 +127,8 @@ EXPORT_SYMBOL(of_gpio_count); int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np, const void *gpio_spec, enum of_gpio_flags *flags) { - const u32 *gpio = gpio_spec; + const __be32 *gpio = gpio_spec; + const u32 n = be32_to_cpup(gpio); /* * We're discouraging gpio_cells < 2, since that way you'll have to @@ -140,13 +141,13 @@ int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np, return -EINVAL; } - if (*gpio > of_gc->gc.ngpio) + if (n > of_gc->gc.ngpio) return -EINVAL; if (flags) - *flags = gpio[1]; + *flags = be32_to_cpu(gpio[1]); - return *gpio; + return n; } EXPORT_SYMBOL(of_gpio_simple_xlate); diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c index fa65a2b2ae2e..a3a708e590d0 100644 --- a/drivers/of/of_i2c.c +++ b/drivers/of/of_i2c.c @@ -25,7 +25,7 @@ void of_register_i2c_devices(struct i2c_adapter *adap, for_each_child_of_node(adap_node, node) { struct i2c_board_info info = {}; struct dev_archdata dev_ad = {}; - const u32 *addr; + const __be32 *addr; int len; if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) @@ -40,7 +40,7 @@ void of_register_i2c_devices(struct i2c_adapter *adap, info.irq = irq_of_parse_and_map(node, 0); - info.addr = *addr; + info.addr = be32_to_cpup(addr); dev_archdata_set_node(&dev_ad, node); info.archdata = &dev_ad; diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index 4b22ba568b19..18ecae4a4375 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -51,7 +51,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) /* Loop over the child nodes and register a phy_device for each one */ for_each_child_of_node(np, child) { - const u32 *addr; + const __be32 *addr; int len; /* A PHY must have a reg property in the range [0-31] */ @@ -68,7 +68,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) mdio->irq[*addr] = PHY_POLL; } - phy = get_phy_device(mdio, *addr); + phy = get_phy_device(mdio, be32_to_cpup(addr)); if (!phy) { dev_err(&mdio->dev, "error probing PHY at address %i\n", *addr); @@ -160,7 +160,7 @@ struct phy_device *of_phy_connect_fixed_link(struct net_device *dev, struct device_node *net_np; char bus_id[MII_BUS_ID_SIZE + 3]; struct phy_device *phy; - const u32 *phy_id; + const __be32 *phy_id; int sz; if (!dev->dev.parent) @@ -174,7 +174,7 @@ struct phy_device *of_phy_connect_fixed_link(struct net_device *dev, if (!phy_id || sz < sizeof(*phy_id)) return NULL; - sprintf(bus_id, PHY_ID_FMT, "0", phy_id[0]); + sprintf(bus_id, PHY_ID_FMT, "0", be32_to_cpu(phy_id[0])); phy = phy_connect(dev, bus_id, hndlr, 0, iface); return IS_ERR(phy) ? NULL : phy; diff --git a/drivers/of/of_spi.c b/drivers/of/of_spi.c index bed0ed6dcdc1..f65f48b98448 100644 --- a/drivers/of/of_spi.c +++ b/drivers/of/of_spi.c @@ -23,7 +23,7 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np) { struct spi_device *spi; struct device_node *nc; - const u32 *prop; + const __be32 *prop; int rc; int len; @@ -54,7 +54,7 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np) spi_dev_put(spi); continue; } - spi->chip_select = *prop; + spi->chip_select = be32_to_cpup(prop); /* Mode (clock phase/polarity/etc.) */ if (of_find_property(nc, "spi-cpha", NULL)) @@ -72,7 +72,7 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np) spi_dev_put(spi); continue; } - spi->max_speed_hz = *prop; + spi->max_speed_hz = be32_to_cpup(prop); /* IRQ */ spi->irq = irq_of_parse_and_map(nc, 0); -- cgit v1.2.2 From 087f79c48c090a2c0cd9ee45231d63290d2036d2 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Sat, 30 Jan 2010 04:14:19 -0700 Subject: of/flattree: endian-convert members of boot_param_header The boot_param_header has big-endian fields, so change the types to __be32, and perform endian conversion when we access them. Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely --- drivers/of/fdt.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 5c5f03ef7f06..18d282fefe58 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -28,7 +28,7 @@ struct boot_param_header *initial_boot_params; char *find_flat_dt_string(u32 offset) { return ((char *)initial_boot_params) + - initial_boot_params->off_dt_strings + offset; + be32_to_cpu(initial_boot_params->off_dt_strings) + offset; } /** @@ -46,7 +46,7 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, void *data) { unsigned long p = ((unsigned long)initial_boot_params) + - initial_boot_params->off_dt_struct; + be32_to_cpu(initial_boot_params->off_dt_struct); int rc = 0; int depth = -1; @@ -66,7 +66,7 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, if (tag == OF_DT_PROP) { u32 sz = be32_to_cpup((__be32 *)p); p += 8; - if (initial_boot_params->version < 0x10) + if (be32_to_cpu(initial_boot_params->version) < 0x10) p = _ALIGN(p, sz >= 8 ? 8 : 4); p += sz; p = _ALIGN(p, 4); @@ -101,7 +101,7 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, unsigned long __init of_get_flat_dt_root(void) { unsigned long p = ((unsigned long)initial_boot_params) + - initial_boot_params->off_dt_struct; + be32_to_cpu(initial_boot_params->off_dt_struct); while (be32_to_cpup((__be32 *)p) == OF_DT_NOP) p += 4; @@ -135,7 +135,7 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name, sz = be32_to_cpup((__be32 *)p); noff = be32_to_cpup((__be32 *)(p + 4)); p += 8; - if (initial_boot_params->version < 0x10) + if (be32_to_cpu(initial_boot_params->version) < 0x10) p = _ALIGN(p, sz >= 8 ? 8 : 4); nstr = find_flat_dt_string(noff); @@ -296,7 +296,7 @@ unsigned long __init unflatten_dt_node(unsigned long mem, sz = be32_to_cpup((__be32 *)(*p)); noff = be32_to_cpup((__be32 *)((*p) + 4)); *p += 8; - if (initial_boot_params->version < 0x10) + if (be32_to_cpu(initial_boot_params->version) < 0x10) *p = _ALIGN(*p, sz >= 8 ? 8 : 4); pname = find_flat_dt_string(noff); @@ -544,7 +544,7 @@ void __init unflatten_device_tree(void) /* First pass, scan for size */ start = ((unsigned long)initial_boot_params) + - initial_boot_params->off_dt_struct; + be32_to_cpu(initial_boot_params->off_dt_struct); size = unflatten_dt_node(0, &start, NULL, NULL, 0); size = (size | 3) + 1; @@ -560,7 +560,7 @@ void __init unflatten_device_tree(void) /* Second pass, do actual unflattening */ start = ((unsigned long)initial_boot_params) + - initial_boot_params->off_dt_struct; + be32_to_cpu(initial_boot_params->off_dt_struct); unflatten_dt_node(mem, &start, NULL, &allnextp, 0); if (be32_to_cpup((__be32 *)start) != OF_DT_END) pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start)); -- cgit v1.2.2 From 04b954a673dd02f585a2769c4945a43880faa989 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 1 Feb 2010 21:34:15 -0700 Subject: of/flattree: Make the kernel accept ePAPR style phandle information Currently when processing flattened device trees, the kernel expects the phandle in a property called "linux,phandle". The ePAPR spec - not being Linux specific - instead requires phandles to be encoded in a property named simply "phandle". This patch makes the kernel accept either form when unflattening the device tree. Signed-off-by: David Gibson Signed-off-by: Grant Likely --- drivers/of/fdt.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 18d282fefe58..b51f797d9d9d 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -310,10 +310,19 @@ unsigned long __init unflatten_dt_node(unsigned long mem, pp = unflatten_dt_alloc(&mem, sizeof(struct property), __alignof__(struct property)); if (allnextpp) { - if (strcmp(pname, "linux,phandle") == 0) { + /* We accept flattened tree phandles either in + * ePAPR-style "phandle" properties, or the + * legacy "linux,phandle" properties. If both + * appear and have different values, things + * will get weird. Don't do that. */ + if ((strcmp(pname, "phandle") == 0) || + (strcmp(pname, "linux,phandle") == 0)) { if (np->phandle == 0) np->phandle = *((u32 *)*p); } + /* And we process the "ibm,phandle" property + * used in pSeries dynamic device tree + * stuff */ if (strcmp(pname, "ibm,phandle") == 0) np->phandle = *((u32 *)*p); pp->name = pname; -- cgit v1.2.2 From b32758c7216f337044ceb6dcaa754b8eda95a59f Mon Sep 17 00:00:00 2001 From: Stephane Chatty Date: Wed, 10 Feb 2010 12:09:17 +0100 Subject: HID: fixed bug in single-touch emulation on the stantum panel Fixed stupid copy-paste bug in touchscreen emulation for the Stantum multitouch panel: a flag was reset just before being tested. Signed-off-by: Stephane Chatty Signed-off-by: Jiri Kosina --- drivers/hid/hid-stantum.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c index add965dab932..1b7b1659e7bb 100644 --- a/drivers/hid/hid-stantum.c +++ b/drivers/hid/hid-stantum.c @@ -147,7 +147,6 @@ static void stantum_filter_event(struct stantum_data *sd, input_mt_sync(input); sd->valid = false; - sd->first = false; /* touchscreen emulation */ if (sd->first) { @@ -158,6 +157,7 @@ static void stantum_filter_event(struct stantum_data *sd, input_event(input, EV_ABS, ABS_X, sd->x); input_event(input, EV_ABS, ABS_Y, sd->y); } + sd->first = false; } -- cgit v1.2.2 From 580363db92572cccbe6226bf83321e50a9ea50ea Mon Sep 17 00:00:00 2001 From: Stephane Chatty Date: Sat, 6 Feb 2010 15:20:03 +0100 Subject: HID: add pressure support for the Stantum multitouch panel Added pressure handling for Stantum multitouch panels Signed-off-by: Stephane Chatty Signed-off-by: Jiri Kosina --- drivers/hid/hid-stantum.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c index 1b7b1659e7bb..04b0b986f5f4 100644 --- a/drivers/hid/hid-stantum.c +++ b/drivers/hid/hid-stantum.c @@ -66,7 +66,6 @@ static int stantum_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_DG_DEVICEINDEX: case HID_DG_CONTACTCOUNT: case HID_DG_CONTACTMAX: - case HID_DG_TIPPRESSURE: return -1; case HID_DG_TIPSWITCH: @@ -84,6 +83,11 @@ static int stantum_input_mapping(struct hid_device *hdev, struct hid_input *hi, input_set_abs_params(hi->input, ABS_MT_ORIENTATION, 1, 1, 0, 0); return 1; + case HID_DG_TIPPRESSURE: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_PRESSURE); + return 1; + case HID_DG_CONTACTID: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TRACKING_ID); @@ -140,10 +144,7 @@ static void stantum_filter_event(struct stantum_data *sd, input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, wide ? sd->w : sd->h); input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, wide ? sd->h : sd->w); -#if 0 - /* MT_PRESSURE does not exist yet */ input_event(input, EV_ABS, ABS_MT_PRESSURE, sd->z); -#endif input_mt_sync(input); sd->valid = false; -- cgit v1.2.2 From 77f720b71d88a3cbf574c113566a31c93099f97d Mon Sep 17 00:00:00 2001 From: Stephane Chatty Date: Sat, 6 Feb 2010 15:17:13 +0100 Subject: HID: Support for MosArt multitouch panel Added support for MosArt dual-touch panels, present in the Asus T91MT notebook. Signed-off-by: Stephane Chatty Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 6 ++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 5 +- drivers/hid/hid-ids.h | 9 +- drivers/hid/hid-mosart.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 290 insertions(+), 5 deletions(-) create mode 100644 drivers/hid/hid-mosart.c (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 617ed7db67d1..2b93d7f647ee 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -204,6 +204,12 @@ config HID_MICROSOFT ---help--- Support for Microsoft devices that are not fully compliant with HID standard. +config HID_MOSART + tristate "MosArt" + depends on USB_HID + ---help--- + Support for MosArt dual-touch panels. + config HID_MONTEREY tristate "Monterey" if EMBEDDED depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index b62d4b3afdc2..03051694d546 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_HID_KYE) += hid-kye.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o +obj-$(CONFIG_HID_MOSART) += hid-mosart.o obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o obj-$(CONFIG_HID_ORTEK) += hid-ortek.o obj-$(CONFIG_HID_QUANTA) += hid-quanta.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 282f4a1e7214..da97195474ff 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1550,8 +1550,9 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) }, { HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) }, { HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM)}, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM2)}, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT)}, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)}, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)}, { HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) }, { HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) }, { HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 282bfe8d95e8..ab370f1c4b6e 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -99,9 +99,12 @@ #define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241 #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 -#define USB_VENDOR_ID_ASUS 0x0b05 -#define USB_DEVICE_ID_ASUS_LCM 0x1726 -#define USB_DEVICE_ID_ASUS_LCM2 0x175b +#define USB_VENDOR_ID_ASUS 0x0486 +#define USB_DEVICE_ID_ASUS_T91MT 0x0185 + +#define USB_VENDOR_ID_ASUSTEK 0x0b05 +#define USB_DEVICE_ID_ASUSTEK_LCM 0x1726 +#define USB_DEVICE_ID_ASUSTEK_LCM2 0x175b #define USB_VENDOR_ID_ATEN 0x0557 #define USB_DEVICE_ID_ATEN_UC100KM 0x2004 diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c new file mode 100644 index 000000000000..f6ec4f150859 --- /dev/null +++ b/drivers/hid/hid-mosart.c @@ -0,0 +1,274 @@ +/* + * HID driver for the multitouch panel on the ASUS EeePC T91MT + * + * Copyright (c) 2009-2010 Stephane Chatty + * Copyright (c) 2010 Teemu Tuominen + * + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include +#include "usbhid/usbhid.h" + +MODULE_VERSION("1.00"); +MODULE_AUTHOR("Stephane Chatty "); +MODULE_DESCRIPTION("MosArt dual-touch panel"); +MODULE_LICENSE("GPL"); + +#include "hid-ids.h" + +struct mosart_data { + __u16 x, y; + __u8 id; + bool valid; /* valid finger data, or just placeholder? */ + bool first; /* is this the first finger in this frame? */ + bool activity_now; /* at least one active finger in this frame? */ + bool activity; /* at least one active finger previously? */ +}; + +static int mosart_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + switch (usage->hid & HID_USAGE_PAGE) { + + case HID_UP_GENDESK: + switch (usage->hid) { + case HID_GD_X: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_X); + /* touchscreen emulation */ + input_set_abs_params(hi->input, ABS_X, + field->logical_minimum, + field->logical_maximum, 0, 0); + return 1; + case HID_GD_Y: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_Y); + /* touchscreen emulation */ + input_set_abs_params(hi->input, ABS_Y, + field->logical_minimum, + field->logical_maximum, 0, 0); + return 1; + } + return 0; + + case HID_UP_DIGITIZER: + switch (usage->hid) { + case HID_DG_CONFIDENCE: + case HID_DG_TIPSWITCH: + case HID_DG_INPUTMODE: + case HID_DG_DEVICEINDEX: + case HID_DG_CONTACTCOUNT: + case HID_DG_CONTACTMAX: + case HID_DG_TIPPRESSURE: + case HID_DG_WIDTH: + case HID_DG_HEIGHT: + return -1; + case HID_DG_INRANGE: + /* touchscreen emulation */ + hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); + return 1; + + case HID_DG_CONTACTID: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_TRACKING_ID); + return 1; + + } + return 0; + + case 0xff000000: + /* ignore HID features */ + return -1; + } + + return 0; +} + +static int mosart_input_mapped(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if (usage->type == EV_KEY || usage->type == EV_ABS) + clear_bit(usage->code, *bit); + + return 0; +} + +/* + * this function is called when a whole finger has been parsed, + * so that it can decide what to send to the input layer. + */ +static void mosart_filter_event(struct mosart_data *td, struct input_dev *input) +{ + td->first = !td->first; /* touchscreen emulation */ + + if (!td->valid) { + /* + * touchscreen emulation: if no finger in this frame is valid + * and there previously was finger activity, this is a release + */ + if (!td->first && !td->activity_now && td->activity) { + input_event(input, EV_KEY, BTN_TOUCH, 0); + td->activity = false; + } + return; + } + + input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id); + input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y); + + input_mt_sync(input); + td->valid = false; + + /* touchscreen emulation: if first active finger in this frame... */ + if (!td->activity_now) { + /* if there was no previous activity, emit touch event */ + if (!td->activity) { + input_event(input, EV_KEY, BTN_TOUCH, 1); + td->activity = true; + } + td->activity_now = true; + /* and in any case this is our preferred finger */ + input_event(input, EV_ABS, ABS_X, td->x); + input_event(input, EV_ABS, ABS_Y, td->y); + } +} + + +static int mosart_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct mosart_data *td = hid_get_drvdata(hid); + + if (hid->claimed & HID_CLAIMED_INPUT) { + struct input_dev *input = field->hidinput->input; + switch (usage->hid) { + case HID_DG_INRANGE: + td->valid = !!value; + break; + case HID_GD_X: + td->x = value; + break; + case HID_GD_Y: + td->y = value; + mosart_filter_event(td, input); + break; + case HID_DG_CONTACTID: + td->id = value; + break; + case HID_DG_CONTACTCOUNT: + /* touch emulation: this is the last field in a frame */ + td->first = false; + td->activity_now = false; + break; + case HID_DG_CONFIDENCE: + case HID_DG_TIPSWITCH: + /* avoid interference from generic hidinput handling */ + break; + + default: + /* fallback to the generic hidinput handling */ + return 0; + } + } + + /* we have handled the hidinput part, now remains hiddev */ + if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) + hid->hiddev_hid_event(hid, field, usage, value); + + return 1; +} + +static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + struct mosart_data *td; + + + td = kmalloc(sizeof(struct mosart_data), GFP_KERNEL); + if (!td) { + dev_err(&hdev->dev, "cannot allocate MosArt data\n"); + return -ENOMEM; + } + td->valid = false; + td->activity = false; + td->activity_now = false; + td->first = false; + hid_set_drvdata(hdev, td); + + /* currently, it's better to have one evdev device only */ +#if 0 + hdev->quirks |= HID_QUIRK_MULTI_INPUT; +#endif + + ret = hid_parse(hdev); + if (ret == 0) + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + + if (ret == 0) { + struct hid_report_enum *re = hdev->report_enum + + HID_FEATURE_REPORT; + struct hid_report *r = re->report_id_hash[7]; + + r->field[0]->value[0] = 0x02; + usbhid_submit_report(hdev, r, USB_DIR_OUT); + } else + kfree(td); + + return ret; +} + +static void mosart_remove(struct hid_device *hdev) +{ + hid_hw_stop(hdev); + kfree(hid_get_drvdata(hdev)); + hid_set_drvdata(hdev, NULL); +} + +static const struct hid_device_id mosart_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) }, + { } +}; +MODULE_DEVICE_TABLE(hid, mosart_devices); + +static const struct hid_usage_id mosart_grabbed_usages[] = { + { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, + { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} +}; + +static struct hid_driver mosart_driver = { + .name = "mosart", + .id_table = mosart_devices, + .probe = mosart_probe, + .remove = mosart_remove, + .input_mapping = mosart_input_mapping, + .input_mapped = mosart_input_mapped, + .usage_table = mosart_grabbed_usages, + .event = mosart_event, +}; + +static int __init mosart_init(void) +{ + return hid_register_driver(&mosart_driver); +} + +static void __exit mosart_exit(void) +{ + hid_unregister_driver(&mosart_driver); +} + +module_init(mosart_init); +module_exit(mosart_exit); + -- cgit v1.2.2 From 90a006abf8015c8cab893555244d8fc673b24839 Mon Sep 17 00:00:00 2001 From: Michael Poole Date: Sun, 24 Jan 2010 22:32:29 -0500 Subject: HID: Export hid_register_report The Apple Magic Mouse (and probably other devices) publish reports that are not called out in their HID report descriptors -- they only send them when enabled through other writes to the device. This allows a driver to handle these unlisted reports. Signed-off-by: Michael Poole Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index f7f80e1f1eef..66a91eb3e4c4 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -51,7 +51,7 @@ EXPORT_SYMBOL_GPL(hid_debug); * Register a new report for a device. */ -static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id) +struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id) { struct hid_report_enum *report_enum = device->report_enum + type; struct hid_report *report; @@ -75,6 +75,7 @@ static struct hid_report *hid_register_report(struct hid_device *device, unsigne return report; } +EXPORT_SYMBOL_GPL(hid_register_report); /* * Register a new field for this report. -- cgit v1.2.2 From 128537cea464d919febeaea2000e256749f317eb Mon Sep 17 00:00:00 2001 From: Michael Poole Date: Sat, 6 Feb 2010 12:24:36 -0500 Subject: HID: add a device driver for the Apple Magic Mouse. The Magic Mouse requires that a driver send an unlock Report(Feature) command, similar to the Wacom wireless tablet and Sixaxis controller quirks. This turns on an Input Report that isn't published in the input Report descriptor that contains touch data (and usually overrides the normal motion and click Report). Because the mouse has only one switch and no scroll wheel, the driver (under control of parameters) emulates a middle button and scroll wheel. User space could also ignore and/or re-synthesize those events based on the reported events. Some user-space tools to talk to the mouse directly (that is, when it is not associated with the host's HIDP stack) are at http://github.com/entrope/linux-magicmouse Signed-off-by: Michael Poole Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 10 + drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-magicmouse.c | 469 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 482 insertions(+) create mode 100644 drivers/hid/hid-magicmouse.c (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 24d90ea246ce..ba14ec898258 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -183,6 +183,16 @@ config LOGIRUMBLEPAD2_FF Say Y here if you want to enable force feedback support for Logitech Rumblepad 2 devices. +config HID_MAGICMOUSE + tristate "Apple" if EMBEDDED + depends on BT_HIDP + default !EMBEDDED + ---help--- + Support for the Apple Magic Mouse. + + Say Y here if you want support for the multi-touch features of the + Apple Wireless "Magic" Mouse. + config HID_MICROSOFT tristate "Microsoft" if EMBEDDED depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 0de2dff5542c..45d81e9cd2de 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o obj-$(CONFIG_HID_KYE) += hid-kye.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o +obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 66a91eb3e4c4..f038422f432c 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1254,6 +1254,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 010368e649ed..11e521864abb 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -56,6 +56,7 @@ #define USB_VENDOR_ID_APPLE 0x05ac #define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304 +#define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d #define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e #define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f #define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214 diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c new file mode 100644 index 000000000000..f94b3e43c5b6 --- /dev/null +++ b/drivers/hid/hid-magicmouse.c @@ -0,0 +1,469 @@ +/* + * Apple "Magic" Wireless Mouse driver + * + * Copyright (c) 2010 Michael Poole + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include + +#include "hid-ids.h" + +static bool emulate_3button = 1; +module_param(emulate_3button, bool, 0644); +MODULE_PARM_DESC(emulate_3button, "Emulate a middle button"); + +static int middle_button_start = -350; +static int middle_button_stop = +350; + +static bool emulate_scroll_wheel = 1; +module_param(emulate_scroll_wheel, bool, 0644); +MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel"); + +static bool report_touches = 1; +module_param(report_touches, bool, 0644); +MODULE_PARM_DESC(report_touches, "Emit touch records (otherwise, only use them for emulation)"); + +static bool report_undeciphered = 0; +module_param(report_undeciphered, bool, 0644); +MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state field using a MSC_RAW event"); + +#define TOUCH_REPORT_ID 0x29 +/* These definitions are not precise, but they're close enough. (Bits + * 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem + * to be some kind of bit mask -- 0x20 may be a near-field reading, + * and 0x40 is actual contact, and 0x10 may be a start/stop or change + * indication.) + */ +#define TOUCH_STATE_MASK 0xf0 +#define TOUCH_STATE_NONE 0x00 +#define TOUCH_STATE_START 0x30 +#define TOUCH_STATE_DRAG 0x40 + +/** + * struct magicmouse_sc - Tracks Magic Mouse-specific data. + * @input: Input device through which we report events. + * @quirks: Currently unused. + * @last_timestamp: Timestamp from most recent (18-bit) touch report + * (units of milliseconds over short windows, but seems to + * increase faster when there are no touches). + * @delta_time: 18-bit difference between the two most recent touch + * reports from the mouse. + * @ntouches: Number of touches in most recent touch report. + * @scroll_accel: Number of consecutive scroll motions. + * @scroll_jiffies: Time of last scroll motion. + * @touches: Most recent data for a touch, indexed by tracking ID. + * @tracking_ids: Mapping of current touch input data to @touches. + */ +struct magicmouse_sc { + struct input_dev *input; + unsigned long quirks; + + int last_timestamp; + int delta_time; + int ntouches; + int scroll_accel; + unsigned long scroll_jiffies; + + struct { + short x; + short y; + short scroll_y; + u8 size; + } touches[16]; + int tracking_ids[16]; +}; + +static int magicmouse_firm_touch(struct magicmouse_sc *msc) +{ + int touch = -1; + int ii; + + /* If there is only one "firm" touch, set touch to its + * tracking ID. + */ + for (ii = 0; ii < msc->ntouches; ii++) { + int idx = msc->tracking_ids[ii]; + if (msc->touches[idx].size < 8) { + /* Ignore this touch. */ + } else if (touch >= 0) { + touch = -1; + break; + } else { + touch = idx; + } + } + + return touch; +} + +static void magicmouse_emit_buttons(struct magicmouse_sc *msc, int state) +{ + int last_state = test_bit(BTN_LEFT, msc->input->key) << 0 | + test_bit(BTN_RIGHT, msc->input->key) << 1 | + test_bit(BTN_MIDDLE, msc->input->key) << 2; + + if (emulate_3button) { + int id; + + /* If some button was pressed before, keep it held + * down. Otherwise, if there's exactly one firm + * touch, use that to override the mouse's guess. + */ + if (state == 0) { + /* The button was released. */ + } else if (last_state != 0) { + state = last_state; + } else if ((id = magicmouse_firm_touch(msc)) >= 0) { + int x = msc->touches[id].x; + if (x < middle_button_start) + state = 1; + else if (x > middle_button_stop) + state = 2; + else + state = 4; + } /* else: we keep the mouse's guess */ + + input_report_key(msc->input, BTN_MIDDLE, state & 4); + } + + input_report_key(msc->input, BTN_LEFT, state & 1); + input_report_key(msc->input, BTN_RIGHT, state & 2); + + if (state != last_state) + msc->scroll_accel = 0; +} + +static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tdata) +{ + struct input_dev *input = msc->input; + __s32 x_y = tdata[0] << 8 | tdata[1] << 16 | tdata[2] << 24; + int misc = tdata[5] | tdata[6] << 8; + int id = (misc >> 6) & 15; + int x = x_y << 12 >> 20; + int y = -(x_y >> 20); + + /* Store tracking ID and other fields. */ + msc->tracking_ids[raw_id] = id; + msc->touches[id].x = x; + msc->touches[id].y = y; + msc->touches[id].size = misc & 63; + + /* If requested, emulate a scroll wheel by detecting small + * vertical touch motions along the middle of the mouse. + */ + if (emulate_scroll_wheel && + middle_button_start < x && x < middle_button_stop) { + static const int accel_profile[] = { + 256, 228, 192, 160, 128, 96, 64, 32, + }; + unsigned long now = jiffies; + int step = msc->touches[id].scroll_y - y; + + /* Reset acceleration after half a second. */ + if (time_after(now, msc->scroll_jiffies + HZ / 2)) + msc->scroll_accel = 0; + + /* Calculate and apply the scroll motion. */ + switch (tdata[7] & TOUCH_STATE_MASK) { + case TOUCH_STATE_START: + msc->touches[id].scroll_y = y; + msc->scroll_accel = min_t(int, msc->scroll_accel + 1, + ARRAY_SIZE(accel_profile) - 1); + break; + case TOUCH_STATE_DRAG: + step = step / accel_profile[msc->scroll_accel]; + if (step != 0) { + msc->touches[id].scroll_y = y; + msc->scroll_jiffies = now; + input_report_rel(input, REL_WHEEL, step); + } + break; + } + } + + /* Generate the input events for this touch. */ + if (report_touches) { + int orientation = (misc >> 10) - 32; + + input_report_abs(input, ABS_MT_TRACKING_ID, id); + input_report_abs(input, ABS_MT_TOUCH_MAJOR, tdata[3]); + input_report_abs(input, ABS_MT_TOUCH_MINOR, tdata[4]); + input_report_abs(input, ABS_MT_ORIENTATION, orientation); + input_report_abs(input, ABS_MT_POSITION_X, x); + input_report_abs(input, ABS_MT_POSITION_Y, y); + + if (report_undeciphered) { + input_event(input, EV_MSC, MSC_RAW, tdata[7]); + } + + input_mt_sync(input); + } +} + +static int magicmouse_raw_event(struct hid_device *hdev, + struct hid_report *report, u8 *data, int size) +{ + struct magicmouse_sc *msc = hid_get_drvdata(hdev); + struct input_dev *input = msc->input; + int x, y, ts, ii, clicks; + + switch (data[0]) { + case 0x10: + if (size != 6) + return 0; + x = (__s16)(data[2] | data[3] << 8); + y = (__s16)(data[4] | data[5] << 8); + clicks = data[1]; + break; + case TOUCH_REPORT_ID: + /* Expect six bytes of prefix, and N*8 bytes of touch data. */ + if (size < 6 || ((size - 6) % 8) != 0) + return 0; + ts = data[3] >> 6 | data[4] << 2 | data[5] << 10; + msc->delta_time = (ts - msc->last_timestamp) & 0x3ffff; + msc->last_timestamp = ts; + msc->ntouches = (size - 6) / 8; + for (ii = 0; ii < msc->ntouches; ii++) + magicmouse_emit_touch(msc, ii, data + ii * 8 + 6); + /* When emulating three-button mode, it is important + * to have the current touch information before + * generating a click event. + */ + x = (signed char)data[1]; + y = (signed char)data[2]; + clicks = data[3]; + break; + case 0x20: /* Theoretically battery status (0-100), but I have + * never seen it -- maybe it is only upon request. + */ + case 0x60: /* Unknown, maybe laser on/off. */ + case 0x61: /* Laser reflection status change. + * data[1]: 0 = spotted, 1 = lost + */ + default: + return 0; + } + + magicmouse_emit_buttons(msc, clicks & 3); + input_report_rel(input, REL_X, x); + input_report_rel(input, REL_Y, y); + input_sync(input); + return 1; +} + +static int magicmouse_input_open(struct input_dev *dev) +{ + struct hid_device *hid = input_get_drvdata(dev); + + return hid->ll_driver->open(hid); +} + +static void magicmouse_input_close(struct input_dev *dev) +{ + struct hid_device *hid = input_get_drvdata(dev); + + hid->ll_driver->close(hid); +} + +static void magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev) +{ + input_set_drvdata(input, hdev); + input->event = hdev->ll_driver->hidinput_input_event; + input->open = magicmouse_input_open; + input->close = magicmouse_input_close; + + input->name = hdev->name; + input->phys = hdev->phys; + input->uniq = hdev->uniq; + input->id.bustype = hdev->bus; + input->id.vendor = hdev->vendor; + input->id.product = hdev->product; + input->id.version = hdev->version; + input->dev.parent = hdev->dev.parent; + + set_bit(EV_KEY, input->evbit); + set_bit(BTN_LEFT, input->keybit); + set_bit(BTN_RIGHT, input->keybit); + if (emulate_3button) + set_bit(BTN_MIDDLE, input->keybit); + set_bit(BTN_TOOL_FINGER, input->keybit); + + set_bit(EV_REL, input->evbit); + set_bit(REL_X, input->relbit); + set_bit(REL_Y, input->relbit); + if (emulate_scroll_wheel) + set_bit(REL_WHEEL, input->relbit); + + if (report_touches) { + set_bit(EV_ABS, input->evbit); + + set_bit(ABS_MT_TRACKING_ID, input->absbit); + input->absmin[ABS_MT_TRACKING_ID] = 0; + input->absmax[ABS_MT_TRACKING_ID] = 15; + input->absfuzz[ABS_MT_TRACKING_ID] = 0; + + set_bit(ABS_MT_TOUCH_MAJOR, input->absbit); + input->absmin[ABS_MT_TOUCH_MAJOR] = 0; + input->absmax[ABS_MT_TOUCH_MAJOR] = 255; + input->absfuzz[ABS_MT_TOUCH_MAJOR] = 4; + + set_bit(ABS_MT_TOUCH_MINOR, input->absbit); + input->absmin[ABS_MT_TOUCH_MINOR] = 0; + input->absmax[ABS_MT_TOUCH_MINOR] = 255; + input->absfuzz[ABS_MT_TOUCH_MINOR] = 4; + + set_bit(ABS_MT_ORIENTATION, input->absbit); + input->absmin[ABS_MT_ORIENTATION] = -32; + input->absmax[ABS_MT_ORIENTATION] = 31; + input->absfuzz[ABS_MT_ORIENTATION] = 1; + + set_bit(ABS_MT_POSITION_X, input->absbit); + input->absmin[ABS_MT_POSITION_X] = -1100; + input->absmax[ABS_MT_POSITION_X] = 1358; + input->absfuzz[ABS_MT_POSITION_X] = 4; + + /* Note: Touch Y position from the device is inverted relative + * to how pointer motion is reported (and relative to how USB + * HID recommends the coordinates work). This driver keeps + * the origin at the same position, and just uses the additive + * inverse of the reported Y. + */ + set_bit(ABS_MT_POSITION_Y, input->absbit); + input->absmin[ABS_MT_POSITION_Y] = -1589; + input->absmax[ABS_MT_POSITION_Y] = 2047; + input->absfuzz[ABS_MT_POSITION_Y] = 4; + } + + if (report_undeciphered) { + set_bit(EV_MSC, input->evbit); + set_bit(MSC_RAW, input->mscbit); + } +} + +static int magicmouse_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + __u8 feature_1[] = { 0xd7, 0x01 }; + __u8 feature_2[] = { 0xf8, 0x01, 0x32 }; + struct input_dev *input; + struct magicmouse_sc *msc; + struct hid_report *report; + int ret; + + msc = kzalloc(sizeof(*msc), GFP_KERNEL); + if (msc == NULL) { + dev_err(&hdev->dev, "can't alloc magicmouse descriptor\n"); + return -ENOMEM; + } + + msc->quirks = id->driver_data; + hid_set_drvdata(hdev, msc); + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "magicmouse hid parse failed\n"); + goto err_free; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) { + dev_err(&hdev->dev, "magicmouse hw start failed\n"); + goto err_free; + } + + report = hid_register_report(hdev, HID_INPUT_REPORT, TOUCH_REPORT_ID); + if (!report) { + dev_err(&hdev->dev, "unable to register touch report\n"); + ret = -ENOMEM; + goto err_free; + } + report->size = 6; + + ret = hdev->hid_output_raw_report(hdev, feature_1, sizeof(feature_1), + HID_FEATURE_REPORT); + if (ret != sizeof(feature_1)) { + dev_err(&hdev->dev, "unable to request touch data (1:%d)\n", + ret); + goto err_free; + } + ret = hdev->hid_output_raw_report(hdev, feature_2, + sizeof(feature_2), HID_FEATURE_REPORT); + if (ret != sizeof(feature_2)) { + dev_err(&hdev->dev, "unable to request touch data (2:%d)\n", + ret); + goto err_free; + } + + input = input_allocate_device(); + if (!input) { + dev_err(&hdev->dev, "can't alloc input device\n"); + ret = -ENOMEM; + goto err_free; + } + magicmouse_setup_input(input, hdev); + + ret = input_register_device(input); + if (ret) { + dev_err(&hdev->dev, "input device registration failed\n"); + goto err_both; + } + msc->input = input; + + return 0; + err_both: + input_free_device(input); + err_free: + kfree(msc); + return ret; +} + +static void magicmouse_remove(struct hid_device *hdev) +{ + hid_hw_stop(hdev); + kfree(hid_get_drvdata(hdev)); +} + +static const struct hid_device_id magic_mice[] = { + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE), + .driver_data = 0 }, + { } +}; +MODULE_DEVICE_TABLE(hid, magic_mice); + +static struct hid_driver magicmouse_driver = { + .name = "magicmouse", + .id_table = magic_mice, + .probe = magicmouse_probe, + .remove = magicmouse_remove, + .raw_event = magicmouse_raw_event, +}; + +static int __init magicmouse_init(void) +{ + int ret; + + ret = hid_register_driver(&magicmouse_driver); + if (ret) + printk(KERN_ERR "can't register magicmouse driver\n"); + + return ret; +} + +static void __exit magicmouse_exit(void) +{ + hid_unregister_driver(&magicmouse_driver); +} + +module_init(magicmouse_init); +module_exit(magicmouse_exit); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 9f5231472340ebcaf2dec75428b67d5d0d872857 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 10 Feb 2010 14:59:03 +0100 Subject: HID: fix up Kconfig entry for MagicMouse Make Apple MagicMouse Kconfig entry consistent with other dirvers. Also expand the tristate text a little bit more, so that it doesn't clash with already existing HID_APPLE. Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index ba14ec898258..0e668ccc2511 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -184,11 +184,10 @@ config LOGIRUMBLEPAD2_FF Rumblepad 2 devices. config HID_MAGICMOUSE - tristate "Apple" if EMBEDDED + tristate "Apple MagicMouse multi-touch support" depends on BT_HIDP - default !EMBEDDED ---help--- - Support for the Apple Magic Mouse. + Support for the Apple Magic Mouse multi-touch. Say Y here if you want support for the multi-touch features of the Apple Wireless "Magic" Mouse. -- cgit v1.2.2 From c8a8602b76b6703df1243e31be01cf0e4451e4a6 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 10 Feb 2010 15:29:02 +0100 Subject: HID: remove MODULE_VERSION from new drivers MODULE_VERSION doesn't make too much sense for drivers merged into main tree, as git is much better tracking revisions than any developer might ever be. Signed-off-by: Jiri Kosina --- drivers/hid/hid-3m-pct.c | 1 - drivers/hid/hid-mosart.c | 1 - drivers/hid/hid-quanta.c | 1 - drivers/hid/hid-stantum.c | 1 - 4 files changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c index 6d11e3dbbbff..2370aefc86b2 100644 --- a/drivers/hid/hid-3m-pct.c +++ b/drivers/hid/hid-3m-pct.c @@ -17,7 +17,6 @@ #include #include -MODULE_VERSION("0.6"); MODULE_AUTHOR("Stephane Chatty "); MODULE_DESCRIPTION("3M PCT multitouch panels"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c index f6ec4f150859..c8718168fe42 100644 --- a/drivers/hid/hid-mosart.c +++ b/drivers/hid/hid-mosart.c @@ -19,7 +19,6 @@ #include #include "usbhid/usbhid.h" -MODULE_VERSION("1.00"); MODULE_AUTHOR("Stephane Chatty "); MODULE_DESCRIPTION("MosArt dual-touch panel"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-quanta.c b/drivers/hid/hid-quanta.c index 9ac49287b943..01dd51c4986c 100644 --- a/drivers/hid/hid-quanta.c +++ b/drivers/hid/hid-quanta.c @@ -16,7 +16,6 @@ #include #include -MODULE_VERSION("1.00"); MODULE_AUTHOR("Stephane Chatty "); MODULE_DESCRIPTION("Quanta dual-touch panel"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c index 04b0b986f5f4..2e592a06654e 100644 --- a/drivers/hid/hid-stantum.c +++ b/drivers/hid/hid-stantum.c @@ -16,7 +16,6 @@ #include #include -MODULE_VERSION("0.6"); MODULE_AUTHOR("Stephane Chatty "); MODULE_DESCRIPTION("Stantum HID multitouch panels"); MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 71b38bd4c1cc4f2b653064357e4efab77dfd711d Mon Sep 17 00:00:00 2001 From: Michael Poole Date: Thu, 11 Feb 2010 00:32:57 -0500 Subject: HID: magicmouse: coding style and probe failure fixes Use proper values to initialize bool configuration variables, tabs rather than spaces, no braces for one-line else clause, __set_bit() when the operation doesn't have to be atomic, input_set_abs_params() rather than writing the fields directly, and call hid_hw_stop() when appropriate to handle failures in the probe. Signed-off-by: Michael Poole Signed-off-by: Jiri Kosina --- drivers/hid/hid-magicmouse.c | 100 +++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index f94b3e43c5b6..4a3a94f2b10c 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -18,22 +18,22 @@ #include "hid-ids.h" -static bool emulate_3button = 1; +static bool emulate_3button = true; module_param(emulate_3button, bool, 0644); MODULE_PARM_DESC(emulate_3button, "Emulate a middle button"); static int middle_button_start = -350; static int middle_button_stop = +350; -static bool emulate_scroll_wheel = 1; +static bool emulate_scroll_wheel = true; module_param(emulate_scroll_wheel, bool, 0644); MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel"); -static bool report_touches = 1; +static bool report_touches = true; module_param(report_touches, bool, 0644); MODULE_PARM_DESC(report_touches, "Emit touch records (otherwise, only use them for emulation)"); -static bool report_undeciphered = 0; +static bool report_undeciphered; module_param(report_undeciphered, bool, 0644); MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state field using a MSC_RAW event"); @@ -108,9 +108,9 @@ static int magicmouse_firm_touch(struct magicmouse_sc *msc) static void magicmouse_emit_buttons(struct magicmouse_sc *msc, int state) { - int last_state = test_bit(BTN_LEFT, msc->input->key) << 0 | - test_bit(BTN_RIGHT, msc->input->key) << 1 | - test_bit(BTN_MIDDLE, msc->input->key) << 2; + int last_state = test_bit(BTN_LEFT, msc->input->key) << 0 | + test_bit(BTN_RIGHT, msc->input->key) << 1 | + test_bit(BTN_MIDDLE, msc->input->key) << 2; if (emulate_3button) { int id; @@ -177,7 +177,7 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda switch (tdata[7] & TOUCH_STATE_MASK) { case TOUCH_STATE_START: msc->touches[id].scroll_y = y; - msc->scroll_accel = min_t(int, msc->scroll_accel + 1, + msc->scroll_accel = min_t(int, msc->scroll_accel + 1, ARRAY_SIZE(accel_profile) - 1); break; case TOUCH_STATE_DRAG: @@ -193,7 +193,7 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda /* Generate the input events for this touch. */ if (report_touches) { - int orientation = (misc >> 10) - 32; + int orientation = (misc >> 10) - 32; input_report_abs(input, ABS_MT_TRACKING_ID, id); input_report_abs(input, ABS_MT_TOUCH_MAJOR, tdata[3]); @@ -202,9 +202,8 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda input_report_abs(input, ABS_MT_POSITION_X, x); input_report_abs(input, ABS_MT_POSITION_Y, y); - if (report_undeciphered) { + if (report_undeciphered) input_event(input, EV_MSC, MSC_RAW, tdata[7]); - } input_mt_sync(input); } @@ -291,62 +290,41 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h input->id.version = hdev->version; input->dev.parent = hdev->dev.parent; - set_bit(EV_KEY, input->evbit); - set_bit(BTN_LEFT, input->keybit); - set_bit(BTN_RIGHT, input->keybit); + __set_bit(EV_KEY, input->evbit); + __set_bit(BTN_LEFT, input->keybit); + __set_bit(BTN_RIGHT, input->keybit); if (emulate_3button) - set_bit(BTN_MIDDLE, input->keybit); - set_bit(BTN_TOOL_FINGER, input->keybit); + __set_bit(BTN_MIDDLE, input->keybit); + __set_bit(BTN_TOOL_FINGER, input->keybit); - set_bit(EV_REL, input->evbit); - set_bit(REL_X, input->relbit); - set_bit(REL_Y, input->relbit); + __set_bit(EV_REL, input->evbit); + __set_bit(REL_X, input->relbit); + __set_bit(REL_Y, input->relbit); if (emulate_scroll_wheel) - set_bit(REL_WHEEL, input->relbit); + __set_bit(REL_WHEEL, input->relbit); if (report_touches) { - set_bit(EV_ABS, input->evbit); - - set_bit(ABS_MT_TRACKING_ID, input->absbit); - input->absmin[ABS_MT_TRACKING_ID] = 0; - input->absmax[ABS_MT_TRACKING_ID] = 15; - input->absfuzz[ABS_MT_TRACKING_ID] = 0; - - set_bit(ABS_MT_TOUCH_MAJOR, input->absbit); - input->absmin[ABS_MT_TOUCH_MAJOR] = 0; - input->absmax[ABS_MT_TOUCH_MAJOR] = 255; - input->absfuzz[ABS_MT_TOUCH_MAJOR] = 4; - - set_bit(ABS_MT_TOUCH_MINOR, input->absbit); - input->absmin[ABS_MT_TOUCH_MINOR] = 0; - input->absmax[ABS_MT_TOUCH_MINOR] = 255; - input->absfuzz[ABS_MT_TOUCH_MINOR] = 4; - - set_bit(ABS_MT_ORIENTATION, input->absbit); - input->absmin[ABS_MT_ORIENTATION] = -32; - input->absmax[ABS_MT_ORIENTATION] = 31; - input->absfuzz[ABS_MT_ORIENTATION] = 1; - - set_bit(ABS_MT_POSITION_X, input->absbit); - input->absmin[ABS_MT_POSITION_X] = -1100; - input->absmax[ABS_MT_POSITION_X] = 1358; - input->absfuzz[ABS_MT_POSITION_X] = 4; - + __set_bit(EV_ABS, input->evbit); + + input_set_abs_params(input, ABS_MT_TRACKING_ID, 0, 15, 0, 0); + input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 4, 0); + input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 4, 0); + input_set_abs_params(input, ABS_MT_ORIENTATION, -32, 31, 1, 0); + input_set_abs_params(input, ABS_MT_POSITION_X, -1100, 1358, + 4, 0); /* Note: Touch Y position from the device is inverted relative * to how pointer motion is reported (and relative to how USB * HID recommends the coordinates work). This driver keeps * the origin at the same position, and just uses the additive * inverse of the reported Y. */ - set_bit(ABS_MT_POSITION_Y, input->absbit); - input->absmin[ABS_MT_POSITION_Y] = -1589; - input->absmax[ABS_MT_POSITION_Y] = 2047; - input->absfuzz[ABS_MT_POSITION_Y] = 4; + input_set_abs_params(input, ABS_MT_POSITION_Y, -1589, 2047, + 4, 0); } if (report_undeciphered) { - set_bit(EV_MSC, input->evbit); - set_bit(MSC_RAW, input->mscbit); + __set_bit(EV_MSC, input->evbit); + __set_bit(MSC_RAW, input->mscbit); } } @@ -385,7 +363,7 @@ static int magicmouse_probe(struct hid_device *hdev, if (!report) { dev_err(&hdev->dev, "unable to register touch report\n"); ret = -ENOMEM; - goto err_free; + goto err_stop_hw; } report->size = 6; @@ -394,35 +372,37 @@ static int magicmouse_probe(struct hid_device *hdev, if (ret != sizeof(feature_1)) { dev_err(&hdev->dev, "unable to request touch data (1:%d)\n", ret); - goto err_free; + goto err_stop_hw; } ret = hdev->hid_output_raw_report(hdev, feature_2, sizeof(feature_2), HID_FEATURE_REPORT); if (ret != sizeof(feature_2)) { dev_err(&hdev->dev, "unable to request touch data (2:%d)\n", ret); - goto err_free; + goto err_stop_hw; } input = input_allocate_device(); if (!input) { dev_err(&hdev->dev, "can't alloc input device\n"); ret = -ENOMEM; - goto err_free; + goto err_stop_hw; } magicmouse_setup_input(input, hdev); ret = input_register_device(input); if (ret) { dev_err(&hdev->dev, "input device registration failed\n"); - goto err_both; + goto err_input; } msc->input = input; return 0; - err_both: +err_input: input_free_device(input); - err_free: +err_stop_hw: + hid_hw_stop(hdev); +err_free: kfree(msc); return ret; } -- cgit v1.2.2 From 858155fbcc0cd713f6382c527bb1c3abc0ed6d00 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 12 Feb 2010 13:02:28 +0100 Subject: HID: usbhid: introduce timeout for stuck ctrl/out URBs Some devices do not react to a control request (seen on APC UPS's) resulting in a slow stream of messages, "generic-usb ... control queue full". Therefore request needs a timeout. Cc: stable@kernel.org Signed-off-by: Oliver Neukum Signed-off-by: David Fries Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 28 ++++++++++++++++++++++++++-- drivers/hid/usbhid/usbhid.h | 2 ++ 2 files changed, 28 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 54060741d45b..74bd3ca220d3 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -316,6 +316,7 @@ static int hid_submit_out(struct hid_device *hid) err_hid("usb_submit_urb(out) failed"); return -1; } + usbhid->last_out = jiffies; } else { /* * queue work to wake up the device. @@ -377,6 +378,7 @@ static int hid_submit_ctrl(struct hid_device *hid) err_hid("usb_submit_urb(ctrl) failed"); return -1; } + usbhid->last_ctrl = jiffies; } else { /* * queue work to wake up the device. @@ -512,9 +514,20 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re usbhid->out[usbhid->outhead].report = report; usbhid->outhead = head; - if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) + if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) { if (hid_submit_out(hid)) clear_bit(HID_OUT_RUNNING, &usbhid->iofl); + } else { + /* + * the queue is known to run + * but an earlier request may be stuck + * we may need to time out + * no race because this is called under + * spinlock + */ + if (time_after(jiffies, usbhid->last_out + HZ * 5)) + usb_unlink_urb(usbhid->urbout); + } return; } @@ -535,9 +548,20 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re usbhid->ctrl[usbhid->ctrlhead].dir = dir; usbhid->ctrlhead = head; - if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) + if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) { if (hid_submit_ctrl(hid)) clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); + } else { + /* + * the queue is known to run + * but an earlier request may be stuck + * we may need to time out + * no race because this is called under + * spinlock + */ + if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) + usb_unlink_urb(usbhid->urbctrl); + } } void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h index 08f505ca2e3d..ec20400c7f29 100644 --- a/drivers/hid/usbhid/usbhid.h +++ b/drivers/hid/usbhid/usbhid.h @@ -80,12 +80,14 @@ struct usbhid_device { unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */ char *ctrlbuf; /* Control buffer */ dma_addr_t ctrlbuf_dma; /* Control buffer dma */ + unsigned long last_ctrl; /* record of last output for timeouts */ struct urb *urbout; /* Output URB */ struct hid_output_fifo out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ unsigned char outhead, outtail; /* Output pipe fifo head & tail */ char *outbuf; /* Output buffer */ dma_addr_t outbuf_dma; /* Output buffer dma */ + unsigned long last_out; /* record of last output for timeouts */ spinlock_t lock; /* fifo spinlock */ unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ -- cgit v1.2.2 From 4ef7b373df330bc0ff037dc4792d373c9346375f Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Sun, 14 Feb 2010 07:13:47 -0700 Subject: of/flattree: Don't assume HAVE_LMB We don't always have lmb available, so make arches provide an early_init_dt_alloc_memory_arch() to handle the allocation of memory in the fdt code. When we don't have lmb.h included, we need asm/page.h for __va. Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt Acked-by: Michal Simek --- drivers/of/fdt.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index b51f797d9d9d..406757a9d7ea 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -10,16 +10,18 @@ */ #include -#include #include #include #include - +#include +#include #ifdef CONFIG_PPC #include #endif /* CONFIG_PPC */ +#include + int __initdata dt_root_addr_cells; int __initdata dt_root_size_cells; @@ -560,7 +562,8 @@ void __init unflatten_device_tree(void) pr_debug(" size is %lx, allocating...\n", size); /* Allocate memory for the expanded device tree */ - mem = lmb_alloc(size + 4, __alignof__(struct device_node)); + mem = early_init_dt_alloc_memory_arch(size + 4, + __alignof__(struct device_node)); mem = (unsigned long) __va(mem); ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef); -- cgit v1.2.2 From fc0bdae49d810e4cb32d7b547bc6d4dfb08f9e2e Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sun, 14 Feb 2010 07:13:55 -0700 Subject: of: move definition of of_chosen into common code. Rather than defining of_chosen in each arch, it can be defined for all in driver/of/base.c Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt Acked-by: Michal Simek --- drivers/of/base.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index 873479a21c80..cb96888d1427 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -23,6 +23,7 @@ #include struct device_node *allnodes; +struct device_node *of_chosen; /* use when traversing tree through the allnext, child, sibling, * or parent members of struct device_node. -- cgit v1.2.2 From d9184fa97b6f48d399636e5e2669bc8419f9369e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 16 Feb 2010 11:14:14 +1000 Subject: drm/nouveau: use mutex for vbios lock Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 7 +++---- drivers/gpu/drm/nouveau/nouveau_bios.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 2cd0fad17dac..0e9cd1d49130 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -5861,13 +5861,12 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table, struct drm_nouveau_private *dev_priv = dev->dev_private; struct nvbios *bios = &dev_priv->VBIOS; struct init_exec iexec = { true, false }; - unsigned long flags; - spin_lock_irqsave(&bios->lock, flags); + mutex_lock(&bios->lock); bios->display.output = dcbent; parse_init_table(bios, table, &iexec); bios->display.output = NULL; - spin_unlock_irqrestore(&bios->lock, flags); + mutex_unlock(&bios->lock); } static bool NVInitVBIOS(struct drm_device *dev) @@ -5876,7 +5875,7 @@ static bool NVInitVBIOS(struct drm_device *dev) struct nvbios *bios = &dev_priv->VBIOS; memset(bios, 0, sizeof(struct nvbios)); - spin_lock_init(&bios->lock); + mutex_init(&bios->lock); bios->dev = dev; if (!NVShadowVBIOS(dev, bios->data)) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h index 68446fd4146b..fd94bd6dc264 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h @@ -205,7 +205,7 @@ struct nvbios { struct drm_device *dev; struct nouveau_bios_info pub; - spinlock_t lock; + struct mutex lock; uint8_t data[NV_PROM_SIZE]; unsigned int length; -- cgit v1.2.2 From bf929efa56ac174bf6d4f54cd6fe811181a51ae5 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 11 Feb 2010 12:47:40 +0100 Subject: drm/nouveau: Force TV encoder DPMS reinit after resume. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv17_tv.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c index 58b917c3341b..21ac6e49b6ee 100644 --- a/drivers/gpu/drm/nouveau/nv17_tv.c +++ b/drivers/gpu/drm/nouveau/nv17_tv.c @@ -579,6 +579,8 @@ static void nv17_tv_restore(struct drm_encoder *encoder) nouveau_encoder(encoder)->restore.output); nv17_tv_state_load(dev, &to_tv_enc(encoder)->saved_state); + + nouveau_encoder(encoder)->last_dpms = NV_DPMS_CLEARED; } static int nv17_tv_create_resources(struct drm_encoder *encoder, -- cgit v1.2.2 From 40331b21f5fdb746e80fc609ef60ef71b5cd47d9 Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Mon, 15 Feb 2010 13:57:49 +0000 Subject: video: sh_mobile_lcdcfb: Add wait for vsync. Added FBIO_WAITFORVSYNC ioctl for SH-Mobile devices. Tested on MS7724 and MigoR boards against 2.6.33-rc7. Signed-off-by: Phil Edworthy Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 48 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index a69830d26f7f..37aeced2dc18 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -19,6 +19,7 @@ #include #include #include +#include #include