mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 06:02:05 +00:00
Merge ../linux-2.6
This commit is contained in:
commit
eb703027ac
@ -1024,6 +1024,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
||||
intel-mac-v3 Intel Mac Type 3
|
||||
intel-mac-v4 Intel Mac Type 4
|
||||
intel-mac-v5 Intel Mac Type 5
|
||||
intel-mac-auto Intel Mac (detect type according to subsystem id)
|
||||
macmini Intel Mac Mini (equivalent with type 3)
|
||||
macbook Intel Mac Book (eq. type 5)
|
||||
macbook-pro-v1 Intel Mac Book Pro 1st generation (eq. type 3)
|
||||
|
@ -73,10 +73,10 @@ recompiled, or use "make C=2" to run sparse on the files whether they need to
|
||||
be recompiled or not. The latter is a fast way to check the whole tree if you
|
||||
have already built it.
|
||||
|
||||
The optional make variable CHECKFLAGS can be used to pass arguments to sparse.
|
||||
The build system passes -Wbitwise to sparse automatically. To perform
|
||||
endianness checks, you may define __CHECK_ENDIAN__:
|
||||
The optional make variable CF can be used to pass arguments to sparse. The
|
||||
build system passes -Wbitwise to sparse automatically. To perform endianness
|
||||
checks, you may define __CHECK_ENDIAN__:
|
||||
|
||||
make C=2 CHECKFLAGS="-D__CHECK_ENDIAN__"
|
||||
make C=2 CF="-D__CHECK_ENDIAN__"
|
||||
|
||||
These checks are disabled by default as they generate a host of warnings.
|
||||
|
3
Kbuild
3
Kbuild
@ -43,7 +43,7 @@ $(obj)/$(bounds-file): kernel/bounds.s Kbuild
|
||||
# 2) Generate asm-offsets.h
|
||||
#
|
||||
|
||||
offsets-file := include/asm-$(SRCARCH)/asm-offsets.h
|
||||
offsets-file := include/asm/asm-offsets.h
|
||||
|
||||
always += $(offsets-file)
|
||||
targets += $(offsets-file)
|
||||
@ -81,7 +81,6 @@ arch/$(SRCARCH)/kernel/asm-offsets.s: arch/$(SRCARCH)/kernel/asm-offsets.c \
|
||||
$(call if_changed_dep,cc_s_c)
|
||||
|
||||
$(obj)/$(offsets-file): arch/$(SRCARCH)/kernel/asm-offsets.s Kbuild
|
||||
$(Q)mkdir -p $(dir $@)
|
||||
$(call cmd,offsets)
|
||||
|
||||
#####
|
||||
|
115
Makefile
115
Makefile
@ -205,6 +205,9 @@ ifeq ($(ARCH),x86_64)
|
||||
SRCARCH := x86
|
||||
endif
|
||||
|
||||
# Where to locate arch specific headers
|
||||
hdr-arch := $(SRCARCH)
|
||||
|
||||
KCONFIG_CONFIG ?= .config
|
||||
|
||||
# SHELL used by kbuild
|
||||
@ -326,7 +329,8 @@ AFLAGS_KERNEL =
|
||||
# Needed to be compatible with the O= option
|
||||
LINUXINCLUDE := -Iinclude \
|
||||
$(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) \
|
||||
-include include/linux/autoconf.h
|
||||
-I$(srctree)/arch/$(hdr-arch)/include \
|
||||
-include include/linux/autoconf.h
|
||||
|
||||
KBUILD_CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE)
|
||||
|
||||
@ -922,7 +926,9 @@ ifneq ($(KBUILD_SRC),)
|
||||
/bin/false; \
|
||||
fi;
|
||||
$(Q)if [ ! -d include2 ]; then mkdir -p include2; fi;
|
||||
$(Q)ln -fsn $(srctree)/include/asm-$(SRCARCH) include2/asm
|
||||
$(Q)if [ -e $(srctree)/include/asm-$(SRCARCH)/system.h ]; then \
|
||||
ln -fsn $(srctree)/include/asm-$(SRCARCH) include2/asm; \
|
||||
fi
|
||||
endif
|
||||
|
||||
# prepare2 creates a makefile if using a separate output directory
|
||||
@ -948,22 +954,34 @@ export CPPFLAGS_vmlinux.lds += -P -C -U$(ARCH)
|
||||
|
||||
# The asm symlink changes when $(ARCH) changes.
|
||||
# Detect this and ask user to run make mrproper
|
||||
|
||||
include/asm: FORCE
|
||||
$(Q)set -e; asmlink=`readlink include/asm | cut -d '-' -f 2`; \
|
||||
if [ -L include/asm ]; then \
|
||||
if [ "$$asmlink" != "$(SRCARCH)" ]; then \
|
||||
define check-symlink
|
||||
set -e; \
|
||||
if [ -L include/asm ]; then \
|
||||
asmlink=`readlink include/asm | cut -d '-' -f 2`; \
|
||||
if [ "$$asmlink" != "$(SRCARCH)" ]; then \
|
||||
echo "ERROR: the symlink $@ points to asm-$$asmlink but asm-$(SRCARCH) was expected"; \
|
||||
echo " set ARCH or save .config and run 'make mrproper' to fix it"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
else \
|
||||
echo ' SYMLINK $@ -> include/asm-$(SRCARCH)'; \
|
||||
if [ ! -d include ]; then \
|
||||
mkdir -p include; \
|
||||
fi; \
|
||||
ln -fsn asm-$(SRCARCH) $@; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
fi
|
||||
endef
|
||||
|
||||
# We create the target directory of the symlink if it does
|
||||
# not exist so the test in chack-symlink works and we have a
|
||||
# directory for generated filesas used by some architectures.
|
||||
define create-symlink
|
||||
if [ ! -L include/asm ]; then \
|
||||
echo ' SYMLINK $@ -> include/asm-$(SRCARCH)'; \
|
||||
if [ ! -d include/asm-$(SRCARCH) ]; then \
|
||||
mkdir -p include/asm-$(SRCARCH); \
|
||||
fi; \
|
||||
ln -fsn asm-$(SRCARCH) $@; \
|
||||
fi
|
||||
endef
|
||||
|
||||
include/asm: FORCE
|
||||
$(Q)$(check-symlink)
|
||||
$(Q)$(create-symlink)
|
||||
|
||||
# Generate some files
|
||||
# ---------------------------------------------------------------------------
|
||||
@ -1010,36 +1028,43 @@ firmware_install: FORCE
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Kernel headers
|
||||
INSTALL_HDR_PATH=$(objtree)/usr
|
||||
export INSTALL_HDR_PATH
|
||||
|
||||
HDRFILTER=generic i386 x86_64
|
||||
HDRARCHES=$(filter-out $(HDRFILTER),$(patsubst $(srctree)/include/asm-%/Kbuild,%,$(wildcard $(srctree)/include/asm-*/Kbuild)))
|
||||
#Default location for installed headers
|
||||
export INSTALL_HDR_PATH = $(objtree)/usr
|
||||
|
||||
hdr-inst := -rR -f $(srctree)/scripts/Makefile.headersinst obj
|
||||
# Find out where the Kbuild file is located to support
|
||||
# arch/$(ARCH)/include/asm
|
||||
hdr-dir = $(strip \
|
||||
$(if $(wildcard $(srctree)/arch/$(hdr-arch)/include/asm/Kbuild), \
|
||||
arch/$(hdr-arch)/include/asm, include/asm-$(hdr-arch)))
|
||||
|
||||
# If we do an all arch process set dst to asm-$(hdr-arch)
|
||||
hdr-dst = $(if $(KBUILD_HEADERS), dst=include/asm-$(hdr-arch), dst=include/asm)
|
||||
|
||||
PHONY += __headers
|
||||
__headers: include/linux/version.h scripts_basic FORCE
|
||||
$(Q)$(MAKE) $(build)=scripts scripts/unifdef
|
||||
|
||||
PHONY += headers_install_all
|
||||
headers_install_all: include/linux/version.h scripts_basic FORCE
|
||||
$(Q)$(MAKE) $(build)=scripts scripts/unifdef
|
||||
$(Q)for arch in $(HDRARCHES); do \
|
||||
$(MAKE) ARCH=$$arch -f $(srctree)/scripts/Makefile.headersinst obj=include BIASMDIR=-bi-$$arch ;\
|
||||
done
|
||||
headers_install_all:
|
||||
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/headers.sh install
|
||||
|
||||
PHONY += headers_install
|
||||
headers_install: include/linux/version.h scripts_basic FORCE
|
||||
@if [ ! -r $(srctree)/include/asm-$(SRCARCH)/Kbuild ]; then \
|
||||
echo '*** Error: Headers not exportable for this architecture ($(SRCARCH))'; \
|
||||
exit 1 ; fi
|
||||
$(Q)$(MAKE) $(build)=scripts scripts/unifdef
|
||||
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.headersinst ARCH=$(SRCARCH) obj=include
|
||||
headers_install: __headers
|
||||
$(if $(wildcard $(srctree)/$(hdr-dir)/Kbuild),, \
|
||||
$(error Headers not exportable for the $(SRCARCH) architecture))
|
||||
$(Q)$(MAKE) $(hdr-inst)=include
|
||||
$(Q)$(MAKE) $(hdr-inst)=$(hdr-dir) $(hdr-dst)
|
||||
|
||||
PHONY += headers_check_all
|
||||
headers_check_all: headers_install_all
|
||||
$(Q)for arch in $(HDRARCHES); do \
|
||||
$(MAKE) ARCH=$$arch -f $(srctree)/scripts/Makefile.headersinst obj=include BIASMDIR=-bi-$$arch HDRCHECK=1 ;\
|
||||
done
|
||||
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/headers.sh check
|
||||
|
||||
PHONY += headers_check
|
||||
headers_check: headers_install
|
||||
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.headersinst ARCH=$(SRCARCH) obj=include HDRCHECK=1
|
||||
$(Q)$(MAKE) $(hdr-inst)=include HDRCHECK=1
|
||||
$(Q)$(MAKE) $(hdr-inst)=$(hdr-dir) $(hdr-dst) HDRCHECK=1
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Modules
|
||||
@ -1131,7 +1156,7 @@ MRPROPER_FILES += .config .config.old include/asm .version .old_version \
|
||||
include/linux/autoconf.h include/linux/version.h \
|
||||
include/linux/utsrelease.h \
|
||||
include/linux/bounds.h include/asm*/asm-offsets.h \
|
||||
Module.symvers tags TAGS cscope*
|
||||
Module.symvers Module.markers tags TAGS cscope*
|
||||
|
||||
# clean - Delete most, but leave enough to build external modules
|
||||
#
|
||||
@ -1150,7 +1175,7 @@ clean: archclean $(clean-dirs)
|
||||
\( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
|
||||
-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
|
||||
-o -name '*.symtypes' -o -name 'modules.order' \
|
||||
-o -name 'Module.markers' \) \
|
||||
-o -name 'Module.markers' -o -name '.tmp_*.o.*' \) \
|
||||
-type f -print | xargs rm -f
|
||||
|
||||
# mrproper - Delete all generated files, including .config
|
||||
@ -1224,21 +1249,17 @@ help:
|
||||
@echo ' cscope - Generate cscope index'
|
||||
@echo ' kernelrelease - Output the release version string'
|
||||
@echo ' kernelversion - Output the version stored in Makefile'
|
||||
@if [ -r $(srctree)/include/asm-$(SRCARCH)/Kbuild ]; then \
|
||||
echo ' headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH'; \
|
||||
@echo ' headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH'; \
|
||||
echo ' (default: $(INSTALL_HDR_PATH))'; \
|
||||
fi
|
||||
@echo ''
|
||||
echo ''
|
||||
@echo 'Static analysers'
|
||||
@echo ' checkstack - Generate a list of stack hogs'
|
||||
@echo ' namespacecheck - Name space analysis on compiled kernel'
|
||||
@echo ' versioncheck - Sanity check on version.h usage'
|
||||
@echo ' includecheck - Check for duplicate included header files'
|
||||
@echo ' export_report - List the usages of all exported symbols'
|
||||
@if [ -r $(srctree)/include/asm-$(SRCARCH)/Kbuild ]; then \
|
||||
echo ' headers_check - Sanity check on exported headers'; \
|
||||
fi
|
||||
@echo ''
|
||||
@echo ' headers_check - Sanity check on exported headers'; \
|
||||
echo ''
|
||||
@echo 'Kernel packaging:'
|
||||
@$(MAKE) $(build)=$(package-dir) help
|
||||
@echo ''
|
||||
@ -1411,7 +1432,11 @@ define find-sources
|
||||
\( -name config -o -name 'asm-*' \) -prune \
|
||||
-o -name $1 -print; \
|
||||
for arch in $(ALLINCLUDE_ARCHS) ; do \
|
||||
find $(__srctree)include/asm-$${arch} $(RCS_FIND_IGNORE) \
|
||||
test -e $(__srctree)include/asm-$${arch} && \
|
||||
find $(__srctree)include/asm-$${arch} $(RCS_FIND_IGNORE) \
|
||||
-name $1 -print; \
|
||||
test -e $(__srctree)arch/$${arch}/include/asm && \
|
||||
find $(__srctree)arch/$${arch}/include/asm $(RCS_FIND_IGNORE) \
|
||||
-name $1 -print; \
|
||||
done ; \
|
||||
find $(__srctree)include/asm-generic $(RCS_FIND_IGNORE) \
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/atmel-mci.h>
|
||||
|
||||
#include <asm/arch/at32ap700x.h>
|
||||
#include <asm/arch/board.h>
|
||||
#include <asm/arch/init.h>
|
||||
@ -260,6 +262,21 @@ void __init setup_board(void)
|
||||
at32_setup_serial_console(0);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
|
||||
|
||||
/* MMC card detect requires MACB0 *NOT* be used */
|
||||
#ifdef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM
|
||||
static struct mci_platform_data __initdata mci0_data = {
|
||||
.detect_pin = GPIO_PIN_PC(14), /* gpio30/sdcd */
|
||||
.wp_pin = GPIO_PIN_PC(15), /* gpio31/sdwp */
|
||||
};
|
||||
#define MCI_PDATA &mci0_data
|
||||
#else
|
||||
#define MCI_PDATA NULL
|
||||
#endif /* SW6 for sd{cd,wp} routing */
|
||||
|
||||
#endif /* SW2 for MMC signal routing */
|
||||
|
||||
static int __init atstk1002_init(void)
|
||||
{
|
||||
/*
|
||||
@ -309,7 +326,7 @@ static int __init atstk1002_init(void)
|
||||
at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
|
||||
#endif
|
||||
#ifndef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
|
||||
at32_add_device_mci(0, NULL);
|
||||
at32_add_device_mci(0, MCI_PDATA);
|
||||
#endif
|
||||
#ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
|
||||
set_hw_addr(at32_add_device_eth(1, ð_data[1]));
|
||||
|
@ -154,7 +154,7 @@ static int __init atstk1003_init(void)
|
||||
at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
|
||||
#endif
|
||||
#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
|
||||
at32_add_device_mci(0);
|
||||
at32_add_device_mci(0, NULL);
|
||||
#endif
|
||||
at32_add_device_usba(0, NULL);
|
||||
#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
|
||||
|
@ -137,7 +137,7 @@ static int __init atstk1004_init(void)
|
||||
at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
|
||||
#endif
|
||||
#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
|
||||
at32_add_device_mci(0);
|
||||
at32_add_device_mci(0, NULL);
|
||||
#endif
|
||||
at32_add_device_lcdc(0, &atstk1000_lcdc_data,
|
||||
fbmem_start, fbmem_size, 0);
|
||||
|
@ -43,6 +43,9 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct clock_event_device *evdev = dev_id;
|
||||
|
||||
if (unlikely(!(intc_get_pending(0) & 1)))
|
||||
return IRQ_NONE;
|
||||
|
||||
/*
|
||||
* Disable the interrupt until the clockevent subsystem
|
||||
* reprograms it.
|
||||
@ -55,7 +58,8 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
|
||||
|
||||
static struct irqaction timer_irqaction = {
|
||||
.handler = timer_interrupt,
|
||||
.flags = IRQF_TIMER | IRQF_DISABLED,
|
||||
/* Oprofile uses the same irq as the timer, so allow it to be shared */
|
||||
.flags = IRQF_TIMER | IRQF_DISABLED | IRQF_SHARED,
|
||||
.name = "avr32_comparator",
|
||||
};
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/usb/atmel_usba_udc.h>
|
||||
|
||||
@ -1285,7 +1286,6 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
|
||||
{
|
||||
struct mci_platform_data _data;
|
||||
struct platform_device *pdev;
|
||||
struct dw_dma_slave *dws;
|
||||
|
||||
if (id != 0)
|
||||
return NULL;
|
||||
@ -1300,7 +1300,9 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
|
||||
|
||||
if (!data) {
|
||||
data = &_data;
|
||||
memset(data, 0, sizeof(struct mci_platform_data));
|
||||
memset(data, -1, sizeof(struct mci_platform_data));
|
||||
data->detect_pin = GPIO_PIN_NONE;
|
||||
data->wp_pin = GPIO_PIN_NONE;
|
||||
}
|
||||
|
||||
if (platform_device_add_data(pdev, data,
|
||||
@ -1314,12 +1316,10 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
|
||||
select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */
|
||||
select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */
|
||||
|
||||
if (data) {
|
||||
if (data->detect_pin != GPIO_PIN_NONE)
|
||||
at32_select_gpio(data->detect_pin, 0);
|
||||
if (data->wp_pin != GPIO_PIN_NONE)
|
||||
at32_select_gpio(data->wp_pin, 0);
|
||||
}
|
||||
if (gpio_is_valid(data->detect_pin))
|
||||
at32_select_gpio(data->detect_pin, 0);
|
||||
if (gpio_is_valid(data->wp_pin))
|
||||
at32_select_gpio(data->wp_pin, 0);
|
||||
|
||||
atmel_mci0_pclk.dev = &pdev->dev;
|
||||
|
||||
@ -1853,11 +1853,11 @@ at32_add_device_cf(unsigned int id, unsigned int extint,
|
||||
if (at32_init_ide_or_cf(pdev, data->cs, extint))
|
||||
goto fail;
|
||||
|
||||
if (data->detect_pin != GPIO_PIN_NONE)
|
||||
if (gpio_is_valid(data->detect_pin))
|
||||
at32_select_gpio(data->detect_pin, AT32_GPIOF_DEGLITCH);
|
||||
if (data->reset_pin != GPIO_PIN_NONE)
|
||||
if (gpio_is_valid(data->reset_pin))
|
||||
at32_select_gpio(data->reset_pin, 0);
|
||||
if (data->vcc_pin != GPIO_PIN_NONE)
|
||||
if (gpio_is_valid(data->vcc_pin))
|
||||
at32_select_gpio(data->vcc_pin, 0);
|
||||
/* READY is used as extint, so we can't select it as gpio */
|
||||
|
||||
@ -1937,9 +1937,11 @@ static struct clk atmel_ac97c0_pclk = {
|
||||
.index = 10,
|
||||
};
|
||||
|
||||
struct platform_device *__init at32_add_device_ac97c(unsigned int id)
|
||||
struct platform_device *__init
|
||||
at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct ac97c_platform_data _data;
|
||||
|
||||
if (id != 0)
|
||||
return NULL;
|
||||
@ -1950,19 +1952,37 @@ struct platform_device *__init at32_add_device_ac97c(unsigned int id)
|
||||
|
||||
if (platform_device_add_resources(pdev, atmel_ac97c0_resource,
|
||||
ARRAY_SIZE(atmel_ac97c0_resource)))
|
||||
goto err_add_resources;
|
||||
goto fail;
|
||||
|
||||
select_peripheral(PB(20), PERIPH_B, 0); /* SYNC */
|
||||
select_peripheral(PB(21), PERIPH_B, 0); /* SDO */
|
||||
select_peripheral(PB(22), PERIPH_B, 0); /* SDI */
|
||||
select_peripheral(PB(23), PERIPH_B, 0); /* SCLK */
|
||||
if (!data) {
|
||||
data = &_data;
|
||||
memset(data, 0, sizeof(struct ac97c_platform_data));
|
||||
data->reset_pin = GPIO_PIN_NONE;
|
||||
}
|
||||
|
||||
data->dma_rx_periph_id = 3;
|
||||
data->dma_tx_periph_id = 4;
|
||||
data->dma_controller_id = 0;
|
||||
|
||||
if (platform_device_add_data(pdev, data,
|
||||
sizeof(struct ac97c_platform_data)))
|
||||
goto fail;
|
||||
|
||||
select_peripheral(PB(20), PERIPH_B, 0); /* SDO */
|
||||
select_peripheral(PB(21), PERIPH_B, 0); /* SYNC */
|
||||
select_peripheral(PB(22), PERIPH_B, 0); /* SCLK */
|
||||
select_peripheral(PB(23), PERIPH_B, 0); /* SDI */
|
||||
|
||||
/* TODO: gpio_is_valid(data->reset_pin) with kernel 2.6.26. */
|
||||
if (data->reset_pin != GPIO_PIN_NONE)
|
||||
at32_select_gpio(data->reset_pin, 0);
|
||||
|
||||
atmel_ac97c0_pclk.dev = &pdev->dev;
|
||||
|
||||
platform_device_add(pdev);
|
||||
return pdev;
|
||||
|
||||
err_add_resources:
|
||||
fail:
|
||||
platform_device_put(pdev);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -125,9 +125,9 @@ void kvm_arch_hardware_enable(void *garbage)
|
||||
PAGE_KERNEL));
|
||||
local_irq_save(saved_psr);
|
||||
slot = ia64_itr_entry(0x3, KVM_VMM_BASE, pte, KVM_VMM_SHIFT);
|
||||
local_irq_restore(saved_psr);
|
||||
if (slot < 0)
|
||||
return;
|
||||
local_irq_restore(saved_psr);
|
||||
|
||||
spin_lock(&vp_lock);
|
||||
status = ia64_pal_vp_init_env(kvm_vsa_base ?
|
||||
@ -160,9 +160,9 @@ void kvm_arch_hardware_disable(void *garbage)
|
||||
|
||||
local_irq_save(saved_psr);
|
||||
slot = ia64_itr_entry(0x3, KVM_VMM_BASE, pte, KVM_VMM_SHIFT);
|
||||
local_irq_restore(saved_psr);
|
||||
if (slot < 0)
|
||||
return;
|
||||
local_irq_restore(saved_psr);
|
||||
|
||||
status = ia64_pal_vp_exit_env(host_iva);
|
||||
if (status)
|
||||
@ -1253,6 +1253,7 @@ static int vti_vcpu_setup(struct kvm_vcpu *vcpu, int id)
|
||||
uninit:
|
||||
kvm_vcpu_uninit(vcpu);
|
||||
fail:
|
||||
local_irq_restore(psr);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -177,7 +177,8 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gfn_t gfn, u64 asid,
|
||||
vcpu->arch.msr & MSR_PR);
|
||||
}
|
||||
|
||||
void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, u64 eaddr, u64 asid)
|
||||
void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, gva_t eaddr,
|
||||
gva_t eend, u32 asid)
|
||||
{
|
||||
unsigned int pid = asid & 0xff;
|
||||
int i;
|
||||
@ -191,7 +192,7 @@ void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, u64 eaddr, u64 asid)
|
||||
if (!get_tlb_v(stlbe))
|
||||
continue;
|
||||
|
||||
if (eaddr < get_tlb_eaddr(stlbe))
|
||||
if (eend < get_tlb_eaddr(stlbe))
|
||||
continue;
|
||||
|
||||
if (eaddr > get_tlb_end(stlbe))
|
||||
|
@ -137,7 +137,7 @@ static int kvmppc_emul_tlbwe(struct kvm_vcpu *vcpu, u32 inst)
|
||||
if (tlbe->word0 & PPC44x_TLB_VALID) {
|
||||
eaddr = get_tlb_eaddr(tlbe);
|
||||
asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid;
|
||||
kvmppc_mmu_invalidate(vcpu, eaddr, asid);
|
||||
kvmppc_mmu_invalidate(vcpu, eaddr, get_tlb_end(tlbe), asid);
|
||||
}
|
||||
|
||||
switch (ws) {
|
||||
|
@ -18,11 +18,11 @@
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
static inline void __user *__guestaddr_to_user(struct kvm_vcpu *vcpu,
|
||||
u64 guestaddr)
|
||||
unsigned long guestaddr)
|
||||
{
|
||||
u64 prefix = vcpu->arch.sie_block->prefix;
|
||||
u64 origin = vcpu->kvm->arch.guest_origin;
|
||||
u64 memsize = vcpu->kvm->arch.guest_memsize;
|
||||
unsigned long prefix = vcpu->arch.sie_block->prefix;
|
||||
unsigned long origin = vcpu->kvm->arch.guest_origin;
|
||||
unsigned long memsize = vcpu->kvm->arch.guest_memsize;
|
||||
|
||||
if (guestaddr < 2 * PAGE_SIZE)
|
||||
guestaddr += prefix;
|
||||
@ -37,7 +37,7 @@ static inline void __user *__guestaddr_to_user(struct kvm_vcpu *vcpu,
|
||||
return (void __user *) guestaddr;
|
||||
}
|
||||
|
||||
static inline int get_guest_u64(struct kvm_vcpu *vcpu, u64 guestaddr,
|
||||
static inline int get_guest_u64(struct kvm_vcpu *vcpu, unsigned long guestaddr,
|
||||
u64 *result)
|
||||
{
|
||||
void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
|
||||
@ -47,10 +47,10 @@ static inline int get_guest_u64(struct kvm_vcpu *vcpu, u64 guestaddr,
|
||||
if (IS_ERR((void __force *) uptr))
|
||||
return PTR_ERR((void __force *) uptr);
|
||||
|
||||
return get_user(*result, (u64 __user *) uptr);
|
||||
return get_user(*result, (unsigned long __user *) uptr);
|
||||
}
|
||||
|
||||
static inline int get_guest_u32(struct kvm_vcpu *vcpu, u64 guestaddr,
|
||||
static inline int get_guest_u32(struct kvm_vcpu *vcpu, unsigned long guestaddr,
|
||||
u32 *result)
|
||||
{
|
||||
void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
|
||||
@ -63,7 +63,7 @@ static inline int get_guest_u32(struct kvm_vcpu *vcpu, u64 guestaddr,
|
||||
return get_user(*result, (u32 __user *) uptr);
|
||||
}
|
||||
|
||||
static inline int get_guest_u16(struct kvm_vcpu *vcpu, u64 guestaddr,
|
||||
static inline int get_guest_u16(struct kvm_vcpu *vcpu, unsigned long guestaddr,
|
||||
u16 *result)
|
||||
{
|
||||
void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
|
||||
@ -76,7 +76,7 @@ static inline int get_guest_u16(struct kvm_vcpu *vcpu, u64 guestaddr,
|
||||
return get_user(*result, (u16 __user *) uptr);
|
||||
}
|
||||
|
||||
static inline int get_guest_u8(struct kvm_vcpu *vcpu, u64 guestaddr,
|
||||
static inline int get_guest_u8(struct kvm_vcpu *vcpu, unsigned long guestaddr,
|
||||
u8 *result)
|
||||
{
|
||||
void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
|
||||
@ -87,7 +87,7 @@ static inline int get_guest_u8(struct kvm_vcpu *vcpu, u64 guestaddr,
|
||||
return get_user(*result, (u8 __user *) uptr);
|
||||
}
|
||||
|
||||
static inline int put_guest_u64(struct kvm_vcpu *vcpu, u64 guestaddr,
|
||||
static inline int put_guest_u64(struct kvm_vcpu *vcpu, unsigned long guestaddr,
|
||||
u64 value)
|
||||
{
|
||||
void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
|
||||
@ -100,7 +100,7 @@ static inline int put_guest_u64(struct kvm_vcpu *vcpu, u64 guestaddr,
|
||||
return put_user(value, (u64 __user *) uptr);
|
||||
}
|
||||
|
||||
static inline int put_guest_u32(struct kvm_vcpu *vcpu, u64 guestaddr,
|
||||
static inline int put_guest_u32(struct kvm_vcpu *vcpu, unsigned long guestaddr,
|
||||
u32 value)
|
||||
{
|
||||
void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
|
||||
@ -113,7 +113,7 @@ static inline int put_guest_u32(struct kvm_vcpu *vcpu, u64 guestaddr,
|
||||
return put_user(value, (u32 __user *) uptr);
|
||||
}
|
||||
|
||||
static inline int put_guest_u16(struct kvm_vcpu *vcpu, u64 guestaddr,
|
||||
static inline int put_guest_u16(struct kvm_vcpu *vcpu, unsigned long guestaddr,
|
||||
u16 value)
|
||||
{
|
||||
void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
|
||||
@ -126,7 +126,7 @@ static inline int put_guest_u16(struct kvm_vcpu *vcpu, u64 guestaddr,
|
||||
return put_user(value, (u16 __user *) uptr);
|
||||
}
|
||||
|
||||
static inline int put_guest_u8(struct kvm_vcpu *vcpu, u64 guestaddr,
|
||||
static inline int put_guest_u8(struct kvm_vcpu *vcpu, unsigned long guestaddr,
|
||||
u8 value)
|
||||
{
|
||||
void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
|
||||
@ -138,7 +138,8 @@ static inline int put_guest_u8(struct kvm_vcpu *vcpu, u64 guestaddr,
|
||||
}
|
||||
|
||||
|
||||
static inline int __copy_to_guest_slow(struct kvm_vcpu *vcpu, u64 guestdest,
|
||||
static inline int __copy_to_guest_slow(struct kvm_vcpu *vcpu,
|
||||
unsigned long guestdest,
|
||||
const void *from, unsigned long n)
|
||||
{
|
||||
int rc;
|
||||
@ -153,12 +154,12 @@ static inline int __copy_to_guest_slow(struct kvm_vcpu *vcpu, u64 guestdest,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int copy_to_guest(struct kvm_vcpu *vcpu, u64 guestdest,
|
||||
static inline int copy_to_guest(struct kvm_vcpu *vcpu, unsigned long guestdest,
|
||||
const void *from, unsigned long n)
|
||||
{
|
||||
u64 prefix = vcpu->arch.sie_block->prefix;
|
||||
u64 origin = vcpu->kvm->arch.guest_origin;
|
||||
u64 memsize = vcpu->kvm->arch.guest_memsize;
|
||||
unsigned long prefix = vcpu->arch.sie_block->prefix;
|
||||
unsigned long origin = vcpu->kvm->arch.guest_origin;
|
||||
unsigned long memsize = vcpu->kvm->arch.guest_memsize;
|
||||
|
||||
if ((guestdest < 2 * PAGE_SIZE) && (guestdest + n > 2 * PAGE_SIZE))
|
||||
goto slowpath;
|
||||
@ -189,7 +190,8 @@ slowpath:
|
||||
}
|
||||
|
||||
static inline int __copy_from_guest_slow(struct kvm_vcpu *vcpu, void *to,
|
||||
u64 guestsrc, unsigned long n)
|
||||
unsigned long guestsrc,
|
||||
unsigned long n)
|
||||
{
|
||||
int rc;
|
||||
unsigned long i;
|
||||
@ -204,11 +206,11 @@ static inline int __copy_from_guest_slow(struct kvm_vcpu *vcpu, void *to,
|
||||
}
|
||||
|
||||
static inline int copy_from_guest(struct kvm_vcpu *vcpu, void *to,
|
||||
u64 guestsrc, unsigned long n)
|
||||
unsigned long guestsrc, unsigned long n)
|
||||
{
|
||||
u64 prefix = vcpu->arch.sie_block->prefix;
|
||||
u64 origin = vcpu->kvm->arch.guest_origin;
|
||||
u64 memsize = vcpu->kvm->arch.guest_memsize;
|
||||
unsigned long prefix = vcpu->arch.sie_block->prefix;
|
||||
unsigned long origin = vcpu->kvm->arch.guest_origin;
|
||||
unsigned long memsize = vcpu->kvm->arch.guest_memsize;
|
||||
|
||||
if ((guestsrc < 2 * PAGE_SIZE) && (guestsrc + n > 2 * PAGE_SIZE))
|
||||
goto slowpath;
|
||||
@ -238,11 +240,12 @@ slowpath:
|
||||
return __copy_from_guest_slow(vcpu, to, guestsrc, n);
|
||||
}
|
||||
|
||||
static inline int copy_to_guest_absolute(struct kvm_vcpu *vcpu, u64 guestdest,
|
||||
static inline int copy_to_guest_absolute(struct kvm_vcpu *vcpu,
|
||||
unsigned long guestdest,
|
||||
const void *from, unsigned long n)
|
||||
{
|
||||
u64 origin = vcpu->kvm->arch.guest_origin;
|
||||
u64 memsize = vcpu->kvm->arch.guest_memsize;
|
||||
unsigned long origin = vcpu->kvm->arch.guest_origin;
|
||||
unsigned long memsize = vcpu->kvm->arch.guest_memsize;
|
||||
|
||||
if (guestdest + n > memsize)
|
||||
return -EFAULT;
|
||||
@ -256,10 +259,11 @@ static inline int copy_to_guest_absolute(struct kvm_vcpu *vcpu, u64 guestdest,
|
||||
}
|
||||
|
||||
static inline int copy_from_guest_absolute(struct kvm_vcpu *vcpu, void *to,
|
||||
u64 guestsrc, unsigned long n)
|
||||
unsigned long guestsrc,
|
||||
unsigned long n)
|
||||
{
|
||||
u64 origin = vcpu->kvm->arch.guest_origin;
|
||||
u64 memsize = vcpu->kvm->arch.guest_memsize;
|
||||
unsigned long origin = vcpu->kvm->arch.guest_origin;
|
||||
unsigned long memsize = vcpu->kvm->arch.guest_memsize;
|
||||
|
||||
if (guestsrc + n > memsize)
|
||||
return -EFAULT;
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "kvm-s390.h"
|
||||
#include "gaccess.h"
|
||||
|
||||
static int handle_lctg(struct kvm_vcpu *vcpu)
|
||||
static int handle_lctlg(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
|
||||
int reg3 = vcpu->arch.sie_block->ipa & 0x000f;
|
||||
@ -30,7 +30,7 @@ static int handle_lctg(struct kvm_vcpu *vcpu)
|
||||
u64 useraddr;
|
||||
int reg, rc;
|
||||
|
||||
vcpu->stat.instruction_lctg++;
|
||||
vcpu->stat.instruction_lctlg++;
|
||||
if ((vcpu->arch.sie_block->ipb & 0xff) != 0x2f)
|
||||
return -ENOTSUPP;
|
||||
|
||||
@ -38,9 +38,12 @@ static int handle_lctg(struct kvm_vcpu *vcpu)
|
||||
if (base2)
|
||||
useraddr += vcpu->arch.guest_gprs[base2];
|
||||
|
||||
if (useraddr & 7)
|
||||
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
|
||||
|
||||
reg = reg1;
|
||||
|
||||
VCPU_EVENT(vcpu, 5, "lctg r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2,
|
||||
VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2,
|
||||
disp2);
|
||||
|
||||
do {
|
||||
@ -74,6 +77,9 @@ static int handle_lctl(struct kvm_vcpu *vcpu)
|
||||
if (base2)
|
||||
useraddr += vcpu->arch.guest_gprs[base2];
|
||||
|
||||
if (useraddr & 3)
|
||||
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
|
||||
|
||||
VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2,
|
||||
disp2);
|
||||
|
||||
@ -99,7 +105,7 @@ static intercept_handler_t instruction_handlers[256] = {
|
||||
[0xae] = kvm_s390_handle_sigp,
|
||||
[0xb2] = kvm_s390_handle_priv,
|
||||
[0xb7] = handle_lctl,
|
||||
[0xeb] = handle_lctg,
|
||||
[0xeb] = handle_lctlg,
|
||||
};
|
||||
|
||||
static int handle_noop(struct kvm_vcpu *vcpu)
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <asm/lowcore.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/signal.h>
|
||||
#include "kvm-s390.h"
|
||||
#include "gaccess.h"
|
||||
|
||||
@ -246,15 +247,10 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (exception) {
|
||||
VCPU_EVENT(vcpu, 1, "%s", "program exception while delivering"
|
||||
" interrupt");
|
||||
kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
|
||||
if (inti->type == KVM_S390_PROGRAM_INT) {
|
||||
printk(KERN_WARNING "kvm: recursive program check\n");
|
||||
BUG();
|
||||
}
|
||||
printk("kvm: The guest lowcore is not mapped during interrupt "
|
||||
"delivery, killing userspace\n");
|
||||
do_exit(SIGKILL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,14 +273,11 @@ static int __try_deliver_ckc_interrupt(struct kvm_vcpu *vcpu)
|
||||
__LC_EXT_NEW_PSW, sizeof(psw_t));
|
||||
if (rc == -EFAULT)
|
||||
exception = 1;
|
||||
|
||||
if (exception) {
|
||||
VCPU_EVENT(vcpu, 1, "%s", "program exception while delivering" \
|
||||
" ckc interrupt");
|
||||
kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
|
||||
return 0;
|
||||
printk("kvm: The guest lowcore is not mapped during interrupt "
|
||||
"delivery, killing userspace\n");
|
||||
do_exit(SIGKILL);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
|
||||
{ "exit_instruction", VCPU_STAT(exit_instruction) },
|
||||
{ "exit_program_interruption", VCPU_STAT(exit_program_interruption) },
|
||||
{ "exit_instr_and_program_int", VCPU_STAT(exit_instr_and_program) },
|
||||
{ "instruction_lctg", VCPU_STAT(instruction_lctg) },
|
||||
{ "instruction_lctlg", VCPU_STAT(instruction_lctlg) },
|
||||
{ "instruction_lctl", VCPU_STAT(instruction_lctl) },
|
||||
{ "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) },
|
||||
{ "deliver_service_signal", VCPU_STAT(deliver_service_signal) },
|
||||
@ -112,7 +112,12 @@ long kvm_arch_dev_ioctl(struct file *filp,
|
||||
|
||||
int kvm_dev_ioctl_check_extension(long ext)
|
||||
{
|
||||
return 0;
|
||||
switch (ext) {
|
||||
case KVM_CAP_USER_MEMORY:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Section: vm related */
|
||||
|
@ -43,7 +43,8 @@
|
||||
#define SIGP_STAT_RECEIVER_CHECK 0x00000001UL
|
||||
|
||||
|
||||
static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr, u64 *reg)
|
||||
static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
|
||||
unsigned long *reg)
|
||||
{
|
||||
struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
|
||||
int rc;
|
||||
@ -167,7 +168,7 @@ static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter)
|
||||
}
|
||||
|
||||
static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
|
||||
u64 *reg)
|
||||
unsigned long *reg)
|
||||
{
|
||||
struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
|
||||
struct kvm_s390_local_interrupt *li;
|
||||
|
@ -1814,6 +1814,7 @@ int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva)
|
||||
spin_unlock(&vcpu->kvm->mmu_lock);
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_mmu_unprotect_page_virt);
|
||||
|
||||
void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
@ -1870,6 +1871,12 @@ void kvm_enable_tdp(void)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_enable_tdp);
|
||||
|
||||
void kvm_disable_tdp(void)
|
||||
{
|
||||
tdp_enabled = false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_disable_tdp);
|
||||
|
||||
static void free_mmu_pages(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_mmu_page *sp;
|
||||
|
@ -453,7 +453,8 @@ static __init int svm_hardware_setup(void)
|
||||
if (npt_enabled) {
|
||||
printk(KERN_INFO "kvm: Nested Paging enabled\n");
|
||||
kvm_enable_tdp();
|
||||
}
|
||||
} else
|
||||
kvm_disable_tdp();
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1007,10 +1008,13 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
|
||||
struct kvm *kvm = svm->vcpu.kvm;
|
||||
u64 fault_address;
|
||||
u32 error_code;
|
||||
bool event_injection = false;
|
||||
|
||||
if (!irqchip_in_kernel(kvm) &&
|
||||
is_external_interrupt(exit_int_info))
|
||||
is_external_interrupt(exit_int_info)) {
|
||||
event_injection = true;
|
||||
push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK);
|
||||
}
|
||||
|
||||
fault_address = svm->vmcb->control.exit_info_2;
|
||||
error_code = svm->vmcb->control.exit_info_1;
|
||||
@ -1024,6 +1028,8 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
|
||||
(u32)fault_address, (u32)(fault_address >> 32),
|
||||
handler);
|
||||
|
||||
if (event_injection)
|
||||
kvm_mmu_unprotect_page_virt(&svm->vcpu, fault_address);
|
||||
return kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code);
|
||||
}
|
||||
|
||||
|
@ -2298,6 +2298,8 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
||||
cr2 = vmcs_readl(EXIT_QUALIFICATION);
|
||||
KVMTRACE_3D(PAGE_FAULT, vcpu, error_code, (u32)cr2,
|
||||
(u32)((u64)cr2 >> 32), handler);
|
||||
if (vect_info & VECTORING_INFO_VALID_MASK)
|
||||
kvm_mmu_unprotect_page_virt(vcpu, cr2);
|
||||
return kvm_mmu_page_fault(vcpu, cr2, error_code);
|
||||
}
|
||||
|
||||
@ -3116,15 +3118,6 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
allocate_vpid(vmx);
|
||||
if (id == 0 && vm_need_ept()) {
|
||||
kvm_mmu_set_base_ptes(VMX_EPT_READABLE_MASK |
|
||||
VMX_EPT_WRITABLE_MASK |
|
||||
VMX_EPT_DEFAULT_MT << VMX_EPT_MT_EPTE_SHIFT);
|
||||
kvm_mmu_set_mask_ptes(0ull, VMX_EPT_FAKE_ACCESSED_MASK,
|
||||
VMX_EPT_FAKE_DIRTY_MASK, 0ull,
|
||||
VMX_EPT_EXECUTABLE_MASK);
|
||||
kvm_enable_tdp();
|
||||
}
|
||||
|
||||
err = kvm_vcpu_init(&vmx->vcpu, kvm, id);
|
||||
if (err)
|
||||
@ -3303,8 +3296,17 @@ static int __init vmx_init(void)
|
||||
vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_ESP);
|
||||
vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_EIP);
|
||||
|
||||
if (cpu_has_vmx_ept())
|
||||
if (vm_need_ept()) {
|
||||
bypass_guest_pf = 0;
|
||||
kvm_mmu_set_base_ptes(VMX_EPT_READABLE_MASK |
|
||||
VMX_EPT_WRITABLE_MASK |
|
||||
VMX_EPT_DEFAULT_MT << VMX_EPT_MT_EPTE_SHIFT);
|
||||
kvm_mmu_set_mask_ptes(0ull, VMX_EPT_FAKE_ACCESSED_MASK,
|
||||
VMX_EPT_FAKE_DIRTY_MASK, 0ull,
|
||||
VMX_EPT_EXECUTABLE_MASK);
|
||||
kvm_enable_tdp();
|
||||
} else
|
||||
kvm_disable_tdp();
|
||||
|
||||
if (bypass_guest_pf)
|
||||
kvm_mmu_set_nonpresent_ptes(~0xffeull, 0ull);
|
||||
|
@ -3184,6 +3184,10 @@ static void seg_desct_to_kvm_desct(struct desc_struct *seg_desc, u16 selector,
|
||||
kvm_desct->base |= seg_desc->base2 << 24;
|
||||
kvm_desct->limit = seg_desc->limit0;
|
||||
kvm_desct->limit |= seg_desc->limit << 16;
|
||||
if (seg_desc->g) {
|
||||
kvm_desct->limit <<= 12;
|
||||
kvm_desct->limit |= 0xfff;
|
||||
}
|
||||
kvm_desct->selector = selector;
|
||||
kvm_desct->type = seg_desc->type;
|
||||
kvm_desct->present = seg_desc->p;
|
||||
@ -3223,6 +3227,7 @@ static void get_segment_descritptor_dtable(struct kvm_vcpu *vcpu,
|
||||
static int load_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
|
||||
struct desc_struct *seg_desc)
|
||||
{
|
||||
gpa_t gpa;
|
||||
struct descriptor_table dtable;
|
||||
u16 index = selector >> 3;
|
||||
|
||||
@ -3232,13 +3237,16 @@ static int load_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
|
||||
kvm_queue_exception_e(vcpu, GP_VECTOR, selector & 0xfffc);
|
||||
return 1;
|
||||
}
|
||||
return kvm_read_guest(vcpu->kvm, dtable.base + index * 8, seg_desc, 8);
|
||||
gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, dtable.base);
|
||||
gpa += index * 8;
|
||||
return kvm_read_guest(vcpu->kvm, gpa, seg_desc, 8);
|
||||
}
|
||||
|
||||
/* allowed just for 8 bytes segments */
|
||||
static int save_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
|
||||
struct desc_struct *seg_desc)
|
||||
{
|
||||
gpa_t gpa;
|
||||
struct descriptor_table dtable;
|
||||
u16 index = selector >> 3;
|
||||
|
||||
@ -3246,7 +3254,9 @@ static int save_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
|
||||
|
||||
if (dtable.limit < index * 8 + 7)
|
||||
return 1;
|
||||
return kvm_write_guest(vcpu->kvm, dtable.base + index * 8, seg_desc, 8);
|
||||
gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, dtable.base);
|
||||
gpa += index * 8;
|
||||
return kvm_write_guest(vcpu->kvm, gpa, seg_desc, 8);
|
||||
}
|
||||
|
||||
static u32 get_tss_base_addr(struct kvm_vcpu *vcpu,
|
||||
@ -3258,55 +3268,7 @@ static u32 get_tss_base_addr(struct kvm_vcpu *vcpu,
|
||||
base_addr |= (seg_desc->base1 << 16);
|
||||
base_addr |= (seg_desc->base2 << 24);
|
||||
|
||||
return base_addr;
|
||||
}
|
||||
|
||||
static int load_tss_segment32(struct kvm_vcpu *vcpu,
|
||||
struct desc_struct *seg_desc,
|
||||
struct tss_segment_32 *tss)
|
||||
{
|
||||
u32 base_addr;
|
||||
|
||||
base_addr = get_tss_base_addr(vcpu, seg_desc);
|
||||
|
||||
return kvm_read_guest(vcpu->kvm, base_addr, tss,
|
||||
sizeof(struct tss_segment_32));
|
||||
}
|
||||
|
||||
static int save_tss_segment32(struct kvm_vcpu *vcpu,
|
||||
struct desc_struct *seg_desc,
|
||||
struct tss_segment_32 *tss)
|
||||
{
|
||||
u32 base_addr;
|
||||
|
||||
base_addr = get_tss_base_addr(vcpu, seg_desc);
|
||||
|
||||
return kvm_write_guest(vcpu->kvm, base_addr, tss,
|
||||
sizeof(struct tss_segment_32));
|
||||
}
|
||||
|
||||
static int load_tss_segment16(struct kvm_vcpu *vcpu,
|
||||
struct desc_struct *seg_desc,
|
||||
struct tss_segment_16 *tss)
|
||||
{
|
||||
u32 base_addr;
|
||||
|
||||
base_addr = get_tss_base_addr(vcpu, seg_desc);
|
||||
|
||||
return kvm_read_guest(vcpu->kvm, base_addr, tss,
|
||||
sizeof(struct tss_segment_16));
|
||||
}
|
||||
|
||||
static int save_tss_segment16(struct kvm_vcpu *vcpu,
|
||||
struct desc_struct *seg_desc,
|
||||
struct tss_segment_16 *tss)
|
||||
{
|
||||
u32 base_addr;
|
||||
|
||||
base_addr = get_tss_base_addr(vcpu, seg_desc);
|
||||
|
||||
return kvm_write_guest(vcpu->kvm, base_addr, tss,
|
||||
sizeof(struct tss_segment_16));
|
||||
return vcpu->arch.mmu.gva_to_gpa(vcpu, base_addr);
|
||||
}
|
||||
|
||||
static u16 get_segment_selector(struct kvm_vcpu *vcpu, int seg)
|
||||
@ -3466,20 +3428,26 @@ static int load_state_from_tss16(struct kvm_vcpu *vcpu,
|
||||
}
|
||||
|
||||
static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
|
||||
struct desc_struct *cseg_desc,
|
||||
u32 old_tss_base,
|
||||
struct desc_struct *nseg_desc)
|
||||
{
|
||||
struct tss_segment_16 tss_segment_16;
|
||||
int ret = 0;
|
||||
|
||||
if (load_tss_segment16(vcpu, cseg_desc, &tss_segment_16))
|
||||
if (kvm_read_guest(vcpu->kvm, old_tss_base, &tss_segment_16,
|
||||
sizeof tss_segment_16))
|
||||
goto out;
|
||||
|
||||
save_state_to_tss16(vcpu, &tss_segment_16);
|
||||
save_tss_segment16(vcpu, cseg_desc, &tss_segment_16);
|
||||
|
||||
if (load_tss_segment16(vcpu, nseg_desc, &tss_segment_16))
|
||||
if (kvm_write_guest(vcpu->kvm, old_tss_base, &tss_segment_16,
|
||||
sizeof tss_segment_16))
|
||||
goto out;
|
||||
|
||||
if (kvm_read_guest(vcpu->kvm, get_tss_base_addr(vcpu, nseg_desc),
|
||||
&tss_segment_16, sizeof tss_segment_16))
|
||||
goto out;
|
||||
|
||||
if (load_state_from_tss16(vcpu, &tss_segment_16))
|
||||
goto out;
|
||||
|
||||
@ -3489,20 +3457,26 @@ out:
|
||||
}
|
||||
|
||||
static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
|
||||
struct desc_struct *cseg_desc,
|
||||
u32 old_tss_base,
|
||||
struct desc_struct *nseg_desc)
|
||||
{
|
||||
struct tss_segment_32 tss_segment_32;
|
||||
int ret = 0;
|
||||
|
||||
if (load_tss_segment32(vcpu, cseg_desc, &tss_segment_32))
|
||||
if (kvm_read_guest(vcpu->kvm, old_tss_base, &tss_segment_32,
|
||||
sizeof tss_segment_32))
|
||||
goto out;
|
||||
|
||||
save_state_to_tss32(vcpu, &tss_segment_32);
|
||||
save_tss_segment32(vcpu, cseg_desc, &tss_segment_32);
|
||||
|
||||
if (load_tss_segment32(vcpu, nseg_desc, &tss_segment_32))
|
||||
if (kvm_write_guest(vcpu->kvm, old_tss_base, &tss_segment_32,
|
||||
sizeof tss_segment_32))
|
||||
goto out;
|
||||
|
||||
if (kvm_read_guest(vcpu->kvm, get_tss_base_addr(vcpu, nseg_desc),
|
||||
&tss_segment_32, sizeof tss_segment_32))
|
||||
goto out;
|
||||
|
||||
if (load_state_from_tss32(vcpu, &tss_segment_32))
|
||||
goto out;
|
||||
|
||||
@ -3517,16 +3491,20 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
|
||||
struct desc_struct cseg_desc;
|
||||
struct desc_struct nseg_desc;
|
||||
int ret = 0;
|
||||
u32 old_tss_base = get_segment_base(vcpu, VCPU_SREG_TR);
|
||||
u16 old_tss_sel = get_segment_selector(vcpu, VCPU_SREG_TR);
|
||||
|
||||
kvm_get_segment(vcpu, &tr_seg, VCPU_SREG_TR);
|
||||
old_tss_base = vcpu->arch.mmu.gva_to_gpa(vcpu, old_tss_base);
|
||||
|
||||
/* FIXME: Handle errors. Failure to read either TSS or their
|
||||
* descriptors should generate a pagefault.
|
||||
*/
|
||||
if (load_guest_segment_descriptor(vcpu, tss_selector, &nseg_desc))
|
||||
goto out;
|
||||
|
||||
if (load_guest_segment_descriptor(vcpu, tr_seg.selector, &cseg_desc))
|
||||
if (load_guest_segment_descriptor(vcpu, old_tss_sel, &cseg_desc))
|
||||
goto out;
|
||||
|
||||
|
||||
if (reason != TASK_SWITCH_IRET) {
|
||||
int cpl;
|
||||
|
||||
@ -3544,8 +3522,7 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
|
||||
|
||||
if (reason == TASK_SWITCH_IRET || reason == TASK_SWITCH_JMP) {
|
||||
cseg_desc.type &= ~(1 << 1); //clear the B flag
|
||||
save_guest_segment_descriptor(vcpu, tr_seg.selector,
|
||||
&cseg_desc);
|
||||
save_guest_segment_descriptor(vcpu, old_tss_sel, &cseg_desc);
|
||||
}
|
||||
|
||||
if (reason == TASK_SWITCH_IRET) {
|
||||
@ -3557,10 +3534,10 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
|
||||
kvm_x86_ops->cache_regs(vcpu);
|
||||
|
||||
if (nseg_desc.type & 8)
|
||||
ret = kvm_task_switch_32(vcpu, tss_selector, &cseg_desc,
|
||||
ret = kvm_task_switch_32(vcpu, tss_selector, old_tss_base,
|
||||
&nseg_desc);
|
||||
else
|
||||
ret = kvm_task_switch_16(vcpu, tss_selector, &cseg_desc,
|
||||
ret = kvm_task_switch_16(vcpu, tss_selector, old_tss_base,
|
||||
&nseg_desc);
|
||||
|
||||
if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) {
|
||||
|
@ -99,6 +99,9 @@ struct talitos_private {
|
||||
/* next channel to be assigned next incoming descriptor */
|
||||
atomic_t last_chan;
|
||||
|
||||
/* per-channel number of requests pending in channel h/w fifo */
|
||||
atomic_t *submit_count;
|
||||
|
||||
/* per-channel request fifo */
|
||||
struct talitos_request **fifo;
|
||||
|
||||
@ -263,15 +266,15 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc,
|
||||
|
||||
spin_lock_irqsave(&priv->head_lock[ch], flags);
|
||||
|
||||
head = priv->head[ch];
|
||||
request = &priv->fifo[ch][head];
|
||||
|
||||
if (request->desc) {
|
||||
/* request queue is full */
|
||||
if (!atomic_inc_not_zero(&priv->submit_count[ch])) {
|
||||
/* h/w fifo is full */
|
||||
spin_unlock_irqrestore(&priv->head_lock[ch], flags);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
head = priv->head[ch];
|
||||
request = &priv->fifo[ch][head];
|
||||
|
||||
/* map descriptor and save caller data */
|
||||
request->dma_desc = dma_map_single(dev, desc, sizeof(*desc),
|
||||
DMA_BIDIRECTIONAL);
|
||||
@ -335,6 +338,9 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
|
||||
priv->tail[ch] = (tail + 1) & (priv->fifo_len - 1);
|
||||
|
||||
spin_unlock_irqrestore(&priv->tail_lock[ch], flags);
|
||||
|
||||
atomic_dec(&priv->submit_count[ch]);
|
||||
|
||||
saved_req.callback(dev, saved_req.desc, saved_req.context,
|
||||
status);
|
||||
/* channel may resume processing in single desc error case */
|
||||
@ -842,7 +848,7 @@ static int sg_to_link_tbl(struct scatterlist *sg, int sg_count,
|
||||
|
||||
/* adjust (decrease) last one (or two) entry's len to cryptlen */
|
||||
link_tbl_ptr--;
|
||||
while (link_tbl_ptr->len <= (-cryptlen)) {
|
||||
while (be16_to_cpu(link_tbl_ptr->len) <= (-cryptlen)) {
|
||||
/* Empty this entry, and move to previous one */
|
||||
cryptlen += be16_to_cpu(link_tbl_ptr->len);
|
||||
link_tbl_ptr->len = 0;
|
||||
@ -874,7 +880,7 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq,
|
||||
unsigned int cryptlen = areq->cryptlen;
|
||||
unsigned int authsize = ctx->authsize;
|
||||
unsigned int ivsize;
|
||||
int sg_count;
|
||||
int sg_count, ret;
|
||||
|
||||
/* hmac key */
|
||||
map_single_talitos_ptr(dev, &desc->ptr[0], ctx->authkeylen, &ctx->key,
|
||||
@ -978,7 +984,12 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq,
|
||||
map_single_talitos_ptr(dev, &desc->ptr[6], ivsize, ctx->iv, 0,
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
return talitos_submit(dev, desc, callback, areq);
|
||||
ret = talitos_submit(dev, desc, callback, areq);
|
||||
if (ret != -EINPROGRESS) {
|
||||
ipsec_esp_unmap(dev, edesc, areq);
|
||||
kfree(edesc);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -1009,6 +1020,8 @@ static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq,
|
||||
struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
|
||||
struct ipsec_esp_edesc *edesc;
|
||||
int src_nents, dst_nents, alloc_len, dma_len;
|
||||
gfp_t flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL :
|
||||
GFP_ATOMIC;
|
||||
|
||||
if (areq->cryptlen + ctx->authsize > TALITOS_MAX_DATA_LEN) {
|
||||
dev_err(ctx->dev, "cryptlen exceeds h/w max limit\n");
|
||||
@ -1022,7 +1035,7 @@ static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq,
|
||||
dst_nents = src_nents;
|
||||
} else {
|
||||
dst_nents = sg_count(areq->dst, areq->cryptlen + ctx->authsize);
|
||||
dst_nents = (dst_nents == 1) ? 0 : src_nents;
|
||||
dst_nents = (dst_nents == 1) ? 0 : dst_nents;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1040,7 +1053,7 @@ static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq,
|
||||
alloc_len += icv_stashing ? ctx->authsize : 0;
|
||||
}
|
||||
|
||||
edesc = kmalloc(alloc_len, GFP_DMA);
|
||||
edesc = kmalloc(alloc_len, GFP_DMA | flags);
|
||||
if (!edesc) {
|
||||
dev_err(ctx->dev, "could not allocate edescriptor\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
@ -1337,6 +1350,7 @@ static int __devexit talitos_remove(struct of_device *ofdev)
|
||||
if (hw_supports(dev, DESC_HDR_SEL0_RNG))
|
||||
talitos_unregister_rng(dev);
|
||||
|
||||
kfree(priv->submit_count);
|
||||
kfree(priv->tail);
|
||||
kfree(priv->head);
|
||||
|
||||
@ -1466,9 +1480,6 @@ static int talitos_probe(struct of_device *ofdev,
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
of_node_put(np);
|
||||
np = NULL;
|
||||
|
||||
priv->head_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels,
|
||||
GFP_KERNEL);
|
||||
priv->tail_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels,
|
||||
@ -1504,6 +1515,16 @@ static int talitos_probe(struct of_device *ofdev,
|
||||
}
|
||||
}
|
||||
|
||||
priv->submit_count = kmalloc(sizeof(atomic_t) * priv->num_channels,
|
||||
GFP_KERNEL);
|
||||
if (!priv->submit_count) {
|
||||
dev_err(dev, "failed to allocate fifo submit count space\n");
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
for (i = 0; i < priv->num_channels; i++)
|
||||
atomic_set(&priv->submit_count[i], -priv->chfifo_len);
|
||||
|
||||
priv->head = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL);
|
||||
priv->tail = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL);
|
||||
if (!priv->head || !priv->tail) {
|
||||
@ -1559,8 +1580,6 @@ static int talitos_probe(struct of_device *ofdev,
|
||||
|
||||
err_out:
|
||||
talitos_remove(ofdev);
|
||||
if (np)
|
||||
of_node_put(np);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -16,8 +16,13 @@ config FIREWIRE
|
||||
enable the new stack.
|
||||
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called firewire-core. It functionally replaces ieee1394, raw1394,
|
||||
and video1394.
|
||||
called firewire-core.
|
||||
|
||||
This module functionally replaces ieee1394, raw1394, and video1394.
|
||||
To access it from application programs, you generally need at least
|
||||
libraw1394 version 2. IIDC/DCAM applications also need libdc1394
|
||||
version 2. No libraries are required to access storage devices
|
||||
through the firewire-sbp2 driver.
|
||||
|
||||
config FIREWIRE_OHCI
|
||||
tristate "OHCI-1394 controllers"
|
||||
|
@ -539,7 +539,7 @@ fw_core_remove_card(struct fw_card *card)
|
||||
wait_for_completion(&card->done);
|
||||
|
||||
cancel_delayed_work_sync(&card->work);
|
||||
fw_flush_transactions(card);
|
||||
WARN_ON(!list_empty(&card->transaction_list));
|
||||
del_timer_sync(&card->flush_timer);
|
||||
}
|
||||
EXPORT_SYMBOL(fw_core_remove_card);
|
||||
|
@ -382,9 +382,9 @@ complete_transaction(struct fw_card *card, int rcode,
|
||||
|
||||
response->response.type = FW_CDEV_EVENT_RESPONSE;
|
||||
response->response.rcode = rcode;
|
||||
queue_event(client, &response->event,
|
||||
&response->response, sizeof(response->response),
|
||||
response->response.data, response->response.length);
|
||||
queue_event(client, &response->event, &response->response,
|
||||
sizeof(response->response) + response->response.length,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
static int ioctl_send_request(struct client *client, void *buffer)
|
||||
|
@ -171,7 +171,6 @@ struct iso_context {
|
||||
struct fw_ohci {
|
||||
struct fw_card card;
|
||||
|
||||
u32 version;
|
||||
__iomem char *registers;
|
||||
dma_addr_t self_id_bus;
|
||||
__le32 *self_id_cpu;
|
||||
@ -180,6 +179,8 @@ struct fw_ohci {
|
||||
int generation;
|
||||
int request_generation; /* for timestamping incoming requests */
|
||||
u32 bus_seconds;
|
||||
|
||||
bool use_dualbuffer;
|
||||
bool old_uninorth;
|
||||
bool bus_reset_packet_quirk;
|
||||
|
||||
@ -1885,7 +1886,7 @@ ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size)
|
||||
} else {
|
||||
mask = &ohci->ir_context_mask;
|
||||
list = ohci->ir_context_list;
|
||||
if (ohci->version >= OHCI_VERSION_1_1)
|
||||
if (ohci->use_dualbuffer)
|
||||
callback = handle_ir_dualbuffer_packet;
|
||||
else
|
||||
callback = handle_ir_packet_per_buffer;
|
||||
@ -1949,7 +1950,7 @@ static int ohci_start_iso(struct fw_iso_context *base,
|
||||
} else {
|
||||
index = ctx - ohci->ir_context_list;
|
||||
control = IR_CONTEXT_ISOCH_HEADER;
|
||||
if (ohci->version >= OHCI_VERSION_1_1)
|
||||
if (ohci->use_dualbuffer)
|
||||
control |= IR_CONTEXT_DUAL_BUFFER_MODE;
|
||||
match = (tags << 28) | (sync << 8) | ctx->base.channel;
|
||||
if (cycle >= 0) {
|
||||
@ -2279,7 +2280,7 @@ ohci_queue_iso(struct fw_iso_context *base,
|
||||
spin_lock_irqsave(&ctx->context.ohci->lock, flags);
|
||||
if (base->type == FW_ISO_CONTEXT_TRANSMIT)
|
||||
retval = ohci_queue_iso_transmit(base, packet, buffer, payload);
|
||||
else if (ctx->context.ohci->version >= OHCI_VERSION_1_1)
|
||||
else if (ctx->context.ohci->use_dualbuffer)
|
||||
retval = ohci_queue_iso_receive_dualbuffer(base, packet,
|
||||
buffer, payload);
|
||||
else
|
||||
@ -2341,7 +2342,7 @@ static int __devinit
|
||||
pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
|
||||
{
|
||||
struct fw_ohci *ohci;
|
||||
u32 bus_options, max_receive, link_speed;
|
||||
u32 bus_options, max_receive, link_speed, version;
|
||||
u64 guid;
|
||||
int err;
|
||||
size_t size;
|
||||
@ -2366,12 +2367,6 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
|
||||
pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0);
|
||||
pci_set_drvdata(dev, ohci);
|
||||
|
||||
#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
|
||||
ohci->old_uninorth = dev->vendor == PCI_VENDOR_ID_APPLE &&
|
||||
dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW;
|
||||
#endif
|
||||
ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI;
|
||||
|
||||
spin_lock_init(&ohci->lock);
|
||||
|
||||
tasklet_init(&ohci->bus_reset_tasklet,
|
||||
@ -2390,6 +2385,23 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
|
||||
goto fail_iomem;
|
||||
}
|
||||
|
||||
version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
|
||||
ohci->use_dualbuffer = version >= OHCI_VERSION_1_1;
|
||||
|
||||
/* x86-32 currently doesn't use highmem for dma_alloc_coherent */
|
||||
#if !defined(CONFIG_X86_32)
|
||||
/* dual-buffer mode is broken with descriptor addresses above 2G */
|
||||
if (dev->vendor == PCI_VENDOR_ID_TI &&
|
||||
dev->device == PCI_DEVICE_ID_TI_TSB43AB22)
|
||||
ohci->use_dualbuffer = false;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
|
||||
ohci->old_uninorth = dev->vendor == PCI_VENDOR_ID_APPLE &&
|
||||
dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW;
|
||||
#endif
|
||||
ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI;
|
||||
|
||||
ar_context_init(&ohci->ar_request_ctx, ohci,
|
||||
OHCI1394_AsReqRcvContextControlSet);
|
||||
|
||||
@ -2441,9 +2453,8 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
|
||||
if (err < 0)
|
||||
goto fail_self_id;
|
||||
|
||||
ohci->version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
|
||||
fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n",
|
||||
dev->dev.bus_id, ohci->version >> 16, ohci->version & 0xff);
|
||||
dev->dev.bus_id, version >> 16, version & 0xff);
|
||||
return 0;
|
||||
|
||||
fail_self_id:
|
||||
|
@ -510,8 +510,6 @@ fw_core_handle_bus_reset(struct fw_card *card,
|
||||
struct fw_node *local_node;
|
||||
unsigned long flags;
|
||||
|
||||
fw_flush_transactions(card);
|
||||
|
||||
spin_lock_irqsave(&card->lock, flags);
|
||||
|
||||
/*
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
@ -151,7 +152,7 @@ transmit_complete_callback(struct fw_packet *packet,
|
||||
|
||||
static void
|
||||
fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
|
||||
int node_id, int source_id, int generation, int speed,
|
||||
int destination_id, int source_id, int generation, int speed,
|
||||
unsigned long long offset, void *payload, size_t length)
|
||||
{
|
||||
int ext_tcode;
|
||||
@ -166,7 +167,7 @@ fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
|
||||
HEADER_RETRY(RETRY_X) |
|
||||
HEADER_TLABEL(tlabel) |
|
||||
HEADER_TCODE(tcode) |
|
||||
HEADER_DESTINATION(node_id);
|
||||
HEADER_DESTINATION(destination_id);
|
||||
packet->header[1] =
|
||||
HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id);
|
||||
packet->header[2] =
|
||||
@ -252,7 +253,7 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t,
|
||||
fw_transaction_callback_t callback, void *callback_data)
|
||||
{
|
||||
unsigned long flags;
|
||||
int tlabel, source;
|
||||
int tlabel;
|
||||
|
||||
/*
|
||||
* Bump the flush timer up 100ms first of all so we
|
||||
@ -268,7 +269,6 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t,
|
||||
|
||||
spin_lock_irqsave(&card->lock, flags);
|
||||
|
||||
source = card->node_id;
|
||||
tlabel = card->current_tlabel;
|
||||
if (card->tlabel_mask & (1 << tlabel)) {
|
||||
spin_unlock_irqrestore(&card->lock, flags);
|
||||
@ -279,77 +279,58 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t,
|
||||
card->current_tlabel = (card->current_tlabel + 1) & 0x1f;
|
||||
card->tlabel_mask |= (1 << tlabel);
|
||||
|
||||
list_add_tail(&t->link, &card->transaction_list);
|
||||
|
||||
spin_unlock_irqrestore(&card->lock, flags);
|
||||
|
||||
/* Initialize rest of transaction, fill out packet and send it. */
|
||||
t->node_id = node_id;
|
||||
t->tlabel = tlabel;
|
||||
t->callback = callback;
|
||||
t->callback_data = callback_data;
|
||||
|
||||
fw_fill_request(&t->packet, tcode, t->tlabel,
|
||||
node_id, source, generation,
|
||||
speed, offset, payload, length);
|
||||
fw_fill_request(&t->packet, tcode, t->tlabel, node_id, card->node_id,
|
||||
generation, speed, offset, payload, length);
|
||||
t->packet.callback = transmit_complete_callback;
|
||||
|
||||
list_add_tail(&t->link, &card->transaction_list);
|
||||
|
||||
spin_unlock_irqrestore(&card->lock, flags);
|
||||
|
||||
card->driver->send_request(card, &t->packet);
|
||||
}
|
||||
EXPORT_SYMBOL(fw_send_request);
|
||||
|
||||
struct fw_phy_packet {
|
||||
struct fw_packet packet;
|
||||
struct completion done;
|
||||
struct kref kref;
|
||||
};
|
||||
|
||||
static void phy_packet_release(struct kref *kref)
|
||||
{
|
||||
struct fw_phy_packet *p =
|
||||
container_of(kref, struct fw_phy_packet, kref);
|
||||
kfree(p);
|
||||
}
|
||||
static DEFINE_MUTEX(phy_config_mutex);
|
||||
static DECLARE_COMPLETION(phy_config_done);
|
||||
|
||||
static void transmit_phy_packet_callback(struct fw_packet *packet,
|
||||
struct fw_card *card, int status)
|
||||
{
|
||||
struct fw_phy_packet *p =
|
||||
container_of(packet, struct fw_phy_packet, packet);
|
||||
|
||||
complete(&p->done);
|
||||
kref_put(&p->kref, phy_packet_release);
|
||||
complete(&phy_config_done);
|
||||
}
|
||||
|
||||
static struct fw_packet phy_config_packet = {
|
||||
.header_length = 8,
|
||||
.payload_length = 0,
|
||||
.speed = SCODE_100,
|
||||
.callback = transmit_phy_packet_callback,
|
||||
};
|
||||
|
||||
void fw_send_phy_config(struct fw_card *card,
|
||||
int node_id, int generation, int gap_count)
|
||||
{
|
||||
struct fw_phy_packet *p;
|
||||
long timeout = DIV_ROUND_UP(HZ, 10);
|
||||
u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG) |
|
||||
PHY_CONFIG_ROOT_ID(node_id) |
|
||||
PHY_CONFIG_GAP_COUNT(gap_count);
|
||||
|
||||
p = kmalloc(sizeof(*p), GFP_KERNEL);
|
||||
if (p == NULL)
|
||||
return;
|
||||
mutex_lock(&phy_config_mutex);
|
||||
|
||||
p->packet.header[0] = data;
|
||||
p->packet.header[1] = ~data;
|
||||
p->packet.header_length = 8;
|
||||
p->packet.payload_length = 0;
|
||||
p->packet.speed = SCODE_100;
|
||||
p->packet.generation = generation;
|
||||
p->packet.callback = transmit_phy_packet_callback;
|
||||
init_completion(&p->done);
|
||||
kref_set(&p->kref, 2);
|
||||
phy_config_packet.header[0] = data;
|
||||
phy_config_packet.header[1] = ~data;
|
||||
phy_config_packet.generation = generation;
|
||||
INIT_COMPLETION(phy_config_done);
|
||||
|
||||
card->driver->send_request(card, &p->packet);
|
||||
timeout = wait_for_completion_timeout(&p->done, timeout);
|
||||
kref_put(&p->kref, phy_packet_release);
|
||||
card->driver->send_request(card, &phy_config_packet);
|
||||
wait_for_completion_timeout(&phy_config_done, timeout);
|
||||
|
||||
/* will leak p if the callback is never executed */
|
||||
WARN_ON(timeout == 0);
|
||||
mutex_unlock(&phy_config_mutex);
|
||||
}
|
||||
|
||||
void fw_flush_transactions(struct fw_card *card)
|
||||
|
@ -7,6 +7,7 @@ config MISDN_HFCPCI
|
||||
tristate "Support for HFC PCI cards"
|
||||
depends on MISDN
|
||||
depends on PCI
|
||||
depends on VIRT_TO_BUS
|
||||
help
|
||||
Enable support for cards with Cologne Chip AG's
|
||||
HFC PCI chip.
|
||||
|
@ -2030,7 +2030,7 @@ release_l2(struct layer2 *l2)
|
||||
skb_queue_purge(&l2->down_queue);
|
||||
ReleaseWin(l2);
|
||||
if (test_bit(FLG_LAPD, &l2->flag)) {
|
||||
release_tei(l2);
|
||||
TEIrelease(l2);
|
||||
if (l2->ch.st)
|
||||
l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D,
|
||||
CLOSE_CHANNEL, NULL);
|
||||
|
@ -96,7 +96,7 @@ extern int tei_l2(struct layer2 *, u_int, u_long arg);
|
||||
|
||||
/* from tei.c */
|
||||
extern int l2_tei(struct layer2 *, u_int, u_long arg);
|
||||
extern void release_tei(struct layer2 *);
|
||||
extern void TEIrelease(struct layer2 *);
|
||||
extern int TEIInit(u_int *);
|
||||
extern void TEIFree(void);
|
||||
|
||||
|
@ -945,7 +945,7 @@ l2_tei(struct layer2 *l2, u_int cmd, u_long arg)
|
||||
}
|
||||
|
||||
void
|
||||
release_tei(struct layer2 *l2)
|
||||
TEIrelease(struct layer2 *l2)
|
||||
{
|
||||
struct teimgr *tm = l2->tm;
|
||||
u_long flags;
|
||||
|
@ -147,9 +147,12 @@ static struct priority_group *alloc_priority_group(void)
|
||||
static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti)
|
||||
{
|
||||
struct pgpath *pgpath, *tmp;
|
||||
struct multipath *m = ti->private;
|
||||
|
||||
list_for_each_entry_safe(pgpath, tmp, pgpaths, list) {
|
||||
list_del(&pgpath->list);
|
||||
if (m->hw_handler_name)
|
||||
scsi_dh_detach(bdev_get_queue(pgpath->path.dev->bdev));
|
||||
dm_put_device(ti, pgpath->path.dev);
|
||||
free_pgpath(pgpath);
|
||||
}
|
||||
@ -548,6 +551,7 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
|
||||
{
|
||||
int r;
|
||||
struct pgpath *p;
|
||||
struct multipath *m = ti->private;
|
||||
|
||||
/* we need at least a path arg */
|
||||
if (as->argc < 1) {
|
||||
@ -566,6 +570,15 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (m->hw_handler_name) {
|
||||
r = scsi_dh_attach(bdev_get_queue(p->path.dev->bdev),
|
||||
m->hw_handler_name);
|
||||
if (r < 0) {
|
||||
dm_put_device(ti, p->path.dev);
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
r = ps->type->add_path(ps, &p->path, as->argc, as->argv, &ti->error);
|
||||
if (r) {
|
||||
dm_put_device(ti, p->path.dev);
|
||||
|
@ -273,12 +273,12 @@ mpt_fault_reset_work(struct work_struct *work)
|
||||
ioc_raw_state = mpt_GetIocState(ioc, 0);
|
||||
if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
|
||||
printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
|
||||
ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
|
||||
ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
|
||||
printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
|
||||
ioc->name, __FUNCTION__);
|
||||
ioc->name, __func__);
|
||||
rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
|
||||
printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
|
||||
__FUNCTION__, (rc == 0) ? "success" : "failed");
|
||||
__func__, (rc == 0) ? "success" : "failed");
|
||||
ioc_raw_state = mpt_GetIocState(ioc, 0);
|
||||
if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
|
||||
printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
|
||||
@ -356,7 +356,7 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
|
||||
if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
|
||||
MptCallbacks[cb_idx] == NULL) {
|
||||
printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
|
||||
__FUNCTION__, ioc->name, cb_idx);
|
||||
__func__, ioc->name, cb_idx);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -420,7 +420,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
|
||||
if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
|
||||
MptCallbacks[cb_idx] == NULL) {
|
||||
printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
|
||||
__FUNCTION__, ioc->name, cb_idx);
|
||||
__func__, ioc->name, cb_idx);
|
||||
freeme = 0;
|
||||
goto out;
|
||||
}
|
||||
@ -2434,7 +2434,7 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
|
||||
|
||||
if (ioc->cached_fw != NULL) {
|
||||
ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
|
||||
"adapter\n", __FUNCTION__, ioc->name));
|
||||
"adapter\n", __func__, ioc->name));
|
||||
if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
|
||||
ioc->cached_fw, CAN_SLEEP)) < 0) {
|
||||
printk(MYIOC_s_WARN_FMT
|
||||
@ -3693,7 +3693,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
|
||||
|
||||
if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
|
||||
drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
|
||||
"address=%p\n", ioc->name, __FUNCTION__,
|
||||
"address=%p\n", ioc->name, __func__,
|
||||
&ioc->chip->Doorbell, &ioc->chip->Reset_1078));
|
||||
CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
|
||||
if (sleepFlag == CAN_SLEEP)
|
||||
@ -4742,12 +4742,12 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
|
||||
break;
|
||||
}
|
||||
|
||||
printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
|
||||
printk("%s: persist_opcode=%x\n",__func__, persist_opcode);
|
||||
|
||||
/* Get a MF for this command.
|
||||
*/
|
||||
if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
|
||||
printk("%s: no msg frames!\n",__FUNCTION__);
|
||||
printk("%s: no msg frames!\n",__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -4771,13 +4771,13 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
|
||||
(SasIoUnitControlReply_t *)ioc->persist_reply_frame;
|
||||
if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
|
||||
printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
|
||||
__FUNCTION__,
|
||||
__func__,
|
||||
sasIoUnitCntrReply->IOCStatus,
|
||||
sasIoUnitCntrReply->IOCLogInfo);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printk("%s: success\n",__FUNCTION__);
|
||||
printk("%s: success\n",__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -5784,7 +5784,7 @@ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
|
||||
|
||||
if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
|
||||
ioc->name,__FUNCTION__));
|
||||
ioc->name,__func__));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -505,7 +505,7 @@ mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
|
||||
event = le32_to_cpu(pEvReply->Event) & 0xFF;
|
||||
|
||||
dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s() called\n",
|
||||
ioc->name, __FUNCTION__));
|
||||
ioc->name, __func__));
|
||||
if(async_queue == NULL)
|
||||
return 1;
|
||||
|
||||
@ -2482,7 +2482,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
|
||||
*/
|
||||
if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
|
||||
ioc->name,__FUNCTION__));
|
||||
ioc->name,__func__));
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -231,28 +231,28 @@ static int
|
||||
mptfc_abort(struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
return
|
||||
mptfc_block_error_handler(SCpnt, mptscsih_abort, __FUNCTION__);
|
||||
mptfc_block_error_handler(SCpnt, mptscsih_abort, __func__);
|
||||
}
|
||||
|
||||
static int
|
||||
mptfc_dev_reset(struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
return
|
||||
mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __FUNCTION__);
|
||||
mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __func__);
|
||||
}
|
||||
|
||||
static int
|
||||
mptfc_bus_reset(struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
return
|
||||
mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __FUNCTION__);
|
||||
mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __func__);
|
||||
}
|
||||
|
||||
static int
|
||||
mptfc_host_reset(struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
return
|
||||
mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __FUNCTION__);
|
||||
mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __func__);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -610,7 +610,7 @@ mpt_lan_send_turbo(struct net_device *dev, u32 tmsg)
|
||||
|
||||
dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
|
||||
IOC_AND_NETDEV_NAMES_s_s(dev),
|
||||
__FUNCTION__, sent));
|
||||
__func__, sent));
|
||||
|
||||
priv->SendCtl[ctx].skb = NULL;
|
||||
pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
|
||||
@ -676,7 +676,7 @@ mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep)
|
||||
|
||||
dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
|
||||
IOC_AND_NETDEV_NAMES_s_s(dev),
|
||||
__FUNCTION__, sent));
|
||||
__func__, sent));
|
||||
|
||||
priv->SendCtl[ctx].skb = NULL;
|
||||
pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
|
||||
@ -715,7 +715,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
|
||||
u16 cur_naa = 0x1000;
|
||||
|
||||
dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n",
|
||||
__FUNCTION__, skb));
|
||||
__func__, skb));
|
||||
|
||||
spin_lock_irqsave(&priv->txfidx_lock, flags);
|
||||
if (priv->mpt_txfidx_tail < 0) {
|
||||
@ -723,7 +723,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
|
||||
spin_unlock_irqrestore(&priv->txfidx_lock, flags);
|
||||
|
||||
printk (KERN_ERR "%s: no tx context available: %u\n",
|
||||
__FUNCTION__, priv->mpt_txfidx_tail);
|
||||
__func__, priv->mpt_txfidx_tail);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -733,7 +733,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
|
||||
spin_unlock_irqrestore(&priv->txfidx_lock, flags);
|
||||
|
||||
printk (KERN_ERR "%s: Unable to alloc request frame\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1208,7 +1208,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
|
||||
|
||||
dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n",
|
||||
IOC_AND_NETDEV_NAMES_s_s(dev),
|
||||
__FUNCTION__, buckets, curr));
|
||||
__func__, buckets, curr));
|
||||
|
||||
max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) /
|
||||
(MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t));
|
||||
@ -1217,9 +1217,9 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
|
||||
mf = mpt_get_msg_frame(LanCtx, mpt_dev);
|
||||
if (mf == NULL) {
|
||||
printk (KERN_ERR "%s: Unable to alloc request frame\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
dioprintk((KERN_ERR "%s: %u buckets remaining\n",
|
||||
__FUNCTION__, buckets));
|
||||
__func__, buckets));
|
||||
goto out;
|
||||
}
|
||||
pRecvReq = (LANReceivePostRequest_t *) mf;
|
||||
@ -1244,7 +1244,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
|
||||
spin_lock_irqsave(&priv->rxfidx_lock, flags);
|
||||
if (priv->mpt_rxfidx_tail < 0) {
|
||||
printk (KERN_ERR "%s: Can't alloc context\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
spin_unlock_irqrestore(&priv->rxfidx_lock,
|
||||
flags);
|
||||
break;
|
||||
@ -1267,7 +1267,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
|
||||
if (skb == NULL) {
|
||||
printk (KERN_WARNING
|
||||
MYNAM "/%s: Can't alloc skb\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
|
||||
spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
|
||||
break;
|
||||
@ -1305,7 +1305,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
|
||||
|
||||
if (pSimple == NULL) {
|
||||
/**/ printk (KERN_WARNING MYNAM "/%s: No buckets posted\n",
|
||||
/**/ __FUNCTION__);
|
||||
/**/ __func__);
|
||||
mpt_free_msg_frame(mpt_dev, mf);
|
||||
goto out;
|
||||
}
|
||||
@ -1329,9 +1329,9 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
|
||||
|
||||
out:
|
||||
dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n",
|
||||
__FUNCTION__, buckets, atomic_read(&priv->buckets_out)));
|
||||
__func__, buckets, atomic_read(&priv->buckets_out)));
|
||||
dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n",
|
||||
__FUNCTION__, priv->total_posted, priv->total_received));
|
||||
__func__, priv->total_posted, priv->total_received));
|
||||
|
||||
clear_bit(0, &priv->post_buckets_active);
|
||||
}
|
||||
|
@ -300,7 +300,7 @@ mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_detai
|
||||
phy_info = port_info->phy_info;
|
||||
|
||||
dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
|
||||
"bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details,
|
||||
"bitmask=0x%016llX\n", ioc->name, __func__, port_details,
|
||||
port_details->num_phys, (unsigned long long)
|
||||
port_details->phy_bitmask));
|
||||
|
||||
@ -411,7 +411,7 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
|
||||
*/
|
||||
dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
||||
"%s: [%p]: deleting phy = %d\n",
|
||||
ioc->name, __FUNCTION__, port_details, i));
|
||||
ioc->name, __func__, port_details, i));
|
||||
port_details->num_phys--;
|
||||
port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
|
||||
memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
|
||||
@ -497,7 +497,7 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
|
||||
continue;
|
||||
dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
||||
"%s: [%p]: phy_id=%02d num_phys=%02d "
|
||||
"bitmask=0x%016llX\n", ioc->name, __FUNCTION__,
|
||||
"bitmask=0x%016llX\n", ioc->name, __func__,
|
||||
port_details, i, port_details->num_phys,
|
||||
(unsigned long long)port_details->phy_bitmask));
|
||||
dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
|
||||
@ -553,7 +553,7 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
|
||||
|
||||
if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
|
||||
ioc->name,__FUNCTION__, __LINE__));
|
||||
ioc->name,__func__, __LINE__));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -606,7 +606,7 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc,
|
||||
GFP_ATOMIC);
|
||||
if (!target_reset_list) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
|
||||
ioc->name,__FUNCTION__, __LINE__));
|
||||
ioc->name,__func__, __LINE__));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -673,7 +673,7 @@ mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
|
||||
ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
|
||||
if (!ev) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
|
||||
ioc->name,__FUNCTION__, __LINE__));
|
||||
ioc->name,__func__, __LINE__));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1183,7 +1183,7 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
|
||||
reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
|
||||
if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
|
||||
printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
|
||||
ioc->name, __FUNCTION__, reply->IOCStatus, reply->IOCLogInfo);
|
||||
ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
|
||||
error = -ENXIO;
|
||||
goto out_unlock;
|
||||
}
|
||||
@ -1270,14 +1270,14 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
|
||||
|
||||
if (!rsp) {
|
||||
printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
|
||||
ioc->name, __FUNCTION__);
|
||||
ioc->name, __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* do we need to support multiple segments? */
|
||||
if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
|
||||
printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
|
||||
ioc->name, __FUNCTION__, req->bio->bi_vcnt, req->data_len,
|
||||
ioc->name, __func__, req->bio->bi_vcnt, req->data_len,
|
||||
rsp->bio->bi_vcnt, rsp->data_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1343,7 +1343,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
|
||||
|
||||
timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
|
||||
if (!timeleft) {
|
||||
printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __FUNCTION__);
|
||||
printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
|
||||
/* On timeout reset the board */
|
||||
mpt_HardResetHandler(ioc, CAN_SLEEP);
|
||||
ret = -ETIMEDOUT;
|
||||
@ -1361,7 +1361,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
|
||||
rsp->data_len -= smprep->ResponseDataLength;
|
||||
} else {
|
||||
printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
|
||||
ioc->name, __FUNCTION__);
|
||||
ioc->name, __func__);
|
||||
ret = -ENXIO;
|
||||
}
|
||||
unmap:
|
||||
@ -2006,7 +2006,7 @@ static int mptsas_probe_one_phy(struct device *dev,
|
||||
if (error) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
|
||||
"%s: exit at line=%d\n", ioc->name,
|
||||
__FUNCTION__, __LINE__));
|
||||
__func__, __LINE__));
|
||||
goto out;
|
||||
}
|
||||
mptsas_set_port(ioc, phy_info, port);
|
||||
@ -2076,7 +2076,7 @@ static int mptsas_probe_one_phy(struct device *dev,
|
||||
if (!rphy) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
|
||||
"%s: exit at line=%d\n", ioc->name,
|
||||
__FUNCTION__, __LINE__));
|
||||
__func__, __LINE__));
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -2085,7 +2085,7 @@ static int mptsas_probe_one_phy(struct device *dev,
|
||||
if (error) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
|
||||
"%s: exit at line=%d\n", ioc->name,
|
||||
__FUNCTION__, __LINE__));
|
||||
__func__, __LINE__));
|
||||
sas_rphy_free(rphy);
|
||||
goto out;
|
||||
}
|
||||
@ -2613,7 +2613,7 @@ mptsas_hotplug_work(struct work_struct *work)
|
||||
(ev->channel << 8) + ev->id)) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
|
||||
"%s: exit at line=%d\n", ioc->name,
|
||||
__FUNCTION__, __LINE__));
|
||||
__func__, __LINE__));
|
||||
break;
|
||||
}
|
||||
phy_info = mptsas_find_phyinfo_by_sas_address(
|
||||
@ -2633,20 +2633,20 @@ mptsas_hotplug_work(struct work_struct *work)
|
||||
if (!phy_info){
|
||||
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
|
||||
"%s: exit at line=%d\n", ioc->name,
|
||||
__FUNCTION__, __LINE__));
|
||||
__func__, __LINE__));
|
||||
break;
|
||||
}
|
||||
if (!phy_info->port_details) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
|
||||
"%s: exit at line=%d\n", ioc->name,
|
||||
__FUNCTION__, __LINE__));
|
||||
__func__, __LINE__));
|
||||
break;
|
||||
}
|
||||
rphy = mptsas_get_rphy(phy_info);
|
||||
if (!rphy) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
|
||||
"%s: exit at line=%d\n", ioc->name,
|
||||
__FUNCTION__, __LINE__));
|
||||
__func__, __LINE__));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2654,7 +2654,7 @@ mptsas_hotplug_work(struct work_struct *work)
|
||||
if (!port) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
|
||||
"%s: exit at line=%d\n", ioc->name,
|
||||
__FUNCTION__, __LINE__));
|
||||
__func__, __LINE__));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2665,7 +2665,7 @@ mptsas_hotplug_work(struct work_struct *work)
|
||||
if (!vtarget) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
|
||||
"%s: exit at line=%d\n", ioc->name,
|
||||
__FUNCTION__, __LINE__));
|
||||
__func__, __LINE__));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2720,7 +2720,7 @@ mptsas_hotplug_work(struct work_struct *work)
|
||||
(ev->channel << 8) + ev->id)) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
|
||||
"%s: exit at line=%d\n", ioc->name,
|
||||
__FUNCTION__, __LINE__));
|
||||
__func__, __LINE__));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2732,7 +2732,7 @@ mptsas_hotplug_work(struct work_struct *work)
|
||||
if (!phy_info || !phy_info->port_details) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
|
||||
"%s: exit at line=%d\n", ioc->name,
|
||||
__FUNCTION__, __LINE__));
|
||||
__func__, __LINE__));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2744,7 +2744,7 @@ mptsas_hotplug_work(struct work_struct *work)
|
||||
if (!vtarget) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
|
||||
"%s: exit at line=%d\n", ioc->name,
|
||||
__FUNCTION__, __LINE__));
|
||||
__func__, __LINE__));
|
||||
break;
|
||||
}
|
||||
/*
|
||||
@ -2767,7 +2767,7 @@ mptsas_hotplug_work(struct work_struct *work)
|
||||
if (mptsas_get_rphy(phy_info)) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
|
||||
"%s: exit at line=%d\n", ioc->name,
|
||||
__FUNCTION__, __LINE__));
|
||||
__func__, __LINE__));
|
||||
if (ev->channel) printk("%d\n", __LINE__);
|
||||
break;
|
||||
}
|
||||
@ -2776,7 +2776,7 @@ mptsas_hotplug_work(struct work_struct *work)
|
||||
if (!port) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
|
||||
"%s: exit at line=%d\n", ioc->name,
|
||||
__FUNCTION__, __LINE__));
|
||||
__func__, __LINE__));
|
||||
break;
|
||||
}
|
||||
memcpy(&phy_info->attached, &sas_device,
|
||||
@ -2801,7 +2801,7 @@ mptsas_hotplug_work(struct work_struct *work)
|
||||
if (!rphy) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
|
||||
"%s: exit at line=%d\n", ioc->name,
|
||||
__FUNCTION__, __LINE__));
|
||||
__func__, __LINE__));
|
||||
break; /* non-fatal: an rphy can be added later */
|
||||
}
|
||||
|
||||
@ -2809,7 +2809,7 @@ mptsas_hotplug_work(struct work_struct *work)
|
||||
if (sas_rphy_add(rphy)) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
|
||||
"%s: exit at line=%d\n", ioc->name,
|
||||
__FUNCTION__, __LINE__));
|
||||
__func__, __LINE__));
|
||||
sas_rphy_free(rphy);
|
||||
break;
|
||||
}
|
||||
|
@ -461,7 +461,7 @@ mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
|
||||
|
||||
if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
|
||||
ioc->name,__FUNCTION__));
|
||||
ioc->name,__func__));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2187,7 +2187,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m
|
||||
(ioc->debug_level & MPT_DEBUG_TM ))
|
||||
printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
|
||||
"iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
|
||||
"term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
|
||||
"term_cmnds=%d\n", __func__, ioc->id, pScsiTmReply->Bus,
|
||||
pScsiTmReply->TargetID, pScsiTmReq->TaskType,
|
||||
le16_to_cpu(pScsiTmReply->IOCStatus),
|
||||
le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
|
||||
|
@ -360,7 +360,7 @@ config THINKPAD_ACPI_VIDEO
|
||||
If you are not sure, say Y here.
|
||||
|
||||
config THINKPAD_ACPI_HOTKEY_POLL
|
||||
bool "Suport NVRAM polling for hot keys"
|
||||
bool "Support NVRAM polling for hot keys"
|
||||
depends on THINKPAD_ACPI
|
||||
default y
|
||||
---help---
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/atmel-ssc.h>
|
||||
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
@ -27,7 +29,6 @@
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <asm/arch/board.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
|
||||
#include "atmel-mci-regs.h"
|
||||
|
||||
@ -573,7 +574,7 @@ static int atmci_get_ro(struct mmc_host *mmc)
|
||||
int read_only = 0;
|
||||
struct atmel_mci *host = mmc_priv(mmc);
|
||||
|
||||
if (host->wp_pin >= 0) {
|
||||
if (gpio_is_valid(host->wp_pin)) {
|
||||
read_only = gpio_get_value(host->wp_pin);
|
||||
dev_dbg(&mmc->class_dev, "card is %s\n",
|
||||
read_only ? "read-only" : "read-write");
|
||||
@ -635,7 +636,7 @@ static void atmci_detect_change(unsigned long data)
|
||||
* been freed.
|
||||
*/
|
||||
smp_rmb();
|
||||
if (host->detect_pin < 0)
|
||||
if (!gpio_is_valid(host->detect_pin))
|
||||
return;
|
||||
|
||||
enable_irq(gpio_to_irq(host->detect_pin));
|
||||
@ -1050,7 +1051,7 @@ static int __init atmci_probe(struct platform_device *pdev)
|
||||
|
||||
/* Assume card is present if we don't have a detect pin */
|
||||
host->present = 1;
|
||||
if (host->detect_pin >= 0) {
|
||||
if (gpio_is_valid(host->detect_pin)) {
|
||||
if (gpio_request(host->detect_pin, "mmc_detect")) {
|
||||
dev_dbg(&mmc->class_dev, "no detect pin available\n");
|
||||
host->detect_pin = -1;
|
||||
@ -1058,7 +1059,7 @@ static int __init atmci_probe(struct platform_device *pdev)
|
||||
host->present = !gpio_get_value(host->detect_pin);
|
||||
}
|
||||
}
|
||||
if (host->wp_pin >= 0) {
|
||||
if (gpio_is_valid(host->wp_pin)) {
|
||||
if (gpio_request(host->wp_pin, "mmc_wp")) {
|
||||
dev_dbg(&mmc->class_dev, "no WP pin available\n");
|
||||
host->wp_pin = -1;
|
||||
@ -1069,7 +1070,7 @@ static int __init atmci_probe(struct platform_device *pdev)
|
||||
|
||||
mmc_add_host(mmc);
|
||||
|
||||
if (host->detect_pin >= 0) {
|
||||
if (gpio_is_valid(host->detect_pin)) {
|
||||
setup_timer(&host->detect_timer, atmci_detect_change,
|
||||
(unsigned long)host);
|
||||
|
||||
@ -1112,7 +1113,7 @@ static int __exit atmci_remove(struct platform_device *pdev)
|
||||
if (host) {
|
||||
/* Debugfs stuff is cleaned up by mmc core */
|
||||
|
||||
if (host->detect_pin >= 0) {
|
||||
if (gpio_is_valid(host->detect_pin)) {
|
||||
int pin = host->detect_pin;
|
||||
|
||||
/* Make sure the timer doesn't enable the interrupt */
|
||||
@ -1132,7 +1133,7 @@ static int __exit atmci_remove(struct platform_device *pdev)
|
||||
mci_readl(host, SR);
|
||||
clk_disable(host->mck);
|
||||
|
||||
if (host->wp_pin >= 0)
|
||||
if (gpio_is_valid(host->wp_pin))
|
||||
gpio_free(host->wp_pin);
|
||||
|
||||
free_irq(platform_get_irq(pdev, 0), host->mmc);
|
||||
|
@ -6,4 +6,4 @@
|
||||
# it under the terms of the GNU General Public License (version 2 only)
|
||||
# as published by the Free Software Foundation.
|
||||
|
||||
obj-$(CONFIG_VIRTIO) += kvm_virtio.o
|
||||
obj-$(CONFIG_S390_GUEST) += kvm_virtio.o
|
||||
|
@ -4,7 +4,7 @@
|
||||
Written By: Adam Radford <linuxraid@amcc.com>
|
||||
Modifications By: Tom Couch <linuxraid@amcc.com>
|
||||
|
||||
Copyright (C) 2004-2007 Applied Micro Circuits Corporation.
|
||||
Copyright (C) 2004-2008 Applied Micro Circuits Corporation.
|
||||
|
||||
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
|
||||
@ -71,6 +71,10 @@
|
||||
Add support for 9650SE controllers.
|
||||
2.26.02.009 - Fix dma mask setting to fallback to 32-bit if 64-bit fails.
|
||||
2.26.02.010 - Add support for 9690SA controllers.
|
||||
2.26.02.011 - Increase max AENs drained to 256.
|
||||
Add MSI support and "use_msi" module parameter.
|
||||
Fix bug in twa_get_param() on 4GB+.
|
||||
Use pci_resource_len() for ioremap().
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -95,7 +99,7 @@
|
||||
#include "3w-9xxx.h"
|
||||
|
||||
/* Globals */
|
||||
#define TW_DRIVER_VERSION "2.26.02.010"
|
||||
#define TW_DRIVER_VERSION "2.26.02.011"
|
||||
static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
|
||||
static unsigned int twa_device_extension_count;
|
||||
static int twa_major = -1;
|
||||
@ -107,6 +111,10 @@ MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(TW_DRIVER_VERSION);
|
||||
|
||||
static int use_msi = 0;
|
||||
module_param(use_msi, int, S_IRUGO);
|
||||
MODULE_PARM_DESC(use_msi, "Use Message Signaled Interrupts. Default: 0");
|
||||
|
||||
/* Function prototypes */
|
||||
static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header);
|
||||
static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
|
||||
@ -1038,7 +1046,6 @@ static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int tabl
|
||||
TW_Command_Full *full_command_packet;
|
||||
TW_Command *command_packet;
|
||||
TW_Param_Apache *param;
|
||||
unsigned long param_value;
|
||||
void *retval = NULL;
|
||||
|
||||
/* Setup the command packet */
|
||||
@ -1057,9 +1064,8 @@ static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int tabl
|
||||
param->table_id = cpu_to_le16(table_id | 0x8000);
|
||||
param->parameter_id = cpu_to_le16(parameter_id);
|
||||
param->parameter_size_bytes = cpu_to_le16(parameter_size_bytes);
|
||||
param_value = tw_dev->generic_buffer_phys[request_id];
|
||||
|
||||
command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(param_value);
|
||||
command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
|
||||
command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE);
|
||||
|
||||
/* Post the command packet to the board */
|
||||
@ -2000,7 +2006,7 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
|
||||
{
|
||||
struct Scsi_Host *host = NULL;
|
||||
TW_Device_Extension *tw_dev;
|
||||
u32 mem_addr;
|
||||
unsigned long mem_addr, mem_len;
|
||||
int retval = -ENODEV;
|
||||
|
||||
retval = pci_enable_device(pdev);
|
||||
@ -2045,13 +2051,16 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
|
||||
goto out_free_device_extension;
|
||||
}
|
||||
|
||||
if (pdev->device == PCI_DEVICE_ID_3WARE_9000)
|
||||
if (pdev->device == PCI_DEVICE_ID_3WARE_9000) {
|
||||
mem_addr = pci_resource_start(pdev, 1);
|
||||
else
|
||||
mem_len = pci_resource_len(pdev, 1);
|
||||
} else {
|
||||
mem_addr = pci_resource_start(pdev, 2);
|
||||
mem_len = pci_resource_len(pdev, 2);
|
||||
}
|
||||
|
||||
/* Save base address */
|
||||
tw_dev->base_addr = ioremap(mem_addr, PAGE_SIZE);
|
||||
tw_dev->base_addr = ioremap(mem_addr, mem_len);
|
||||
if (!tw_dev->base_addr) {
|
||||
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap");
|
||||
goto out_release_mem_region;
|
||||
@ -2086,7 +2095,7 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
|
||||
|
||||
pci_set_drvdata(pdev, host);
|
||||
|
||||
printk(KERN_WARNING "3w-9xxx: scsi%d: Found a 3ware 9000 Storage Controller at 0x%x, IRQ: %d.\n",
|
||||
printk(KERN_WARNING "3w-9xxx: scsi%d: Found a 3ware 9000 Storage Controller at 0x%lx, IRQ: %d.\n",
|
||||
host->host_no, mem_addr, pdev->irq);
|
||||
printk(KERN_WARNING "3w-9xxx: scsi%d: Firmware %s, BIOS %s, Ports: %d.\n",
|
||||
host->host_no,
|
||||
@ -2097,6 +2106,11 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
|
||||
le32_to_cpu(*(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE,
|
||||
TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH)));
|
||||
|
||||
/* Try to enable MSI */
|
||||
if (use_msi && (pdev->device != PCI_DEVICE_ID_3WARE_9000) &&
|
||||
!pci_enable_msi(pdev))
|
||||
set_bit(TW_USING_MSI, &tw_dev->flags);
|
||||
|
||||
/* Now setup the interrupt handler */
|
||||
retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev);
|
||||
if (retval) {
|
||||
@ -2120,6 +2134,8 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
|
||||
return 0;
|
||||
|
||||
out_remove_host:
|
||||
if (test_bit(TW_USING_MSI, &tw_dev->flags))
|
||||
pci_disable_msi(pdev);
|
||||
scsi_remove_host(host);
|
||||
out_iounmap:
|
||||
iounmap(tw_dev->base_addr);
|
||||
@ -2151,6 +2167,10 @@ static void twa_remove(struct pci_dev *pdev)
|
||||
/* Shutdown the card */
|
||||
__twa_shutdown(tw_dev);
|
||||
|
||||
/* Disable MSI if enabled */
|
||||
if (test_bit(TW_USING_MSI, &tw_dev->flags))
|
||||
pci_disable_msi(pdev);
|
||||
|
||||
/* Free IO remapping */
|
||||
iounmap(tw_dev->base_addr);
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
Written By: Adam Radford <linuxraid@amcc.com>
|
||||
Modifications By: Tom Couch <linuxraid@amcc.com>
|
||||
|
||||
Copyright (C) 2004-2007 Applied Micro Circuits Corporation.
|
||||
Copyright (C) 2004-2008 Applied Micro Circuits Corporation.
|
||||
|
||||
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
|
||||
@ -319,8 +319,8 @@ static twa_message_type twa_error_table[] = {
|
||||
|
||||
/* Compatibility defines */
|
||||
#define TW_9000_ARCH_ID 0x5
|
||||
#define TW_CURRENT_DRIVER_SRL 30
|
||||
#define TW_CURRENT_DRIVER_BUILD 80
|
||||
#define TW_CURRENT_DRIVER_SRL 35
|
||||
#define TW_CURRENT_DRIVER_BUILD 0
|
||||
#define TW_CURRENT_DRIVER_BRANCH 0
|
||||
|
||||
/* Phase defines */
|
||||
@ -352,8 +352,9 @@ static twa_message_type twa_error_table[] = {
|
||||
#define TW_MAX_RESET_TRIES 2
|
||||
#define TW_MAX_CMDS_PER_LUN 254
|
||||
#define TW_MAX_RESPONSE_DRAIN 256
|
||||
#define TW_MAX_AEN_DRAIN 40
|
||||
#define TW_MAX_AEN_DRAIN 255
|
||||
#define TW_IN_RESET 2
|
||||
#define TW_USING_MSI 3
|
||||
#define TW_IN_ATTENTION_LOOP 4
|
||||
#define TW_MAX_SECTORS 256
|
||||
#define TW_AEN_WAIT_TIME 1000
|
||||
|
@ -63,6 +63,7 @@ comment "SCSI support type (disk, tape, CD-ROM)"
|
||||
config BLK_DEV_SD
|
||||
tristate "SCSI disk support"
|
||||
depends on SCSI
|
||||
select CRC_T10DIF
|
||||
---help---
|
||||
If you want to use SCSI hard disks, Fibre Channel disks,
|
||||
Serial ATA (SATA) or Parallel ATA (PATA) hard disks,
|
||||
|
@ -151,6 +151,8 @@ scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o
|
||||
scsi_tgt-y += scsi_tgt_lib.o scsi_tgt_if.o
|
||||
|
||||
sd_mod-objs := sd.o
|
||||
sd_mod-$(CONFIG_BLK_DEV_INTEGRITY) += sd_dif.o
|
||||
|
||||
sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o
|
||||
ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
|
||||
:= -DCONFIG_NCR53C8XX_PREFETCH -DSCSI_NCR_BIG_ENDIAN \
|
||||
|
@ -2278,7 +2278,7 @@ do { \
|
||||
#define ASC_DBG(lvl, format, arg...) { \
|
||||
if (asc_dbglvl >= (lvl)) \
|
||||
printk(KERN_DEBUG "%s: %s: " format, DRV_NAME, \
|
||||
__FUNCTION__ , ## arg); \
|
||||
__func__ , ## arg); \
|
||||
}
|
||||
|
||||
#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
|
||||
|
@ -288,20 +288,20 @@ static LIST_HEAD(aha152x_host_list);
|
||||
#define DO_LOCK(flags) \
|
||||
do { \
|
||||
if(spin_is_locked(&QLOCK)) { \
|
||||
DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
|
||||
DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __func__, __LINE__, QLOCKER, QLOCKERL); \
|
||||
} \
|
||||
DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
|
||||
DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \
|
||||
spin_lock_irqsave(&QLOCK,flags); \
|
||||
DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
|
||||
QLOCKER=__FUNCTION__; \
|
||||
DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \
|
||||
QLOCKER=__func__; \
|
||||
QLOCKERL=__LINE__; \
|
||||
} while(0)
|
||||
|
||||
#define DO_UNLOCK(flags) \
|
||||
do { \
|
||||
DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
|
||||
DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __func__, __LINE__, QLOCKER, QLOCKERL); \
|
||||
spin_unlock_irqrestore(&QLOCK,flags); \
|
||||
DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
|
||||
DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \
|
||||
QLOCKER="(not locked)"; \
|
||||
QLOCKERL=0; \
|
||||
} while(0)
|
||||
|
@ -39,9 +39,9 @@
|
||||
|
||||
#ifdef ASD_ENTER_EXIT
|
||||
#define ENTER printk(KERN_NOTICE "%s: ENTER %s\n", ASD_DRIVER_NAME, \
|
||||
__FUNCTION__)
|
||||
__func__)
|
||||
#define EXIT printk(KERN_NOTICE "%s: --EXIT %s\n", ASD_DRIVER_NAME, \
|
||||
__FUNCTION__)
|
||||
__func__)
|
||||
#else
|
||||
#define ENTER
|
||||
#define EXIT
|
||||
|
@ -1359,7 +1359,7 @@ int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask)
|
||||
struct asd_ascb *ascb_list;
|
||||
|
||||
if (!phy_mask) {
|
||||
asd_printk("%s called with phy_mask of 0!?\n", __FUNCTION__);
|
||||
asd_printk("%s called with phy_mask of 0!?\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -211,7 +211,7 @@ static void asd_form_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
|
||||
phy->asd_port = port;
|
||||
}
|
||||
ASD_DPRINTK("%s: updating phy_mask 0x%x for phy%d\n",
|
||||
__FUNCTION__, phy->asd_port->phy_mask, sas_phy->id);
|
||||
__func__, phy->asd_port->phy_mask, sas_phy->id);
|
||||
asd_update_port_links(asd_ha, phy);
|
||||
spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags);
|
||||
}
|
||||
@ -294,7 +294,7 @@ static void asd_link_reset_err_tasklet(struct asd_ascb *ascb,
|
||||
struct asd_ascb *cp = asd_ascb_alloc_list(ascb->ha, &num,
|
||||
GFP_ATOMIC);
|
||||
if (!cp) {
|
||||
asd_printk("%s: out of memory\n", __FUNCTION__);
|
||||
asd_printk("%s: out of memory\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
ASD_DPRINTK("phy%d: retries:0 performing link reset seq\n",
|
||||
@ -446,7 +446,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
|
||||
struct domain_device *failed_dev = NULL;
|
||||
|
||||
ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n",
|
||||
__FUNCTION__, dl->status_block[3]);
|
||||
__func__, dl->status_block[3]);
|
||||
|
||||
/*
|
||||
* Find the task that caused the abort and abort it first.
|
||||
@ -474,7 +474,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
|
||||
|
||||
if (!failed_dev) {
|
||||
ASD_DPRINTK("%s: Can't find task (tc=%d) to abort!\n",
|
||||
__FUNCTION__, tc_abort);
|
||||
__func__, tc_abort);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -502,7 +502,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
|
||||
conn_handle = *((u16*)(&dl->status_block[1]));
|
||||
conn_handle = le16_to_cpu(conn_handle);
|
||||
|
||||
ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __FUNCTION__,
|
||||
ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __func__,
|
||||
dl->status_block[3]);
|
||||
|
||||
/* Find the last pending task for the device... */
|
||||
@ -522,7 +522,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
|
||||
|
||||
if (!last_dev_task) {
|
||||
ASD_DPRINTK("%s: Device reset for idle device %d?\n",
|
||||
__FUNCTION__, conn_handle);
|
||||
__func__, conn_handle);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -549,10 +549,10 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
|
||||
goto out;
|
||||
}
|
||||
case SIGNAL_NCQ_ERROR:
|
||||
ASD_DPRINTK("%s: SIGNAL_NCQ_ERROR\n", __FUNCTION__);
|
||||
ASD_DPRINTK("%s: SIGNAL_NCQ_ERROR\n", __func__);
|
||||
goto out;
|
||||
case CLEAR_NCQ_ERROR:
|
||||
ASD_DPRINTK("%s: CLEAR_NCQ_ERROR\n", __FUNCTION__);
|
||||
ASD_DPRINTK("%s: CLEAR_NCQ_ERROR\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -560,26 +560,26 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
|
||||
|
||||
switch (sb_opcode) {
|
||||
case BYTES_DMAED:
|
||||
ASD_DPRINTK("%s: phy%d: BYTES_DMAED\n", __FUNCTION__, phy_id);
|
||||
ASD_DPRINTK("%s: phy%d: BYTES_DMAED\n", __func__, phy_id);
|
||||
asd_bytes_dmaed_tasklet(ascb, dl, edb, phy_id);
|
||||
break;
|
||||
case PRIMITIVE_RECVD:
|
||||
ASD_DPRINTK("%s: phy%d: PRIMITIVE_RECVD\n", __FUNCTION__,
|
||||
ASD_DPRINTK("%s: phy%d: PRIMITIVE_RECVD\n", __func__,
|
||||
phy_id);
|
||||
asd_primitive_rcvd_tasklet(ascb, dl, phy_id);
|
||||
break;
|
||||
case PHY_EVENT:
|
||||
ASD_DPRINTK("%s: phy%d: PHY_EVENT\n", __FUNCTION__, phy_id);
|
||||
ASD_DPRINTK("%s: phy%d: PHY_EVENT\n", __func__, phy_id);
|
||||
asd_phy_event_tasklet(ascb, dl);
|
||||
break;
|
||||
case LINK_RESET_ERROR:
|
||||
ASD_DPRINTK("%s: phy%d: LINK_RESET_ERROR\n", __FUNCTION__,
|
||||
ASD_DPRINTK("%s: phy%d: LINK_RESET_ERROR\n", __func__,
|
||||
phy_id);
|
||||
asd_link_reset_err_tasklet(ascb, dl, phy_id);
|
||||
break;
|
||||
case TIMER_EVENT:
|
||||
ASD_DPRINTK("%s: phy%d: TIMER_EVENT, lost dw sync\n",
|
||||
__FUNCTION__, phy_id);
|
||||
__func__, phy_id);
|
||||
asd_turn_led(asd_ha, phy_id, 0);
|
||||
/* the device is gone */
|
||||
sas_phy_disconnected(sas_phy);
|
||||
@ -587,7 +587,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
|
||||
sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT);
|
||||
break;
|
||||
default:
|
||||
ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __FUNCTION__,
|
||||
ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __func__,
|
||||
phy_id, sb_opcode);
|
||||
ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n",
|
||||
edb, dl->opcode);
|
||||
@ -654,7 +654,7 @@ static void control_phy_tasklet_complete(struct asd_ascb *ascb,
|
||||
|
||||
if (status != 0) {
|
||||
ASD_DPRINTK("%s: phy%d status block opcode:0x%x\n",
|
||||
__FUNCTION__, phy_id, status);
|
||||
__func__, phy_id, status);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -663,7 +663,7 @@ static void control_phy_tasklet_complete(struct asd_ascb *ascb,
|
||||
asd_ha->hw_prof.enabled_phys &= ~(1 << phy_id);
|
||||
asd_turn_led(asd_ha, phy_id, 0);
|
||||
asd_control_led(asd_ha, phy_id, 0);
|
||||
ASD_DPRINTK("%s: disable phy%d\n", __FUNCTION__, phy_id);
|
||||
ASD_DPRINTK("%s: disable phy%d\n", __func__, phy_id);
|
||||
break;
|
||||
|
||||
case ENABLE_PHY:
|
||||
@ -673,40 +673,40 @@ static void control_phy_tasklet_complete(struct asd_ascb *ascb,
|
||||
get_lrate_mode(phy, oob_mode);
|
||||
asd_turn_led(asd_ha, phy_id, 1);
|
||||
ASD_DPRINTK("%s: phy%d, lrate:0x%x, proto:0x%x\n",
|
||||
__FUNCTION__, phy_id,phy->sas_phy.linkrate,
|
||||
__func__, phy_id,phy->sas_phy.linkrate,
|
||||
phy->sas_phy.iproto);
|
||||
} else if (oob_status & CURRENT_SPINUP_HOLD) {
|
||||
asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
|
||||
asd_turn_led(asd_ha, phy_id, 1);
|
||||
ASD_DPRINTK("%s: phy%d, spinup hold\n", __FUNCTION__,
|
||||
ASD_DPRINTK("%s: phy%d, spinup hold\n", __func__,
|
||||
phy_id);
|
||||
} else if (oob_status & CURRENT_ERR_MASK) {
|
||||
asd_turn_led(asd_ha, phy_id, 0);
|
||||
ASD_DPRINTK("%s: phy%d: error: oob status:0x%02x\n",
|
||||
__FUNCTION__, phy_id, oob_status);
|
||||
__func__, phy_id, oob_status);
|
||||
} else if (oob_status & (CURRENT_HOT_PLUG_CNCT
|
||||
| CURRENT_DEVICE_PRESENT)) {
|
||||
asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
|
||||
asd_turn_led(asd_ha, phy_id, 1);
|
||||
ASD_DPRINTK("%s: phy%d: hot plug or device present\n",
|
||||
__FUNCTION__, phy_id);
|
||||
__func__, phy_id);
|
||||
} else {
|
||||
asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
|
||||
asd_turn_led(asd_ha, phy_id, 0);
|
||||
ASD_DPRINTK("%s: phy%d: no device present: "
|
||||
"oob_status:0x%x\n",
|
||||
__FUNCTION__, phy_id, oob_status);
|
||||
__func__, phy_id, oob_status);
|
||||
}
|
||||
break;
|
||||
case RELEASE_SPINUP_HOLD:
|
||||
case PHY_NO_OP:
|
||||
case EXECUTE_HARD_RESET:
|
||||
ASD_DPRINTK("%s: phy%d: sub_func:0x%x\n", __FUNCTION__,
|
||||
ASD_DPRINTK("%s: phy%d: sub_func:0x%x\n", __func__,
|
||||
phy_id, control_phy->sub_func);
|
||||
/* XXX finish */
|
||||
break;
|
||||
default:
|
||||
ASD_DPRINTK("%s: phy%d: sub_func:0x%x?\n", __FUNCTION__,
|
||||
ASD_DPRINTK("%s: phy%d: sub_func:0x%x?\n", __func__,
|
||||
phy_id, control_phy->sub_func);
|
||||
break;
|
||||
}
|
||||
|
@ -320,7 +320,7 @@ Again:
|
||||
case TC_RESUME:
|
||||
case TC_PARTIAL_SG_LIST:
|
||||
default:
|
||||
ASD_DPRINTK("%s: dl opcode: 0x%x?\n", __FUNCTION__, opcode);
|
||||
ASD_DPRINTK("%s: dl opcode: 0x%x?\n", __func__, opcode);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -75,12 +75,12 @@ static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb,
|
||||
struct done_list_struct *dl)
|
||||
{
|
||||
struct tasklet_completion_status *tcs = ascb->uldd_task;
|
||||
ASD_DPRINTK("%s: here\n", __FUNCTION__);
|
||||
ASD_DPRINTK("%s: here\n", __func__);
|
||||
if (!del_timer(&ascb->timer)) {
|
||||
ASD_DPRINTK("%s: couldn't delete timer\n", __FUNCTION__);
|
||||
ASD_DPRINTK("%s: couldn't delete timer\n", __func__);
|
||||
return;
|
||||
}
|
||||
ASD_DPRINTK("%s: opcode: 0x%x\n", __FUNCTION__, dl->opcode);
|
||||
ASD_DPRINTK("%s: opcode: 0x%x\n", __func__, dl->opcode);
|
||||
tcs->dl_opcode = dl->opcode;
|
||||
complete(ascb->completion);
|
||||
asd_ascb_free(ascb);
|
||||
@ -91,7 +91,7 @@ static void asd_clear_nexus_timedout(unsigned long data)
|
||||
struct asd_ascb *ascb = (void *)data;
|
||||
struct tasklet_completion_status *tcs = ascb->uldd_task;
|
||||
|
||||
ASD_DPRINTK("%s: here\n", __FUNCTION__);
|
||||
ASD_DPRINTK("%s: here\n", __func__);
|
||||
tcs->dl_opcode = TMF_RESP_FUNC_FAILED;
|
||||
complete(ascb->completion);
|
||||
}
|
||||
@ -103,7 +103,7 @@ static void asd_clear_nexus_timedout(unsigned long data)
|
||||
DECLARE_COMPLETION_ONSTACK(completion); \
|
||||
DECLARE_TCS(tcs); \
|
||||
\
|
||||
ASD_DPRINTK("%s: PRE\n", __FUNCTION__); \
|
||||
ASD_DPRINTK("%s: PRE\n", __func__); \
|
||||
res = 1; \
|
||||
ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); \
|
||||
if (!ascb) \
|
||||
@ -115,12 +115,12 @@ static void asd_clear_nexus_timedout(unsigned long data)
|
||||
scb->header.opcode = CLEAR_NEXUS
|
||||
|
||||
#define CLEAR_NEXUS_POST \
|
||||
ASD_DPRINTK("%s: POST\n", __FUNCTION__); \
|
||||
ASD_DPRINTK("%s: POST\n", __func__); \
|
||||
res = asd_enqueue_internal(ascb, asd_clear_nexus_tasklet_complete, \
|
||||
asd_clear_nexus_timedout); \
|
||||
if (res) \
|
||||
goto out_err; \
|
||||
ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __FUNCTION__); \
|
||||
ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __func__); \
|
||||
wait_for_completion(&completion); \
|
||||
res = tcs.dl_opcode; \
|
||||
if (res == TC_NO_ERROR) \
|
||||
@ -417,7 +417,7 @@ int asd_abort_task(struct sas_task *task)
|
||||
if (task->task_state_flags & SAS_TASK_STATE_DONE) {
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
res = TMF_RESP_FUNC_COMPLETE;
|
||||
ASD_DPRINTK("%s: task 0x%p done\n", __FUNCTION__, task);
|
||||
ASD_DPRINTK("%s: task 0x%p done\n", __func__, task);
|
||||
goto out_done;
|
||||
}
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
@ -481,7 +481,7 @@ int asd_abort_task(struct sas_task *task)
|
||||
if (task->task_state_flags & SAS_TASK_STATE_DONE) {
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
res = TMF_RESP_FUNC_COMPLETE;
|
||||
ASD_DPRINTK("%s: task 0x%p done\n", __FUNCTION__, task);
|
||||
ASD_DPRINTK("%s: task 0x%p done\n", __func__, task);
|
||||
goto out_done;
|
||||
}
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
|
@ -240,7 +240,7 @@ static void __fas216_checkmagic(FAS216_Info *info, const char *func)
|
||||
panic("scsi memory space corrupted in %s", func);
|
||||
}
|
||||
}
|
||||
#define fas216_checkmagic(info) __fas216_checkmagic((info), __FUNCTION__)
|
||||
#define fas216_checkmagic(info) __fas216_checkmagic((info), __func__)
|
||||
#else
|
||||
#define fas216_checkmagic(info)
|
||||
#endif
|
||||
@ -2658,7 +2658,7 @@ int fas216_eh_host_reset(struct scsi_cmnd *SCpnt)
|
||||
fas216_checkmagic(info);
|
||||
|
||||
printk("scsi%d.%c: %s: resetting host\n",
|
||||
info->host->host_no, '0' + SCpnt->device->id, __FUNCTION__);
|
||||
info->host->host_no, '0' + SCpnt->device->id, __func__);
|
||||
|
||||
/*
|
||||
* Reset the SCSI chip.
|
||||
|
@ -930,6 +930,7 @@ static int ch_probe(struct device *dev)
|
||||
if (init)
|
||||
ch_init_elem(ch);
|
||||
|
||||
dev_set_drvdata(dev, ch);
|
||||
sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);
|
||||
|
||||
return 0;
|
||||
|
@ -30,3 +30,11 @@ config SCSI_DH_EMC
|
||||
depends on SCSI_DH
|
||||
help
|
||||
If you have a EMC CLARiiON select y. Otherwise, say N.
|
||||
|
||||
config SCSI_DH_ALUA
|
||||
tristate "SPC-3 ALUA Device Handler (EXPERIMENTAL)"
|
||||
depends on SCSI_DH && EXPERIMENTAL
|
||||
help
|
||||
SCSI Device handler for generic SPC-3 Asymmetric Logical Unit
|
||||
Access (ALUA).
|
||||
|
||||
|
@ -5,3 +5,4 @@ obj-$(CONFIG_SCSI_DH) += scsi_dh.o
|
||||
obj-$(CONFIG_SCSI_DH_RDAC) += scsi_dh_rdac.o
|
||||
obj-$(CONFIG_SCSI_DH_HP_SW) += scsi_dh_hp_sw.o
|
||||
obj-$(CONFIG_SCSI_DH_EMC) += scsi_dh_emc.o
|
||||
obj-$(CONFIG_SCSI_DH_ALUA) += scsi_dh_alua.o
|
||||
|
@ -24,8 +24,16 @@
|
||||
#include <scsi/scsi_dh.h>
|
||||
#include "../scsi_priv.h"
|
||||
|
||||
struct scsi_dh_devinfo_list {
|
||||
struct list_head node;
|
||||
char vendor[9];
|
||||
char model[17];
|
||||
struct scsi_device_handler *handler;
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(list_lock);
|
||||
static LIST_HEAD(scsi_dh_list);
|
||||
static LIST_HEAD(scsi_dh_dev_list);
|
||||
|
||||
static struct scsi_device_handler *get_device_handler(const char *name)
|
||||
{
|
||||
@ -33,7 +41,7 @@ static struct scsi_device_handler *get_device_handler(const char *name)
|
||||
|
||||
spin_lock(&list_lock);
|
||||
list_for_each_entry(tmp, &scsi_dh_list, list) {
|
||||
if (!strcmp(tmp->name, name)) {
|
||||
if (!strncmp(tmp->name, name, strlen(tmp->name))) {
|
||||
found = tmp;
|
||||
break;
|
||||
}
|
||||
@ -42,11 +50,307 @@ static struct scsi_device_handler *get_device_handler(const char *name)
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
static struct scsi_device_handler *
|
||||
scsi_dh_cache_lookup(struct scsi_device *sdev)
|
||||
{
|
||||
struct scsi_dh_devinfo_list *tmp;
|
||||
struct scsi_device_handler *found_dh = NULL;
|
||||
|
||||
spin_lock(&list_lock);
|
||||
list_for_each_entry(tmp, &scsi_dh_dev_list, node) {
|
||||
if (!strncmp(sdev->vendor, tmp->vendor, strlen(tmp->vendor)) &&
|
||||
!strncmp(sdev->model, tmp->model, strlen(tmp->model))) {
|
||||
found_dh = tmp->handler;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&list_lock);
|
||||
|
||||
return found_dh;
|
||||
}
|
||||
|
||||
static int scsi_dh_handler_lookup(struct scsi_device_handler *scsi_dh,
|
||||
struct scsi_device *sdev)
|
||||
{
|
||||
int i, found = 0;
|
||||
|
||||
for(i = 0; scsi_dh->devlist[i].vendor; i++) {
|
||||
if (!strncmp(sdev->vendor, scsi_dh->devlist[i].vendor,
|
||||
strlen(scsi_dh->devlist[i].vendor)) &&
|
||||
!strncmp(sdev->model, scsi_dh->devlist[i].model,
|
||||
strlen(scsi_dh->devlist[i].model))) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
/*
|
||||
* device_handler_match - Attach a device handler to a device
|
||||
* @scsi_dh - The device handler to match against or NULL
|
||||
* @sdev - SCSI device to be tested against @scsi_dh
|
||||
*
|
||||
* Tests @sdev against the device handler @scsi_dh or against
|
||||
* all registered device_handler if @scsi_dh == NULL.
|
||||
* Returns the found device handler or NULL if not found.
|
||||
*/
|
||||
static struct scsi_device_handler *
|
||||
device_handler_match(struct scsi_device_handler *scsi_dh,
|
||||
struct scsi_device *sdev)
|
||||
{
|
||||
struct scsi_device_handler *found_dh = NULL;
|
||||
struct scsi_dh_devinfo_list *tmp;
|
||||
|
||||
found_dh = scsi_dh_cache_lookup(sdev);
|
||||
if (found_dh)
|
||||
return found_dh;
|
||||
|
||||
if (scsi_dh) {
|
||||
if (scsi_dh_handler_lookup(scsi_dh, sdev))
|
||||
found_dh = scsi_dh;
|
||||
} else {
|
||||
struct scsi_device_handler *tmp_dh;
|
||||
|
||||
spin_lock(&list_lock);
|
||||
list_for_each_entry(tmp_dh, &scsi_dh_list, list) {
|
||||
if (scsi_dh_handler_lookup(tmp_dh, sdev))
|
||||
found_dh = tmp_dh;
|
||||
}
|
||||
spin_unlock(&list_lock);
|
||||
}
|
||||
|
||||
if (found_dh) { /* If device is found, add it to the cache */
|
||||
tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
|
||||
if (tmp) {
|
||||
strncpy(tmp->vendor, sdev->vendor, 8);
|
||||
strncpy(tmp->model, sdev->model, 16);
|
||||
tmp->vendor[8] = '\0';
|
||||
tmp->model[16] = '\0';
|
||||
tmp->handler = found_dh;
|
||||
spin_lock(&list_lock);
|
||||
list_add(&tmp->node, &scsi_dh_dev_list);
|
||||
spin_unlock(&list_lock);
|
||||
} else {
|
||||
found_dh = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return found_dh;
|
||||
}
|
||||
|
||||
/*
|
||||
* scsi_dh_handler_attach - Attach a device handler to a device
|
||||
* @sdev - SCSI device the device handler should attach to
|
||||
* @scsi_dh - The device handler to attach
|
||||
*/
|
||||
static int scsi_dh_handler_attach(struct scsi_device *sdev,
|
||||
struct scsi_device_handler *scsi_dh)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (sdev->scsi_dh_data) {
|
||||
if (sdev->scsi_dh_data->scsi_dh != scsi_dh)
|
||||
err = -EBUSY;
|
||||
} else if (scsi_dh->attach)
|
||||
err = scsi_dh->attach(sdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* scsi_dh_handler_detach - Detach a device handler from a device
|
||||
* @sdev - SCSI device the device handler should be detached from
|
||||
* @scsi_dh - Device handler to be detached
|
||||
*
|
||||
* Detach from a device handler. If a device handler is specified,
|
||||
* only detach if the currently attached handler matches @scsi_dh.
|
||||
*/
|
||||
static void scsi_dh_handler_detach(struct scsi_device *sdev,
|
||||
struct scsi_device_handler *scsi_dh)
|
||||
{
|
||||
if (!sdev->scsi_dh_data)
|
||||
return;
|
||||
|
||||
if (scsi_dh && scsi_dh != sdev->scsi_dh_data->scsi_dh)
|
||||
return;
|
||||
|
||||
if (!scsi_dh)
|
||||
scsi_dh = sdev->scsi_dh_data->scsi_dh;
|
||||
|
||||
if (scsi_dh && scsi_dh->detach)
|
||||
scsi_dh->detach(sdev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions for sysfs attribute 'dh_state'
|
||||
*/
|
||||
static ssize_t
|
||||
store_dh_state(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct scsi_device *sdev = to_scsi_device(dev);
|
||||
struct scsi_device_handler *scsi_dh;
|
||||
int err = -EINVAL;
|
||||
|
||||
if (!sdev->scsi_dh_data) {
|
||||
/*
|
||||
* Attach to a device handler
|
||||
*/
|
||||
if (!(scsi_dh = get_device_handler(buf)))
|
||||
return err;
|
||||
err = scsi_dh_handler_attach(sdev, scsi_dh);
|
||||
} else {
|
||||
scsi_dh = sdev->scsi_dh_data->scsi_dh;
|
||||
if (!strncmp(buf, "detach", 6)) {
|
||||
/*
|
||||
* Detach from a device handler
|
||||
*/
|
||||
scsi_dh_handler_detach(sdev, scsi_dh);
|
||||
err = 0;
|
||||
} else if (!strncmp(buf, "activate", 8)) {
|
||||
/*
|
||||
* Activate a device handler
|
||||
*/
|
||||
if (scsi_dh->activate)
|
||||
err = scsi_dh->activate(sdev);
|
||||
else
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return err<0?err:count;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
show_dh_state(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct scsi_device *sdev = to_scsi_device(dev);
|
||||
|
||||
if (!sdev->scsi_dh_data)
|
||||
return snprintf(buf, 20, "detached\n");
|
||||
|
||||
return snprintf(buf, 20, "%s\n", sdev->scsi_dh_data->scsi_dh->name);
|
||||
}
|
||||
|
||||
static struct device_attribute scsi_dh_state_attr =
|
||||
__ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state,
|
||||
store_dh_state);
|
||||
|
||||
/*
|
||||
* scsi_dh_sysfs_attr_add - Callback for scsi_init_dh
|
||||
*/
|
||||
static int scsi_dh_sysfs_attr_add(struct device *dev, void *data)
|
||||
{
|
||||
struct scsi_device *sdev;
|
||||
int err;
|
||||
|
||||
if (!scsi_is_sdev_device(dev))
|
||||
return 0;
|
||||
|
||||
sdev = to_scsi_device(dev);
|
||||
|
||||
err = device_create_file(&sdev->sdev_gendev,
|
||||
&scsi_dh_state_attr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* scsi_dh_sysfs_attr_remove - Callback for scsi_exit_dh
|
||||
*/
|
||||
static int scsi_dh_sysfs_attr_remove(struct device *dev, void *data)
|
||||
{
|
||||
struct scsi_device *sdev;
|
||||
|
||||
if (!scsi_is_sdev_device(dev))
|
||||
return 0;
|
||||
|
||||
sdev = to_scsi_device(dev);
|
||||
|
||||
device_remove_file(&sdev->sdev_gendev,
|
||||
&scsi_dh_state_attr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* scsi_dh_notifier - notifier chain callback
|
||||
*/
|
||||
static int scsi_dh_notifier(struct notifier_block *nb,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
struct device *dev = data;
|
||||
struct scsi_device *sdev;
|
||||
int err = 0;
|
||||
struct scsi_device_handler *devinfo = NULL;
|
||||
|
||||
if (!scsi_is_sdev_device(dev))
|
||||
return 0;
|
||||
|
||||
sdev = to_scsi_device(dev);
|
||||
|
||||
if (action == BUS_NOTIFY_ADD_DEVICE) {
|
||||
devinfo = device_handler_match(NULL, sdev);
|
||||
if (!devinfo)
|
||||
goto out;
|
||||
|
||||
err = scsi_dh_handler_attach(sdev, devinfo);
|
||||
if (!err)
|
||||
err = device_create_file(dev, &scsi_dh_state_attr);
|
||||
} else if (action == BUS_NOTIFY_DEL_DEVICE) {
|
||||
device_remove_file(dev, &scsi_dh_state_attr);
|
||||
scsi_dh_handler_detach(sdev, NULL);
|
||||
}
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* scsi_dh_notifier_add - Callback for scsi_register_device_handler
|
||||
*/
|
||||
static int scsi_dh_notifier_add(struct device *dev, void *data)
|
||||
{
|
||||
struct scsi_device_handler *scsi_dh = data;
|
||||
struct scsi_device *sdev;
|
||||
|
||||
if (!scsi_is_sdev_device(dev))
|
||||
return 0;
|
||||
|
||||
if (!get_device(dev))
|
||||
return 0;
|
||||
|
||||
sdev = to_scsi_device(dev);
|
||||
|
||||
if (device_handler_match(scsi_dh, sdev))
|
||||
scsi_dh_handler_attach(sdev, scsi_dh);
|
||||
|
||||
put_device(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* scsi_dh_notifier_remove - Callback for scsi_unregister_device_handler
|
||||
*/
|
||||
static int scsi_dh_notifier_remove(struct device *dev, void *data)
|
||||
{
|
||||
struct scsi_device_handler *scsi_dh = data;
|
||||
struct scsi_device *sdev;
|
||||
|
||||
if (!scsi_is_sdev_device(dev))
|
||||
return 0;
|
||||
|
||||
if (!get_device(dev))
|
||||
return 0;
|
||||
|
||||
sdev = to_scsi_device(dev);
|
||||
|
||||
scsi_dh_handler_detach(sdev, scsi_dh);
|
||||
|
||||
put_device(dev);
|
||||
|
||||
scsi_dh->nb.notifier_call(&scsi_dh->nb, BUS_NOTIFY_ADD_DEVICE, dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -59,33 +363,19 @@ static int scsi_dh_notifier_add(struct device *dev, void *data)
|
||||
*/
|
||||
int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
|
||||
{
|
||||
int ret = -EBUSY;
|
||||
struct scsi_device_handler *tmp;
|
||||
if (get_device_handler(scsi_dh->name))
|
||||
return -EBUSY;
|
||||
|
||||
tmp = get_device_handler(scsi_dh->name);
|
||||
if (tmp)
|
||||
goto done;
|
||||
|
||||
ret = bus_register_notifier(&scsi_bus_type, &scsi_dh->nb);
|
||||
|
||||
bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add);
|
||||
spin_lock(&list_lock);
|
||||
list_add(&scsi_dh->list, &scsi_dh_list);
|
||||
spin_unlock(&list_lock);
|
||||
bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add);
|
||||
printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
return SCSI_DH_OK;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_register_device_handler);
|
||||
|
||||
static int scsi_dh_notifier_remove(struct device *dev, void *data)
|
||||
{
|
||||
struct scsi_device_handler *scsi_dh = data;
|
||||
|
||||
scsi_dh->nb.notifier_call(&scsi_dh->nb, BUS_NOTIFY_DEL_DEVICE, dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* scsi_unregister_device_handler - register a device handler personality
|
||||
* module.
|
||||
@ -95,23 +385,26 @@ static int scsi_dh_notifier_remove(struct device *dev, void *data)
|
||||
*/
|
||||
int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
|
||||
{
|
||||
int ret = -ENODEV;
|
||||
struct scsi_device_handler *tmp;
|
||||
struct scsi_dh_devinfo_list *tmp, *pos;
|
||||
|
||||
tmp = get_device_handler(scsi_dh->name);
|
||||
if (!tmp)
|
||||
goto done;
|
||||
|
||||
ret = bus_unregister_notifier(&scsi_bus_type, &scsi_dh->nb);
|
||||
if (!get_device_handler(scsi_dh->name))
|
||||
return -ENODEV;
|
||||
|
||||
bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh,
|
||||
scsi_dh_notifier_remove);
|
||||
scsi_dh_notifier_remove);
|
||||
|
||||
spin_lock(&list_lock);
|
||||
list_del(&scsi_dh->list);
|
||||
list_for_each_entry_safe(pos, tmp, &scsi_dh_dev_list, node) {
|
||||
if (pos->handler == scsi_dh) {
|
||||
list_del(&pos->node);
|
||||
kfree(pos);
|
||||
}
|
||||
}
|
||||
spin_unlock(&list_lock);
|
||||
printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
return SCSI_DH_OK;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
|
||||
|
||||
@ -157,6 +450,97 @@ int scsi_dh_handler_exist(const char *name)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_dh_handler_exist);
|
||||
|
||||
/*
|
||||
* scsi_dh_handler_attach - Attach device handler
|
||||
* @sdev - sdev the handler should be attached to
|
||||
* @name - name of the handler to attach
|
||||
*/
|
||||
int scsi_dh_attach(struct request_queue *q, const char *name)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct scsi_device *sdev;
|
||||
struct scsi_device_handler *scsi_dh;
|
||||
int err = 0;
|
||||
|
||||
scsi_dh = get_device_handler(name);
|
||||
if (!scsi_dh)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(q->queue_lock, flags);
|
||||
sdev = q->queuedata;
|
||||
if (!sdev || !get_device(&sdev->sdev_gendev))
|
||||
err = -ENODEV;
|
||||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
|
||||
if (!err) {
|
||||
err = scsi_dh_handler_attach(sdev, scsi_dh);
|
||||
|
||||
put_device(&sdev->sdev_gendev);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_dh_attach);
|
||||
|
||||
/*
|
||||
* scsi_dh_handler_detach - Detach device handler
|
||||
* @sdev - sdev the handler should be detached from
|
||||
*
|
||||
* This function will detach the device handler only
|
||||
* if the sdev is not part of the internal list, ie
|
||||
* if it has been attached manually.
|
||||
*/
|
||||
void scsi_dh_detach(struct request_queue *q)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct scsi_device *sdev;
|
||||
struct scsi_device_handler *scsi_dh = NULL;
|
||||
|
||||
spin_lock_irqsave(q->queue_lock, flags);
|
||||
sdev = q->queuedata;
|
||||
if (!sdev || !get_device(&sdev->sdev_gendev))
|
||||
sdev = NULL;
|
||||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
|
||||
if (!sdev)
|
||||
return;
|
||||
|
||||
if (sdev->scsi_dh_data) {
|
||||
/* if sdev is not on internal list, detach */
|
||||
scsi_dh = sdev->scsi_dh_data->scsi_dh;
|
||||
if (!device_handler_match(scsi_dh, sdev))
|
||||
scsi_dh_handler_detach(sdev, scsi_dh);
|
||||
}
|
||||
put_device(&sdev->sdev_gendev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_dh_detach);
|
||||
|
||||
static struct notifier_block scsi_dh_nb = {
|
||||
.notifier_call = scsi_dh_notifier
|
||||
};
|
||||
|
||||
static int __init scsi_dh_init(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb);
|
||||
|
||||
if (!r)
|
||||
bus_for_each_dev(&scsi_bus_type, NULL, NULL,
|
||||
scsi_dh_sysfs_attr_add);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void __exit scsi_dh_exit(void)
|
||||
{
|
||||
bus_for_each_dev(&scsi_bus_type, NULL, NULL,
|
||||
scsi_dh_sysfs_attr_remove);
|
||||
bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb);
|
||||
}
|
||||
|
||||
module_init(scsi_dh_init);
|
||||
module_exit(scsi_dh_exit);
|
||||
|
||||
MODULE_DESCRIPTION("SCSI device handler");
|
||||
MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
802
drivers/scsi/device_handler/scsi_dh_alua.c
Normal file
802
drivers/scsi/device_handler/scsi_dh_alua.c
Normal file
@ -0,0 +1,802 @@
|
||||
/*
|
||||
* Generic SCSI-3 ALUA SCSI Device Handler
|
||||
*
|
||||
* Copyright (C) 2007, 2008 Hannes Reinecke, SUSE Linux Products GmbH.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 <scsi/scsi.h>
|
||||
#include <scsi/scsi_eh.h>
|
||||
#include <scsi/scsi_dh.h>
|
||||
|
||||
#define ALUA_DH_NAME "alua"
|
||||
#define ALUA_DH_VER "1.2"
|
||||
|
||||
#define TPGS_STATE_OPTIMIZED 0x0
|
||||
#define TPGS_STATE_NONOPTIMIZED 0x1
|
||||
#define TPGS_STATE_STANDBY 0x2
|
||||
#define TPGS_STATE_UNAVAILABLE 0x3
|
||||
#define TPGS_STATE_OFFLINE 0xe
|
||||
#define TPGS_STATE_TRANSITIONING 0xf
|
||||
|
||||
#define TPGS_SUPPORT_NONE 0x00
|
||||
#define TPGS_SUPPORT_OPTIMIZED 0x01
|
||||
#define TPGS_SUPPORT_NONOPTIMIZED 0x02
|
||||
#define TPGS_SUPPORT_STANDBY 0x04
|
||||
#define TPGS_SUPPORT_UNAVAILABLE 0x08
|
||||
#define TPGS_SUPPORT_OFFLINE 0x40
|
||||
#define TPGS_SUPPORT_TRANSITION 0x80
|
||||
|
||||
#define TPGS_MODE_UNINITIALIZED -1
|
||||
#define TPGS_MODE_NONE 0x0
|
||||
#define TPGS_MODE_IMPLICIT 0x1
|
||||
#define TPGS_MODE_EXPLICIT 0x2
|
||||
|
||||
#define ALUA_INQUIRY_SIZE 36
|
||||
#define ALUA_FAILOVER_TIMEOUT (60 * HZ)
|
||||
#define ALUA_FAILOVER_RETRIES 5
|
||||
|
||||
struct alua_dh_data {
|
||||
int group_id;
|
||||
int rel_port;
|
||||
int tpgs;
|
||||
int state;
|
||||
unsigned char inq[ALUA_INQUIRY_SIZE];
|
||||
unsigned char *buff;
|
||||
int bufflen;
|
||||
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
|
||||
int senselen;
|
||||
};
|
||||
|
||||
#define ALUA_POLICY_SWITCH_CURRENT 0
|
||||
#define ALUA_POLICY_SWITCH_ALL 1
|
||||
|
||||
static inline struct alua_dh_data *get_alua_data(struct scsi_device *sdev)
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
|
||||
BUG_ON(scsi_dh_data == NULL);
|
||||
return ((struct alua_dh_data *) scsi_dh_data->buf);
|
||||
}
|
||||
|
||||
static int realloc_buffer(struct alua_dh_data *h, unsigned len)
|
||||
{
|
||||
if (h->buff && h->buff != h->inq)
|
||||
kfree(h->buff);
|
||||
|
||||
h->buff = kmalloc(len, GFP_NOIO);
|
||||
if (!h->buff) {
|
||||
h->buff = h->inq;
|
||||
h->bufflen = ALUA_INQUIRY_SIZE;
|
||||
return 1;
|
||||
}
|
||||
h->bufflen = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct request *get_alua_req(struct scsi_device *sdev,
|
||||
void *buffer, unsigned buflen, int rw)
|
||||
{
|
||||
struct request *rq;
|
||||
struct request_queue *q = sdev->request_queue;
|
||||
|
||||
rq = blk_get_request(q, rw, GFP_NOIO);
|
||||
|
||||
if (!rq) {
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: blk_get_request failed\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) {
|
||||
blk_put_request(rq);
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: blk_rq_map_kern failed\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rq->cmd_type = REQ_TYPE_BLOCK_PC;
|
||||
rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
|
||||
rq->retries = ALUA_FAILOVER_RETRIES;
|
||||
rq->timeout = ALUA_FAILOVER_TIMEOUT;
|
||||
|
||||
return rq;
|
||||
}
|
||||
|
||||
/*
|
||||
* submit_std_inquiry - Issue a standard INQUIRY command
|
||||
* @sdev: sdev the command should be send to
|
||||
*/
|
||||
static int submit_std_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
|
||||
{
|
||||
struct request *rq;
|
||||
int err = SCSI_DH_RES_TEMP_UNAVAIL;
|
||||
|
||||
rq = get_alua_req(sdev, h->inq, ALUA_INQUIRY_SIZE, READ);
|
||||
if (!rq)
|
||||
goto done;
|
||||
|
||||
/* Prepare the command. */
|
||||
rq->cmd[0] = INQUIRY;
|
||||
rq->cmd[1] = 0;
|
||||
rq->cmd[2] = 0;
|
||||
rq->cmd[4] = ALUA_INQUIRY_SIZE;
|
||||
rq->cmd_len = COMMAND_SIZE(INQUIRY);
|
||||
|
||||
rq->sense = h->sense;
|
||||
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
|
||||
rq->sense_len = h->senselen = 0;
|
||||
|
||||
err = blk_execute_rq(rq->q, NULL, rq, 1);
|
||||
if (err == -EIO) {
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: std inquiry failed with %x\n",
|
||||
ALUA_DH_NAME, rq->errors);
|
||||
h->senselen = rq->sense_len;
|
||||
err = SCSI_DH_IO;
|
||||
}
|
||||
blk_put_request(rq);
|
||||
done:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* submit_vpd_inquiry - Issue an INQUIRY VPD page 0x83 command
|
||||
* @sdev: sdev the command should be sent to
|
||||
*/
|
||||
static int submit_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
|
||||
{
|
||||
struct request *rq;
|
||||
int err = SCSI_DH_RES_TEMP_UNAVAIL;
|
||||
|
||||
rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
|
||||
if (!rq)
|
||||
goto done;
|
||||
|
||||
/* Prepare the command. */
|
||||
rq->cmd[0] = INQUIRY;
|
||||
rq->cmd[1] = 1;
|
||||
rq->cmd[2] = 0x83;
|
||||
rq->cmd[4] = h->bufflen;
|
||||
rq->cmd_len = COMMAND_SIZE(INQUIRY);
|
||||
|
||||
rq->sense = h->sense;
|
||||
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
|
||||
rq->sense_len = h->senselen = 0;
|
||||
|
||||
err = blk_execute_rq(rq->q, NULL, rq, 1);
|
||||
if (err == -EIO) {
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: evpd inquiry failed with %x\n",
|
||||
ALUA_DH_NAME, rq->errors);
|
||||
h->senselen = rq->sense_len;
|
||||
err = SCSI_DH_IO;
|
||||
}
|
||||
blk_put_request(rq);
|
||||
done:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* submit_rtpg - Issue a REPORT TARGET GROUP STATES command
|
||||
* @sdev: sdev the command should be sent to
|
||||
*/
|
||||
static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
|
||||
{
|
||||
struct request *rq;
|
||||
int err = SCSI_DH_RES_TEMP_UNAVAIL;
|
||||
|
||||
rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
|
||||
if (!rq)
|
||||
goto done;
|
||||
|
||||
/* Prepare the command. */
|
||||
rq->cmd[0] = MAINTENANCE_IN;
|
||||
rq->cmd[1] = MI_REPORT_TARGET_PGS;
|
||||
rq->cmd[6] = (h->bufflen >> 24) & 0xff;
|
||||
rq->cmd[7] = (h->bufflen >> 16) & 0xff;
|
||||
rq->cmd[8] = (h->bufflen >> 8) & 0xff;
|
||||
rq->cmd[9] = h->bufflen & 0xff;
|
||||
rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN);
|
||||
|
||||
rq->sense = h->sense;
|
||||
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
|
||||
rq->sense_len = h->senselen = 0;
|
||||
|
||||
err = blk_execute_rq(rq->q, NULL, rq, 1);
|
||||
if (err == -EIO) {
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: rtpg failed with %x\n",
|
||||
ALUA_DH_NAME, rq->errors);
|
||||
h->senselen = rq->sense_len;
|
||||
err = SCSI_DH_IO;
|
||||
}
|
||||
blk_put_request(rq);
|
||||
done:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* submit_stpg - Issue a SET TARGET GROUP STATES command
|
||||
* @sdev: sdev the command should be sent to
|
||||
*
|
||||
* Currently we're only setting the current target port group state
|
||||
* to 'active/optimized' and let the array firmware figure out
|
||||
* the states of the remaining groups.
|
||||
*/
|
||||
static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
|
||||
{
|
||||
struct request *rq;
|
||||
int err = SCSI_DH_RES_TEMP_UNAVAIL;
|
||||
int stpg_len = 8;
|
||||
|
||||
/* Prepare the data buffer */
|
||||
memset(h->buff, 0, stpg_len);
|
||||
h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f;
|
||||
h->buff[6] = (h->group_id >> 8) & 0x0f;
|
||||
h->buff[7] = h->group_id & 0x0f;
|
||||
|
||||
rq = get_alua_req(sdev, h->buff, stpg_len, WRITE);
|
||||
if (!rq)
|
||||
goto done;
|
||||
|
||||
/* Prepare the command. */
|
||||
rq->cmd[0] = MAINTENANCE_OUT;
|
||||
rq->cmd[1] = MO_SET_TARGET_PGS;
|
||||
rq->cmd[6] = (stpg_len >> 24) & 0xff;
|
||||
rq->cmd[7] = (stpg_len >> 16) & 0xff;
|
||||
rq->cmd[8] = (stpg_len >> 8) & 0xff;
|
||||
rq->cmd[9] = stpg_len & 0xff;
|
||||
rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT);
|
||||
|
||||
rq->sense = h->sense;
|
||||
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
|
||||
rq->sense_len = h->senselen = 0;
|
||||
|
||||
err = blk_execute_rq(rq->q, NULL, rq, 1);
|
||||
if (err == -EIO) {
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: stpg failed with %x\n",
|
||||
ALUA_DH_NAME, rq->errors);
|
||||
h->senselen = rq->sense_len;
|
||||
err = SCSI_DH_IO;
|
||||
}
|
||||
blk_put_request(rq);
|
||||
done:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* alua_std_inquiry - Evaluate standard INQUIRY command
|
||||
* @sdev: device to be checked
|
||||
*
|
||||
* Just extract the TPGS setting to find out if ALUA
|
||||
* is supported.
|
||||
*/
|
||||
static int alua_std_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = submit_std_inquiry(sdev, h);
|
||||
|
||||
if (err != SCSI_DH_OK)
|
||||
return err;
|
||||
|
||||
/* Check TPGS setting */
|
||||
h->tpgs = (h->inq[5] >> 4) & 0x3;
|
||||
switch (h->tpgs) {
|
||||
case TPGS_MODE_EXPLICIT|TPGS_MODE_IMPLICIT:
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: supports implicit and explicit TPGS\n",
|
||||
ALUA_DH_NAME);
|
||||
break;
|
||||
case TPGS_MODE_EXPLICIT:
|
||||
sdev_printk(KERN_INFO, sdev, "%s: supports explicit TPGS\n",
|
||||
ALUA_DH_NAME);
|
||||
break;
|
||||
case TPGS_MODE_IMPLICIT:
|
||||
sdev_printk(KERN_INFO, sdev, "%s: supports implicit TPGS\n",
|
||||
ALUA_DH_NAME);
|
||||
break;
|
||||
default:
|
||||
h->tpgs = TPGS_MODE_NONE;
|
||||
sdev_printk(KERN_INFO, sdev, "%s: not supported\n",
|
||||
ALUA_DH_NAME);
|
||||
err = SCSI_DH_DEV_UNSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* alua_vpd_inquiry - Evaluate INQUIRY vpd page 0x83
|
||||
* @sdev: device to be checked
|
||||
*
|
||||
* Extract the relative target port and the target port group
|
||||
* descriptor from the list of identificators.
|
||||
*/
|
||||
static int alua_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
|
||||
{
|
||||
int len;
|
||||
unsigned err;
|
||||
unsigned char *d;
|
||||
|
||||
retry:
|
||||
err = submit_vpd_inquiry(sdev, h);
|
||||
|
||||
if (err != SCSI_DH_OK)
|
||||
return err;
|
||||
|
||||
/* Check if vpd page exceeds initial buffer */
|
||||
len = (h->buff[2] << 8) + h->buff[3] + 4;
|
||||
if (len > h->bufflen) {
|
||||
/* Resubmit with the correct length */
|
||||
if (realloc_buffer(h, len)) {
|
||||
sdev_printk(KERN_WARNING, sdev,
|
||||
"%s: kmalloc buffer failed\n",
|
||||
ALUA_DH_NAME);
|
||||
/* Temporary failure, bypass */
|
||||
return SCSI_DH_DEV_TEMP_BUSY;
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now look for the correct descriptor.
|
||||
*/
|
||||
d = h->buff + 4;
|
||||
while (d < h->buff + len) {
|
||||
switch (d[1] & 0xf) {
|
||||
case 0x4:
|
||||
/* Relative target port */
|
||||
h->rel_port = (d[6] << 8) + d[7];
|
||||
break;
|
||||
case 0x5:
|
||||
/* Target port group */
|
||||
h->group_id = (d[6] << 8) + d[7];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
d += d[3] + 4;
|
||||
}
|
||||
|
||||
if (h->group_id == -1) {
|
||||
/*
|
||||
* Internal error; TPGS supported but required
|
||||
* VPD identification descriptors not present.
|
||||
* Disable ALUA support
|
||||
*/
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: No target port descriptors found\n",
|
||||
ALUA_DH_NAME);
|
||||
h->state = TPGS_STATE_OPTIMIZED;
|
||||
h->tpgs = TPGS_MODE_NONE;
|
||||
err = SCSI_DH_DEV_UNSUPP;
|
||||
} else {
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: port group %02x rel port %02x\n",
|
||||
ALUA_DH_NAME, h->group_id, h->rel_port);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static char print_alua_state(int state)
|
||||
{
|
||||
switch (state) {
|
||||
case TPGS_STATE_OPTIMIZED:
|
||||
return 'A';
|
||||
case TPGS_STATE_NONOPTIMIZED:
|
||||
return 'N';
|
||||
case TPGS_STATE_STANDBY:
|
||||
return 'S';
|
||||
case TPGS_STATE_UNAVAILABLE:
|
||||
return 'U';
|
||||
case TPGS_STATE_OFFLINE:
|
||||
return 'O';
|
||||
case TPGS_STATE_TRANSITIONING:
|
||||
return 'T';
|
||||
default:
|
||||
return 'X';
|
||||
}
|
||||
}
|
||||
|
||||
static int alua_check_sense(struct scsi_device *sdev,
|
||||
struct scsi_sense_hdr *sense_hdr)
|
||||
{
|
||||
switch (sense_hdr->sense_key) {
|
||||
case NOT_READY:
|
||||
if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a)
|
||||
/*
|
||||
* LUN Not Accessible - ALUA state transition
|
||||
*/
|
||||
return NEEDS_RETRY;
|
||||
if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0b)
|
||||
/*
|
||||
* LUN Not Accessible -- Target port in standby state
|
||||
*/
|
||||
return SUCCESS;
|
||||
if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0c)
|
||||
/*
|
||||
* LUN Not Accessible -- Target port in unavailable state
|
||||
*/
|
||||
return SUCCESS;
|
||||
if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x12)
|
||||
/*
|
||||
* LUN Not Ready -- Offline
|
||||
*/
|
||||
return SUCCESS;
|
||||
break;
|
||||
case UNIT_ATTENTION:
|
||||
if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
|
||||
/*
|
||||
* Power On, Reset, or Bus Device Reset, just retry.
|
||||
*/
|
||||
return NEEDS_RETRY;
|
||||
if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) {
|
||||
/*
|
||||
* ALUA state changed
|
||||
*/
|
||||
return NEEDS_RETRY;
|
||||
}
|
||||
if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) {
|
||||
/*
|
||||
* Implicit ALUA state transition failed
|
||||
*/
|
||||
return NEEDS_RETRY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return SCSI_RETURN_NOT_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* alua_stpg - Evaluate SET TARGET GROUP STATES
|
||||
* @sdev: the device to be evaluated
|
||||
* @state: the new target group state
|
||||
*
|
||||
* Send a SET TARGET GROUP STATES command to the device.
|
||||
* We only have to test here if we should resubmit the command;
|
||||
* any other error is assumed as a failure.
|
||||
*/
|
||||
static int alua_stpg(struct scsi_device *sdev, int state,
|
||||
struct alua_dh_data *h)
|
||||
{
|
||||
struct scsi_sense_hdr sense_hdr;
|
||||
unsigned err;
|
||||
int retry = ALUA_FAILOVER_RETRIES;
|
||||
|
||||
retry:
|
||||
err = submit_stpg(sdev, h);
|
||||
if (err == SCSI_DH_IO && h->senselen > 0) {
|
||||
err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
|
||||
&sense_hdr);
|
||||
if (!err)
|
||||
return SCSI_DH_IO;
|
||||
err = alua_check_sense(sdev, &sense_hdr);
|
||||
if (retry > 0 && err == NEEDS_RETRY) {
|
||||
retry--;
|
||||
goto retry;
|
||||
}
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: stpg sense code: %02x/%02x/%02x\n",
|
||||
ALUA_DH_NAME, sense_hdr.sense_key,
|
||||
sense_hdr.asc, sense_hdr.ascq);
|
||||
err = SCSI_DH_IO;
|
||||
}
|
||||
if (err == SCSI_DH_OK) {
|
||||
h->state = state;
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: port group %02x switched to state %c\n",
|
||||
ALUA_DH_NAME, h->group_id,
|
||||
print_alua_state(h->state) );
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* alua_rtpg - Evaluate REPORT TARGET GROUP STATES
|
||||
* @sdev: the device to be evaluated.
|
||||
*
|
||||
* Evaluate the Target Port Group State.
|
||||
* Returns SCSI_DH_DEV_OFFLINED if the path is
|
||||
* found to be unuseable.
|
||||
*/
|
||||
static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
|
||||
{
|
||||
struct scsi_sense_hdr sense_hdr;
|
||||
int len, k, off, valid_states = 0;
|
||||
char *ucp;
|
||||
unsigned err;
|
||||
|
||||
retry:
|
||||
err = submit_rtpg(sdev, h);
|
||||
|
||||
if (err == SCSI_DH_IO && h->senselen > 0) {
|
||||
err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
|
||||
&sense_hdr);
|
||||
if (!err)
|
||||
return SCSI_DH_IO;
|
||||
|
||||
err = alua_check_sense(sdev, &sense_hdr);
|
||||
if (err == NEEDS_RETRY)
|
||||
goto retry;
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: rtpg sense code %02x/%02x/%02x\n",
|
||||
ALUA_DH_NAME, sense_hdr.sense_key,
|
||||
sense_hdr.asc, sense_hdr.ascq);
|
||||
err = SCSI_DH_IO;
|
||||
}
|
||||
if (err != SCSI_DH_OK)
|
||||
return err;
|
||||
|
||||
len = (h->buff[0] << 24) + (h->buff[1] << 16) +
|
||||
(h->buff[2] << 8) + h->buff[3] + 4;
|
||||
|
||||
if (len > h->bufflen) {
|
||||
/* Resubmit with the correct length */
|
||||
if (realloc_buffer(h, len)) {
|
||||
sdev_printk(KERN_WARNING, sdev,
|
||||
"%s: kmalloc buffer failed\n",__func__);
|
||||
/* Temporary failure, bypass */
|
||||
return SCSI_DH_DEV_TEMP_BUSY;
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
for (k = 4, ucp = h->buff + 4; k < len; k += off, ucp += off) {
|
||||
if (h->group_id == (ucp[2] << 8) + ucp[3]) {
|
||||
h->state = ucp[0] & 0x0f;
|
||||
valid_states = ucp[1];
|
||||
}
|
||||
off = 8 + (ucp[7] * 4);
|
||||
}
|
||||
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: port group %02x state %c supports %c%c%c%c%c%c\n",
|
||||
ALUA_DH_NAME, h->group_id, print_alua_state(h->state),
|
||||
valid_states&TPGS_SUPPORT_TRANSITION?'T':'t',
|
||||
valid_states&TPGS_SUPPORT_OFFLINE?'O':'o',
|
||||
valid_states&TPGS_SUPPORT_UNAVAILABLE?'U':'u',
|
||||
valid_states&TPGS_SUPPORT_STANDBY?'S':'s',
|
||||
valid_states&TPGS_SUPPORT_NONOPTIMIZED?'N':'n',
|
||||
valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a');
|
||||
|
||||
if (h->tpgs & TPGS_MODE_EXPLICIT) {
|
||||
switch (h->state) {
|
||||
case TPGS_STATE_TRANSITIONING:
|
||||
/* State transition, retry */
|
||||
goto retry;
|
||||
break;
|
||||
case TPGS_STATE_OFFLINE:
|
||||
/* Path is offline, fail */
|
||||
err = SCSI_DH_DEV_OFFLINED;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Only Implicit ALUA support */
|
||||
if (h->state == TPGS_STATE_OPTIMIZED ||
|
||||
h->state == TPGS_STATE_NONOPTIMIZED ||
|
||||
h->state == TPGS_STATE_STANDBY)
|
||||
/* Useable path if active */
|
||||
err = SCSI_DH_OK;
|
||||
else
|
||||
/* Path unuseable for unavailable/offline */
|
||||
err = SCSI_DH_DEV_OFFLINED;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* alua_initialize - Initialize ALUA state
|
||||
* @sdev: the device to be initialized
|
||||
*
|
||||
* For the prep_fn to work correctly we have
|
||||
* to initialize the ALUA state for the device.
|
||||
*/
|
||||
static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = alua_std_inquiry(sdev, h);
|
||||
if (err != SCSI_DH_OK)
|
||||
goto out;
|
||||
|
||||
err = alua_vpd_inquiry(sdev, h);
|
||||
if (err != SCSI_DH_OK)
|
||||
goto out;
|
||||
|
||||
err = alua_rtpg(sdev, h);
|
||||
if (err != SCSI_DH_OK)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* alua_activate - activate a path
|
||||
* @sdev: device on the path to be activated
|
||||
*
|
||||
* We're currently switching the port group to be activated only and
|
||||
* let the array figure out the rest.
|
||||
* There may be other arrays which require us to switch all port groups
|
||||
* based on a certain policy. But until we actually encounter them it
|
||||
* should be okay.
|
||||
*/
|
||||
static int alua_activate(struct scsi_device *sdev)
|
||||
{
|
||||
struct alua_dh_data *h = get_alua_data(sdev);
|
||||
int err = SCSI_DH_OK;
|
||||
|
||||
if (h->group_id != -1) {
|
||||
err = alua_rtpg(sdev, h);
|
||||
if (err != SCSI_DH_OK)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (h->tpgs == TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED)
|
||||
err = alua_stpg(sdev, TPGS_STATE_OPTIMIZED, h);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* alua_prep_fn - request callback
|
||||
*
|
||||
* Fail I/O to all paths not in state
|
||||
* active/optimized or active/non-optimized.
|
||||
*/
|
||||
static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
|
||||
{
|
||||
struct alua_dh_data *h = get_alua_data(sdev);
|
||||
int ret = BLKPREP_OK;
|
||||
|
||||
if (h->state != TPGS_STATE_OPTIMIZED &&
|
||||
h->state != TPGS_STATE_NONOPTIMIZED) {
|
||||
ret = BLKPREP_KILL;
|
||||
req->cmd_flags |= REQ_QUIET;
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
const struct scsi_dh_devlist alua_dev_list[] = {
|
||||
{"HP", "MSA VOLUME" },
|
||||
{"HP", "HSV101" },
|
||||
{"HP", "HSV111" },
|
||||
{"HP", "HSV200" },
|
||||
{"HP", "HSV210" },
|
||||
{"HP", "HSV300" },
|
||||
{"IBM", "2107900" },
|
||||
{"IBM", "2145" },
|
||||
{"Pillar", "Axiom" },
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static int alua_bus_attach(struct scsi_device *sdev);
|
||||
static void alua_bus_detach(struct scsi_device *sdev);
|
||||
|
||||
static struct scsi_device_handler alua_dh = {
|
||||
.name = ALUA_DH_NAME,
|
||||
.module = THIS_MODULE,
|
||||
.devlist = alua_dev_list,
|
||||
.attach = alua_bus_attach,
|
||||
.detach = alua_bus_detach,
|
||||
.prep_fn = alua_prep_fn,
|
||||
.check_sense = alua_check_sense,
|
||||
.activate = alua_activate,
|
||||
};
|
||||
|
||||
/*
|
||||
* alua_bus_attach - Attach device handler
|
||||
* @sdev: device to be attached to
|
||||
*/
|
||||
static int alua_bus_attach(struct scsi_device *sdev)
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data;
|
||||
struct alua_dh_data *h;
|
||||
unsigned long flags;
|
||||
int err = SCSI_DH_OK;
|
||||
|
||||
scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
|
||||
+ sizeof(*h) , GFP_KERNEL);
|
||||
if (!scsi_dh_data) {
|
||||
sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
|
||||
ALUA_DH_NAME);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
scsi_dh_data->scsi_dh = &alua_dh;
|
||||
h = (struct alua_dh_data *) scsi_dh_data->buf;
|
||||
h->tpgs = TPGS_MODE_UNINITIALIZED;
|
||||
h->state = TPGS_STATE_OPTIMIZED;
|
||||
h->group_id = -1;
|
||||
h->rel_port = -1;
|
||||
h->buff = h->inq;
|
||||
h->bufflen = ALUA_INQUIRY_SIZE;
|
||||
|
||||
err = alua_initialize(sdev, h);
|
||||
if (err != SCSI_DH_OK)
|
||||
goto failed;
|
||||
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
goto failed;
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
sdev->scsi_dh_data = scsi_dh_data;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
kfree(scsi_dh_data);
|
||||
sdev_printk(KERN_ERR, sdev, "%s: not attached\n", ALUA_DH_NAME);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* alua_bus_detach - Detach device handler
|
||||
* @sdev: device to be detached from
|
||||
*/
|
||||
static void alua_bus_detach(struct scsi_device *sdev)
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data;
|
||||
struct alua_dh_data *h;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
scsi_dh_data = sdev->scsi_dh_data;
|
||||
sdev->scsi_dh_data = NULL;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
|
||||
h = (struct alua_dh_data *) scsi_dh_data->buf;
|
||||
if (h->buff && h->inq != h->buff)
|
||||
kfree(h->buff);
|
||||
kfree(scsi_dh_data);
|
||||
module_put(THIS_MODULE);
|
||||
sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", ALUA_DH_NAME);
|
||||
}
|
||||
|
||||
static int __init alua_init(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = scsi_register_device_handler(&alua_dh);
|
||||
if (r != 0)
|
||||
printk(KERN_ERR "%s: Failed to register scsi device handler",
|
||||
ALUA_DH_NAME);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void __exit alua_exit(void)
|
||||
{
|
||||
scsi_unregister_device_handler(&alua_dh);
|
||||
}
|
||||
|
||||
module_init(alua_init);
|
||||
module_exit(alua_exit);
|
||||
|
||||
MODULE_DESCRIPTION("DM Multipath ALUA support");
|
||||
MODULE_AUTHOR("Hannes Reinecke <hare@suse.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(ALUA_DH_VER);
|
@ -25,28 +25,31 @@
|
||||
#include <scsi/scsi_dh.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
|
||||
#define CLARIION_NAME "emc_clariion"
|
||||
#define CLARIION_NAME "emc"
|
||||
|
||||
#define CLARIION_TRESPASS_PAGE 0x22
|
||||
#define CLARIION_BUFFER_SIZE 0x80
|
||||
#define CLARIION_BUFFER_SIZE 0xFC
|
||||
#define CLARIION_TIMEOUT (60 * HZ)
|
||||
#define CLARIION_RETRIES 3
|
||||
#define CLARIION_UNBOUND_LU -1
|
||||
#define CLARIION_SP_A 0
|
||||
#define CLARIION_SP_B 1
|
||||
|
||||
/* Flags */
|
||||
#define CLARIION_SHORT_TRESPASS 1
|
||||
#define CLARIION_HONOR_RESERVATIONS 2
|
||||
|
||||
/* LUN states */
|
||||
#define CLARIION_LUN_UNINITIALIZED -1
|
||||
#define CLARIION_LUN_UNBOUND 0
|
||||
#define CLARIION_LUN_BOUND 1
|
||||
#define CLARIION_LUN_OWNED 2
|
||||
|
||||
static unsigned char long_trespass[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
CLARIION_TRESPASS_PAGE, /* Page code */
|
||||
0x09, /* Page length - 2 */
|
||||
0x81, /* Trespass code + Honor reservation bit */
|
||||
0xff, 0xff, /* Trespass target */
|
||||
0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */
|
||||
};
|
||||
|
||||
static unsigned char long_trespass_hr[] = {
|
||||
0, 0, 0, 0,
|
||||
CLARIION_TRESPASS_PAGE, /* Page code */
|
||||
0x09, /* Page length - 2 */
|
||||
0x01, /* Trespass code + Honor reservation bit */
|
||||
0x01, /* Trespass code */
|
||||
0xff, 0xff, /* Trespass target */
|
||||
0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */
|
||||
};
|
||||
@ -55,39 +58,56 @@ static unsigned char short_trespass[] = {
|
||||
0, 0, 0, 0,
|
||||
CLARIION_TRESPASS_PAGE, /* Page code */
|
||||
0x02, /* Page length - 2 */
|
||||
0x81, /* Trespass code + Honor reservation bit */
|
||||
0x01, /* Trespass code */
|
||||
0xff, /* Trespass target */
|
||||
};
|
||||
|
||||
static unsigned char short_trespass_hr[] = {
|
||||
0, 0, 0, 0,
|
||||
CLARIION_TRESPASS_PAGE, /* Page code */
|
||||
0x02, /* Page length - 2 */
|
||||
0x01, /* Trespass code + Honor reservation bit */
|
||||
0xff, /* Trespass target */
|
||||
static const char * lun_state[] =
|
||||
{
|
||||
"not bound",
|
||||
"bound",
|
||||
"owned",
|
||||
};
|
||||
|
||||
struct clariion_dh_data {
|
||||
/*
|
||||
* Flags:
|
||||
* CLARIION_SHORT_TRESPASS
|
||||
* Use short trespass command (FC-series) or the long version
|
||||
* (default for AX/CX CLARiiON arrays).
|
||||
*/
|
||||
unsigned short_trespass;
|
||||
/*
|
||||
*
|
||||
* CLARIION_HONOR_RESERVATIONS
|
||||
* Whether or not (default) to honor SCSI reservations when
|
||||
* initiating a switch-over.
|
||||
*/
|
||||
unsigned hr;
|
||||
/* I/O buffer for both MODE_SELECT and INQUIRY commands. */
|
||||
unsigned flags;
|
||||
/*
|
||||
* I/O buffer for both MODE_SELECT and INQUIRY commands.
|
||||
*/
|
||||
char buffer[CLARIION_BUFFER_SIZE];
|
||||
/*
|
||||
* SCSI sense buffer for commands -- assumes serial issuance
|
||||
* and completion sequence of all commands for same multipath.
|
||||
*/
|
||||
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
|
||||
/* which SP (A=0,B=1,UNBOUND=-1) is dflt SP for path's mapped dev */
|
||||
unsigned int senselen;
|
||||
/*
|
||||
* LUN state
|
||||
*/
|
||||
int lun_state;
|
||||
/*
|
||||
* SP Port number
|
||||
*/
|
||||
int port;
|
||||
/*
|
||||
* which SP (A=0,B=1,UNBOUND=-1) is the default SP for this
|
||||
* path's mapped LUN
|
||||
*/
|
||||
int default_sp;
|
||||
/* which SP (A=0,B=1,UNBOUND=-1) is active for path's mapped dev */
|
||||
/*
|
||||
* which SP (A=0,B=1,UNBOUND=-1) is the active SP for this
|
||||
* path's mapped LUN
|
||||
*/
|
||||
int current_sp;
|
||||
};
|
||||
|
||||
@ -102,19 +122,16 @@ static inline struct clariion_dh_data
|
||||
/*
|
||||
* Parse MODE_SELECT cmd reply.
|
||||
*/
|
||||
static int trespass_endio(struct scsi_device *sdev, int result)
|
||||
static int trespass_endio(struct scsi_device *sdev, char *sense)
|
||||
{
|
||||
int err = SCSI_DH_OK;
|
||||
int err = SCSI_DH_IO;
|
||||
struct scsi_sense_hdr sshdr;
|
||||
struct clariion_dh_data *csdev = get_clariion_data(sdev);
|
||||
char *sense = csdev->sense;
|
||||
|
||||
if (status_byte(result) == CHECK_CONDITION &&
|
||||
scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) {
|
||||
sdev_printk(KERN_ERR, sdev, "Found valid sense data 0x%2x, "
|
||||
if (!scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) {
|
||||
sdev_printk(KERN_ERR, sdev, "%s: Found valid sense data 0x%2x, "
|
||||
"0x%2x, 0x%2x while sending CLARiiON trespass "
|
||||
"command.\n", sshdr.sense_key, sshdr.asc,
|
||||
sshdr.ascq);
|
||||
"command.\n", CLARIION_NAME, sshdr.sense_key,
|
||||
sshdr.asc, sshdr.ascq);
|
||||
|
||||
if ((sshdr.sense_key == 0x05) && (sshdr.asc == 0x04) &&
|
||||
(sshdr.ascq == 0x00)) {
|
||||
@ -122,9 +139,9 @@ static int trespass_endio(struct scsi_device *sdev, int result)
|
||||
* Array based copy in progress -- do not send
|
||||
* mode_select or copy will be aborted mid-stream.
|
||||
*/
|
||||
sdev_printk(KERN_INFO, sdev, "Array Based Copy in "
|
||||
sdev_printk(KERN_INFO, sdev, "%s: Array Based Copy in "
|
||||
"progress while sending CLARiiON trespass "
|
||||
"command.\n");
|
||||
"command.\n", CLARIION_NAME);
|
||||
err = SCSI_DH_DEV_TEMP_BUSY;
|
||||
} else if ((sshdr.sense_key == 0x02) && (sshdr.asc == 0x04) &&
|
||||
(sshdr.ascq == 0x03)) {
|
||||
@ -132,160 +149,153 @@ static int trespass_endio(struct scsi_device *sdev, int result)
|
||||
* LUN Not Ready - Manual Intervention Required
|
||||
* indicates in-progress ucode upgrade (NDU).
|
||||
*/
|
||||
sdev_printk(KERN_INFO, sdev, "Detected in-progress "
|
||||
sdev_printk(KERN_INFO, sdev, "%s: Detected in-progress "
|
||||
"ucode upgrade NDU operation while sending "
|
||||
"CLARiiON trespass command.\n");
|
||||
"CLARiiON trespass command.\n", CLARIION_NAME);
|
||||
err = SCSI_DH_DEV_TEMP_BUSY;
|
||||
} else
|
||||
err = SCSI_DH_DEV_FAILED;
|
||||
} else if (result) {
|
||||
sdev_printk(KERN_ERR, sdev, "Error 0x%x while sending "
|
||||
"CLARiiON trespass command.\n", result);
|
||||
err = SCSI_DH_IO;
|
||||
} else {
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: failed to send MODE SELECT, no sense available\n",
|
||||
CLARIION_NAME);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int parse_sp_info_reply(struct scsi_device *sdev, int result,
|
||||
int *default_sp, int *current_sp, int *new_current_sp)
|
||||
static int parse_sp_info_reply(struct scsi_device *sdev,
|
||||
struct clariion_dh_data *csdev)
|
||||
{
|
||||
int err = SCSI_DH_OK;
|
||||
struct clariion_dh_data *csdev = get_clariion_data(sdev);
|
||||
|
||||
if (result == 0) {
|
||||
/* check for in-progress ucode upgrade (NDU) */
|
||||
if (csdev->buffer[48] != 0) {
|
||||
sdev_printk(KERN_NOTICE, sdev, "Detected in-progress "
|
||||
"ucode upgrade NDU operation while finding "
|
||||
"current active SP.");
|
||||
err = SCSI_DH_DEV_TEMP_BUSY;
|
||||
} else {
|
||||
*default_sp = csdev->buffer[5];
|
||||
|
||||
if (csdev->buffer[4] == 2)
|
||||
/* SP for path is current */
|
||||
*current_sp = csdev->buffer[8];
|
||||
else {
|
||||
if (csdev->buffer[4] == 1)
|
||||
/* SP for this path is NOT current */
|
||||
if (csdev->buffer[8] == 0)
|
||||
*current_sp = 1;
|
||||
else
|
||||
*current_sp = 0;
|
||||
else
|
||||
/* unbound LU or LUNZ */
|
||||
*current_sp = CLARIION_UNBOUND_LU;
|
||||
}
|
||||
*new_current_sp = csdev->buffer[8];
|
||||
}
|
||||
} else {
|
||||
struct scsi_sense_hdr sshdr;
|
||||
|
||||
err = SCSI_DH_IO;
|
||||
|
||||
if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE,
|
||||
&sshdr))
|
||||
sdev_printk(KERN_ERR, sdev, "Found valid sense data "
|
||||
"0x%2x, 0x%2x, 0x%2x while finding current "
|
||||
"active SP.", sshdr.sense_key, sshdr.asc,
|
||||
sshdr.ascq);
|
||||
else
|
||||
sdev_printk(KERN_ERR, sdev, "Error 0x%x finding "
|
||||
"current active SP.", result);
|
||||
/* check for in-progress ucode upgrade (NDU) */
|
||||
if (csdev->buffer[48] != 0) {
|
||||
sdev_printk(KERN_NOTICE, sdev, "%s: Detected in-progress "
|
||||
"ucode upgrade NDU operation while finding "
|
||||
"current active SP.", CLARIION_NAME);
|
||||
err = SCSI_DH_DEV_TEMP_BUSY;
|
||||
goto out;
|
||||
}
|
||||
if (csdev->buffer[4] < 0 || csdev->buffer[4] > 2) {
|
||||
/* Invalid buffer format */
|
||||
sdev_printk(KERN_NOTICE, sdev,
|
||||
"%s: invalid VPD page 0xC0 format\n",
|
||||
CLARIION_NAME);
|
||||
err = SCSI_DH_NOSYS;
|
||||
goto out;
|
||||
}
|
||||
switch (csdev->buffer[28] & 0x0f) {
|
||||
case 6:
|
||||
sdev_printk(KERN_NOTICE, sdev,
|
||||
"%s: ALUA failover mode detected\n",
|
||||
CLARIION_NAME);
|
||||
break;
|
||||
case 4:
|
||||
/* Linux failover */
|
||||
break;
|
||||
default:
|
||||
sdev_printk(KERN_WARNING, sdev,
|
||||
"%s: Invalid failover mode %d\n",
|
||||
CLARIION_NAME, csdev->buffer[28] & 0x0f);
|
||||
err = SCSI_DH_NOSYS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
csdev->default_sp = csdev->buffer[5];
|
||||
csdev->lun_state = csdev->buffer[4];
|
||||
csdev->current_sp = csdev->buffer[8];
|
||||
csdev->port = csdev->buffer[7];
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int sp_info_endio(struct scsi_device *sdev, int result,
|
||||
int mode_select_sent, int *done)
|
||||
#define emc_default_str "FC (Legacy)"
|
||||
|
||||
static char * parse_sp_model(struct scsi_device *sdev, unsigned char *buffer)
|
||||
{
|
||||
struct clariion_dh_data *csdev = get_clariion_data(sdev);
|
||||
int err_flags, default_sp, current_sp, new_current_sp;
|
||||
unsigned char len = buffer[4] + 5;
|
||||
char *sp_model = NULL;
|
||||
unsigned char sp_len, serial_len;
|
||||
|
||||
err_flags = parse_sp_info_reply(sdev, result, &default_sp,
|
||||
¤t_sp, &new_current_sp);
|
||||
|
||||
if (err_flags != SCSI_DH_OK)
|
||||
goto done;
|
||||
|
||||
if (mode_select_sent) {
|
||||
csdev->default_sp = default_sp;
|
||||
csdev->current_sp = current_sp;
|
||||
} else {
|
||||
/*
|
||||
* Issue the actual module_selec request IFF either
|
||||
* (1) we do not know the identity of the current SP OR
|
||||
* (2) what we think we know is actually correct.
|
||||
*/
|
||||
if ((current_sp != CLARIION_UNBOUND_LU) &&
|
||||
(new_current_sp != current_sp)) {
|
||||
|
||||
csdev->default_sp = default_sp;
|
||||
csdev->current_sp = current_sp;
|
||||
|
||||
sdev_printk(KERN_INFO, sdev, "Ignoring path group "
|
||||
"switch-over command for CLARiiON SP%s since "
|
||||
" mapped device is already initialized.",
|
||||
current_sp ? "B" : "A");
|
||||
if (done)
|
||||
*done = 1; /* as good as doing it */
|
||||
if (len < 160) {
|
||||
sdev_printk(KERN_WARNING, sdev,
|
||||
"%s: Invalid information section length %d\n",
|
||||
CLARIION_NAME, len);
|
||||
/* Check for old FC arrays */
|
||||
if (!strncmp(buffer + 8, "DGC", 3)) {
|
||||
/* Old FC array, not supporting extended information */
|
||||
sp_model = emc_default_str;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
done:
|
||||
return err_flags;
|
||||
|
||||
/*
|
||||
* Parse extended information for SP model number
|
||||
*/
|
||||
serial_len = buffer[160];
|
||||
if (serial_len == 0 || serial_len + 161 > len) {
|
||||
sdev_printk(KERN_WARNING, sdev,
|
||||
"%s: Invalid array serial number length %d\n",
|
||||
CLARIION_NAME, serial_len);
|
||||
goto out;
|
||||
}
|
||||
sp_len = buffer[99];
|
||||
if (sp_len == 0 || serial_len + sp_len + 161 > len) {
|
||||
sdev_printk(KERN_WARNING, sdev,
|
||||
"%s: Invalid model number length %d\n",
|
||||
CLARIION_NAME, sp_len);
|
||||
goto out;
|
||||
}
|
||||
sp_model = &buffer[serial_len + 161];
|
||||
/* Strip whitespace at the end */
|
||||
while (sp_len > 1 && sp_model[sp_len - 1] == ' ')
|
||||
sp_len--;
|
||||
|
||||
sp_model[sp_len] = '\0';
|
||||
|
||||
out:
|
||||
return sp_model;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get block request for REQ_BLOCK_PC command issued to path. Currently
|
||||
* limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands.
|
||||
*
|
||||
* Uses data and sense buffers in hardware handler context structure and
|
||||
* assumes serial servicing of commands, both issuance and completion.
|
||||
*/
|
||||
static struct request *get_req(struct scsi_device *sdev, int cmd)
|
||||
* Get block request for REQ_BLOCK_PC command issued to path. Currently
|
||||
* limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands.
|
||||
*
|
||||
* Uses data and sense buffers in hardware handler context structure and
|
||||
* assumes serial servicing of commands, both issuance and completion.
|
||||
*/
|
||||
static struct request *get_req(struct scsi_device *sdev, int cmd,
|
||||
unsigned char *buffer)
|
||||
{
|
||||
struct clariion_dh_data *csdev = get_clariion_data(sdev);
|
||||
struct request *rq;
|
||||
unsigned char *page22;
|
||||
int len = 0;
|
||||
|
||||
rq = blk_get_request(sdev->request_queue,
|
||||
(cmd == MODE_SELECT) ? WRITE : READ, GFP_ATOMIC);
|
||||
(cmd == MODE_SELECT) ? WRITE : READ, GFP_NOIO);
|
||||
if (!rq) {
|
||||
sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(&rq->cmd, 0, BLK_MAX_CDB);
|
||||
memset(rq->cmd, 0, BLK_MAX_CDB);
|
||||
rq->cmd_len = COMMAND_SIZE(cmd);
|
||||
rq->cmd[0] = cmd;
|
||||
rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
|
||||
|
||||
switch (cmd) {
|
||||
case MODE_SELECT:
|
||||
if (csdev->short_trespass) {
|
||||
page22 = csdev->hr ? short_trespass_hr : short_trespass;
|
||||
len = sizeof(short_trespass);
|
||||
} else {
|
||||
page22 = csdev->hr ? long_trespass_hr : long_trespass;
|
||||
len = sizeof(long_trespass);
|
||||
}
|
||||
/*
|
||||
* Can't DMA from kernel BSS -- must copy selected trespass
|
||||
* command mode page contents to context buffer which is
|
||||
* allocated by kmalloc.
|
||||
*/
|
||||
BUG_ON((len > CLARIION_BUFFER_SIZE));
|
||||
memcpy(csdev->buffer, page22, len);
|
||||
len = sizeof(short_trespass);
|
||||
rq->cmd_flags |= REQ_RW;
|
||||
rq->cmd[1] = 0x10;
|
||||
break;
|
||||
case MODE_SELECT_10:
|
||||
len = sizeof(long_trespass);
|
||||
rq->cmd_flags |= REQ_RW;
|
||||
rq->cmd[1] = 0x10;
|
||||
break;
|
||||
case INQUIRY:
|
||||
rq->cmd[1] = 0x1;
|
||||
rq->cmd[2] = 0xC0;
|
||||
len = CLARIION_BUFFER_SIZE;
|
||||
memset(csdev->buffer, 0, CLARIION_BUFFER_SIZE);
|
||||
memset(buffer, 0, len);
|
||||
break;
|
||||
default:
|
||||
BUG_ON(1);
|
||||
@ -298,47 +308,94 @@ static struct request *get_req(struct scsi_device *sdev, int cmd)
|
||||
rq->timeout = CLARIION_TIMEOUT;
|
||||
rq->retries = CLARIION_RETRIES;
|
||||
|
||||
rq->sense = csdev->sense;
|
||||
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
|
||||
rq->sense_len = 0;
|
||||
|
||||
if (blk_rq_map_kern(sdev->request_queue, rq, csdev->buffer,
|
||||
len, GFP_ATOMIC)) {
|
||||
__blk_put_request(rq->q, rq);
|
||||
if (blk_rq_map_kern(rq->q, rq, buffer, len, GFP_NOIO)) {
|
||||
blk_put_request(rq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return rq;
|
||||
}
|
||||
|
||||
static int send_cmd(struct scsi_device *sdev, int cmd)
|
||||
static int send_inquiry_cmd(struct scsi_device *sdev, int page,
|
||||
struct clariion_dh_data *csdev)
|
||||
{
|
||||
struct request *rq = get_req(sdev, cmd);
|
||||
struct request *rq = get_req(sdev, INQUIRY, csdev->buffer);
|
||||
int err;
|
||||
|
||||
if (!rq)
|
||||
return SCSI_DH_RES_TEMP_UNAVAIL;
|
||||
|
||||
return blk_execute_rq(sdev->request_queue, NULL, rq, 1);
|
||||
rq->sense = csdev->sense;
|
||||
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
|
||||
rq->sense_len = csdev->senselen = 0;
|
||||
|
||||
rq->cmd[0] = INQUIRY;
|
||||
if (page != 0) {
|
||||
rq->cmd[1] = 1;
|
||||
rq->cmd[2] = page;
|
||||
}
|
||||
err = blk_execute_rq(sdev->request_queue, NULL, rq, 1);
|
||||
if (err == -EIO) {
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: failed to send %s INQUIRY: %x\n",
|
||||
CLARIION_NAME, page?"EVPD":"standard",
|
||||
rq->errors);
|
||||
csdev->senselen = rq->sense_len;
|
||||
err = SCSI_DH_IO;
|
||||
}
|
||||
|
||||
blk_put_request(rq);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int clariion_activate(struct scsi_device *sdev)
|
||||
static int send_trespass_cmd(struct scsi_device *sdev,
|
||||
struct clariion_dh_data *csdev)
|
||||
{
|
||||
int result, done = 0;
|
||||
struct request *rq;
|
||||
unsigned char *page22;
|
||||
int err, len, cmd;
|
||||
|
||||
result = send_cmd(sdev, INQUIRY);
|
||||
result = sp_info_endio(sdev, result, 0, &done);
|
||||
if (result || done)
|
||||
goto done;
|
||||
if (csdev->flags & CLARIION_SHORT_TRESPASS) {
|
||||
page22 = short_trespass;
|
||||
if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS))
|
||||
/* Set Honor Reservations bit */
|
||||
page22[6] |= 0x80;
|
||||
len = sizeof(short_trespass);
|
||||
cmd = MODE_SELECT;
|
||||
} else {
|
||||
page22 = long_trespass;
|
||||
if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS))
|
||||
/* Set Honor Reservations bit */
|
||||
page22[10] |= 0x80;
|
||||
len = sizeof(long_trespass);
|
||||
cmd = MODE_SELECT_10;
|
||||
}
|
||||
BUG_ON((len > CLARIION_BUFFER_SIZE));
|
||||
memcpy(csdev->buffer, page22, len);
|
||||
|
||||
result = send_cmd(sdev, MODE_SELECT);
|
||||
result = trespass_endio(sdev, result);
|
||||
if (result)
|
||||
goto done;
|
||||
rq = get_req(sdev, cmd, csdev->buffer);
|
||||
if (!rq)
|
||||
return SCSI_DH_RES_TEMP_UNAVAIL;
|
||||
|
||||
result = send_cmd(sdev, INQUIRY);
|
||||
result = sp_info_endio(sdev, result, 1, NULL);
|
||||
done:
|
||||
return result;
|
||||
rq->sense = csdev->sense;
|
||||
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
|
||||
rq->sense_len = csdev->senselen = 0;
|
||||
|
||||
err = blk_execute_rq(sdev->request_queue, NULL, rq, 1);
|
||||
if (err == -EIO) {
|
||||
if (rq->sense_len) {
|
||||
err = trespass_endio(sdev, csdev->sense);
|
||||
} else {
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: failed to send MODE SELECT: %x\n",
|
||||
CLARIION_NAME, rq->errors);
|
||||
}
|
||||
}
|
||||
|
||||
blk_put_request(rq);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int clariion_check_sense(struct scsi_device *sdev,
|
||||
@ -386,99 +443,215 @@ static int clariion_check_sense(struct scsi_device *sdev,
|
||||
break;
|
||||
}
|
||||
|
||||
/* success just means we do not care what scsi-ml does */
|
||||
return SUCCESS;
|
||||
return SCSI_RETURN_NOT_HANDLED;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
char *vendor;
|
||||
char *model;
|
||||
} clariion_dev_list[] = {
|
||||
static int clariion_prep_fn(struct scsi_device *sdev, struct request *req)
|
||||
{
|
||||
struct clariion_dh_data *h = get_clariion_data(sdev);
|
||||
int ret = BLKPREP_OK;
|
||||
|
||||
if (h->lun_state != CLARIION_LUN_OWNED) {
|
||||
ret = BLKPREP_KILL;
|
||||
req->cmd_flags |= REQ_QUIET;
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static int clariion_std_inquiry(struct scsi_device *sdev,
|
||||
struct clariion_dh_data *csdev)
|
||||
{
|
||||
int err;
|
||||
char *sp_model;
|
||||
|
||||
err = send_inquiry_cmd(sdev, 0, csdev);
|
||||
if (err != SCSI_DH_OK && csdev->senselen) {
|
||||
struct scsi_sense_hdr sshdr;
|
||||
|
||||
if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE,
|
||||
&sshdr)) {
|
||||
sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code "
|
||||
"%02x/%02x/%02x\n", CLARIION_NAME,
|
||||
sshdr.sense_key, sshdr.asc, sshdr.ascq);
|
||||
}
|
||||
err = SCSI_DH_IO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sp_model = parse_sp_model(sdev, csdev->buffer);
|
||||
if (!sp_model) {
|
||||
err = SCSI_DH_DEV_UNSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* FC Series arrays do not support long trespass
|
||||
*/
|
||||
if (!strlen(sp_model) || !strncmp(sp_model, "FC",2))
|
||||
csdev->flags |= CLARIION_SHORT_TRESPASS;
|
||||
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: detected Clariion %s, flags %x\n",
|
||||
CLARIION_NAME, sp_model, csdev->flags);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int clariion_send_inquiry(struct scsi_device *sdev,
|
||||
struct clariion_dh_data *csdev)
|
||||
{
|
||||
int err, retry = CLARIION_RETRIES;
|
||||
|
||||
retry:
|
||||
err = send_inquiry_cmd(sdev, 0xC0, csdev);
|
||||
if (err != SCSI_DH_OK && csdev->senselen) {
|
||||
struct scsi_sense_hdr sshdr;
|
||||
|
||||
err = scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE,
|
||||
&sshdr);
|
||||
if (!err)
|
||||
return SCSI_DH_IO;
|
||||
|
||||
err = clariion_check_sense(sdev, &sshdr);
|
||||
if (retry > 0 && err == NEEDS_RETRY) {
|
||||
retry--;
|
||||
goto retry;
|
||||
}
|
||||
sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code "
|
||||
"%02x/%02x/%02x\n", CLARIION_NAME,
|
||||
sshdr.sense_key, sshdr.asc, sshdr.ascq);
|
||||
err = SCSI_DH_IO;
|
||||
} else {
|
||||
err = parse_sp_info_reply(sdev, csdev);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int clariion_activate(struct scsi_device *sdev)
|
||||
{
|
||||
struct clariion_dh_data *csdev = get_clariion_data(sdev);
|
||||
int result;
|
||||
|
||||
result = clariion_send_inquiry(sdev, csdev);
|
||||
if (result != SCSI_DH_OK)
|
||||
goto done;
|
||||
|
||||
if (csdev->lun_state == CLARIION_LUN_OWNED)
|
||||
goto done;
|
||||
|
||||
result = send_trespass_cmd(sdev, csdev);
|
||||
if (result != SCSI_DH_OK)
|
||||
goto done;
|
||||
sdev_printk(KERN_INFO, sdev,"%s: %s trespass command sent\n",
|
||||
CLARIION_NAME,
|
||||
csdev->flags&CLARIION_SHORT_TRESPASS?"short":"long" );
|
||||
|
||||
/* Update status */
|
||||
result = clariion_send_inquiry(sdev, csdev);
|
||||
if (result != SCSI_DH_OK)
|
||||
goto done;
|
||||
|
||||
done:
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: at SP %c Port %d (%s, default SP %c)\n",
|
||||
CLARIION_NAME, csdev->current_sp + 'A',
|
||||
csdev->port, lun_state[csdev->lun_state],
|
||||
csdev->default_sp + 'A');
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const struct scsi_dh_devlist clariion_dev_list[] = {
|
||||
{"DGC", "RAID"},
|
||||
{"DGC", "DISK"},
|
||||
{"DGC", "VRAID"},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
static int clariion_bus_notify(struct notifier_block *, unsigned long, void *);
|
||||
static int clariion_bus_attach(struct scsi_device *sdev);
|
||||
static void clariion_bus_detach(struct scsi_device *sdev);
|
||||
|
||||
static struct scsi_device_handler clariion_dh = {
|
||||
.name = CLARIION_NAME,
|
||||
.module = THIS_MODULE,
|
||||
.nb.notifier_call = clariion_bus_notify,
|
||||
.devlist = clariion_dev_list,
|
||||
.attach = clariion_bus_attach,
|
||||
.detach = clariion_bus_detach,
|
||||
.check_sense = clariion_check_sense,
|
||||
.activate = clariion_activate,
|
||||
.prep_fn = clariion_prep_fn,
|
||||
};
|
||||
|
||||
/*
|
||||
* TODO: need some interface so we can set trespass values
|
||||
*/
|
||||
static int clariion_bus_notify(struct notifier_block *nb,
|
||||
unsigned long action, void *data)
|
||||
static int clariion_bus_attach(struct scsi_device *sdev)
|
||||
{
|
||||
struct device *dev = data;
|
||||
struct scsi_device *sdev;
|
||||
struct scsi_dh_data *scsi_dh_data;
|
||||
struct clariion_dh_data *h;
|
||||
int i, found = 0;
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
if (!scsi_is_sdev_device(dev))
|
||||
return 0;
|
||||
|
||||
sdev = to_scsi_device(dev);
|
||||
|
||||
if (action == BUS_NOTIFY_ADD_DEVICE) {
|
||||
for (i = 0; clariion_dev_list[i].vendor; i++) {
|
||||
if (!strncmp(sdev->vendor, clariion_dev_list[i].vendor,
|
||||
strlen(clariion_dev_list[i].vendor)) &&
|
||||
!strncmp(sdev->model, clariion_dev_list[i].model,
|
||||
strlen(clariion_dev_list[i].model))) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
goto out;
|
||||
|
||||
scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
|
||||
+ sizeof(*h) , GFP_KERNEL);
|
||||
if (!scsi_dh_data) {
|
||||
sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n",
|
||||
CLARIION_NAME);
|
||||
goto out;
|
||||
}
|
||||
|
||||
scsi_dh_data->scsi_dh = &clariion_dh;
|
||||
h = (struct clariion_dh_data *) scsi_dh_data->buf;
|
||||
h->default_sp = CLARIION_UNBOUND_LU;
|
||||
h->current_sp = CLARIION_UNBOUND_LU;
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
sdev->scsi_dh_data = scsi_dh_data;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
|
||||
sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", CLARIION_NAME);
|
||||
try_module_get(THIS_MODULE);
|
||||
|
||||
} else if (action == BUS_NOTIFY_DEL_DEVICE) {
|
||||
if (sdev->scsi_dh_data == NULL ||
|
||||
sdev->scsi_dh_data->scsi_dh != &clariion_dh)
|
||||
goto out;
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
scsi_dh_data = sdev->scsi_dh_data;
|
||||
sdev->scsi_dh_data = NULL;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
|
||||
sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n",
|
||||
scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
|
||||
+ sizeof(*h) , GFP_KERNEL);
|
||||
if (!scsi_dh_data) {
|
||||
sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
|
||||
CLARIION_NAME);
|
||||
|
||||
kfree(scsi_dh_data);
|
||||
module_put(THIS_MODULE);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
out:
|
||||
scsi_dh_data->scsi_dh = &clariion_dh;
|
||||
h = (struct clariion_dh_data *) scsi_dh_data->buf;
|
||||
h->lun_state = CLARIION_LUN_UNINITIALIZED;
|
||||
h->default_sp = CLARIION_UNBOUND_LU;
|
||||
h->current_sp = CLARIION_UNBOUND_LU;
|
||||
|
||||
err = clariion_std_inquiry(sdev, h);
|
||||
if (err != SCSI_DH_OK)
|
||||
goto failed;
|
||||
|
||||
err = clariion_send_inquiry(sdev, h);
|
||||
if (err != SCSI_DH_OK)
|
||||
goto failed;
|
||||
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
goto failed;
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
sdev->scsi_dh_data = scsi_dh_data;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: connected to SP %c Port %d (%s, default SP %c)\n",
|
||||
CLARIION_NAME, h->current_sp + 'A',
|
||||
h->port, lun_state[h->lun_state],
|
||||
h->default_sp + 'A');
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
kfree(scsi_dh_data);
|
||||
sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
|
||||
CLARIION_NAME);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void clariion_bus_detach(struct scsi_device *sdev)
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
scsi_dh_data = sdev->scsi_dh_data;
|
||||
sdev->scsi_dh_data = NULL;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
|
||||
sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n",
|
||||
CLARIION_NAME);
|
||||
|
||||
kfree(scsi_dh_data);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
static int __init clariion_init(void)
|
||||
@ -487,7 +660,8 @@ static int __init clariion_init(void)
|
||||
|
||||
r = scsi_register_device_handler(&clariion_dh);
|
||||
if (r != 0)
|
||||
printk(KERN_ERR "Failed to register scsi device handler.");
|
||||
printk(KERN_ERR "%s: Failed to register scsi device handler.",
|
||||
CLARIION_NAME);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
*
|
||||
* Copyright (C) 2006 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2006 Mike Christie
|
||||
* Copyright (C) 2008 Hannes Reinecke <hare@suse.de>
|
||||
*
|
||||
* 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
|
||||
@ -25,13 +26,18 @@
|
||||
#include <scsi/scsi_eh.h>
|
||||
#include <scsi/scsi_dh.h>
|
||||
|
||||
#define HP_SW_NAME "hp_sw"
|
||||
#define HP_SW_NAME "hp_sw"
|
||||
|
||||
#define HP_SW_TIMEOUT (60 * HZ)
|
||||
#define HP_SW_RETRIES 3
|
||||
#define HP_SW_TIMEOUT (60 * HZ)
|
||||
#define HP_SW_RETRIES 3
|
||||
|
||||
#define HP_SW_PATH_UNINITIALIZED -1
|
||||
#define HP_SW_PATH_ACTIVE 0
|
||||
#define HP_SW_PATH_PASSIVE 1
|
||||
|
||||
struct hp_sw_dh_data {
|
||||
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
|
||||
int path_state;
|
||||
int retries;
|
||||
};
|
||||
|
||||
@ -42,51 +48,161 @@ static inline struct hp_sw_dh_data *get_hp_sw_data(struct scsi_device *sdev)
|
||||
return ((struct hp_sw_dh_data *) scsi_dh_data->buf);
|
||||
}
|
||||
|
||||
static int hp_sw_done(struct scsi_device *sdev)
|
||||
/*
|
||||
* tur_done - Handle TEST UNIT READY return status
|
||||
* @sdev: sdev the command has been sent to
|
||||
* @errors: blk error code
|
||||
*
|
||||
* Returns SCSI_DH_DEV_OFFLINED if the sdev is on the passive path
|
||||
*/
|
||||
static int tur_done(struct scsi_device *sdev, unsigned char *sense)
|
||||
{
|
||||
struct scsi_sense_hdr sshdr;
|
||||
int ret;
|
||||
|
||||
ret = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
|
||||
if (!ret) {
|
||||
sdev_printk(KERN_WARNING, sdev,
|
||||
"%s: sending tur failed, no sense available\n",
|
||||
HP_SW_NAME);
|
||||
ret = SCSI_DH_IO;
|
||||
goto done;
|
||||
}
|
||||
switch (sshdr.sense_key) {
|
||||
case UNIT_ATTENTION:
|
||||
ret = SCSI_DH_IMM_RETRY;
|
||||
break;
|
||||
case NOT_READY:
|
||||
if ((sshdr.asc == 0x04) && (sshdr.ascq == 2)) {
|
||||
/*
|
||||
* LUN not ready - Initialization command required
|
||||
*
|
||||
* This is the passive path
|
||||
*/
|
||||
ret = SCSI_DH_DEV_OFFLINED;
|
||||
break;
|
||||
}
|
||||
/* Fallthrough */
|
||||
default:
|
||||
sdev_printk(KERN_WARNING, sdev,
|
||||
"%s: sending tur failed, sense %x/%x/%x\n",
|
||||
HP_SW_NAME, sshdr.sense_key, sshdr.asc,
|
||||
sshdr.ascq);
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* hp_sw_tur - Send TEST UNIT READY
|
||||
* @sdev: sdev command should be sent to
|
||||
*
|
||||
* Use the TEST UNIT READY command to determine
|
||||
* the path state.
|
||||
*/
|
||||
static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
|
||||
{
|
||||
struct request *req;
|
||||
int ret;
|
||||
|
||||
req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO);
|
||||
if (!req)
|
||||
return SCSI_DH_RES_TEMP_UNAVAIL;
|
||||
|
||||
req->cmd_type = REQ_TYPE_BLOCK_PC;
|
||||
req->cmd_flags |= REQ_FAILFAST;
|
||||
req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY);
|
||||
memset(req->cmd, 0, MAX_COMMAND_SIZE);
|
||||
req->cmd[0] = TEST_UNIT_READY;
|
||||
req->timeout = HP_SW_TIMEOUT;
|
||||
req->sense = h->sense;
|
||||
memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
|
||||
req->sense_len = 0;
|
||||
|
||||
retry:
|
||||
ret = blk_execute_rq(req->q, NULL, req, 1);
|
||||
if (ret == -EIO) {
|
||||
if (req->sense_len > 0) {
|
||||
ret = tur_done(sdev, h->sense);
|
||||
} else {
|
||||
sdev_printk(KERN_WARNING, sdev,
|
||||
"%s: sending tur failed with %x\n",
|
||||
HP_SW_NAME, req->errors);
|
||||
ret = SCSI_DH_IO;
|
||||
}
|
||||
} else {
|
||||
h->path_state = HP_SW_PATH_ACTIVE;
|
||||
ret = SCSI_DH_OK;
|
||||
}
|
||||
if (ret == SCSI_DH_IMM_RETRY)
|
||||
goto retry;
|
||||
if (ret == SCSI_DH_DEV_OFFLINED) {
|
||||
h->path_state = HP_SW_PATH_PASSIVE;
|
||||
ret = SCSI_DH_OK;
|
||||
}
|
||||
|
||||
blk_put_request(req);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* start_done - Handle START STOP UNIT return status
|
||||
* @sdev: sdev the command has been sent to
|
||||
* @errors: blk error code
|
||||
*/
|
||||
static int start_done(struct scsi_device *sdev, unsigned char *sense)
|
||||
{
|
||||
struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
|
||||
struct scsi_sense_hdr sshdr;
|
||||
int rc;
|
||||
|
||||
sdev_printk(KERN_INFO, sdev, "hp_sw_done\n");
|
||||
|
||||
rc = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
|
||||
if (!rc)
|
||||
goto done;
|
||||
rc = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
|
||||
if (!rc) {
|
||||
sdev_printk(KERN_WARNING, sdev,
|
||||
"%s: sending start_stop_unit failed, "
|
||||
"no sense available\n",
|
||||
HP_SW_NAME);
|
||||
return SCSI_DH_IO;
|
||||
}
|
||||
switch (sshdr.sense_key) {
|
||||
case NOT_READY:
|
||||
if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) {
|
||||
/*
|
||||
* LUN not ready - manual intervention required
|
||||
*
|
||||
* Switch-over in progress, retry.
|
||||
*/
|
||||
rc = SCSI_DH_RETRY;
|
||||
h->retries++;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
h->retries++;
|
||||
rc = SCSI_DH_IMM_RETRY;
|
||||
}
|
||||
|
||||
done:
|
||||
if (rc == SCSI_DH_OK || rc == SCSI_DH_IO)
|
||||
h->retries = 0;
|
||||
else if (h->retries > HP_SW_RETRIES) {
|
||||
h->retries = 0;
|
||||
sdev_printk(KERN_WARNING, sdev,
|
||||
"%s: sending start_stop_unit failed, sense %x/%x/%x\n",
|
||||
HP_SW_NAME, sshdr.sense_key, sshdr.asc,
|
||||
sshdr.ascq);
|
||||
rc = SCSI_DH_IO;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int hp_sw_activate(struct scsi_device *sdev)
|
||||
/*
|
||||
* hp_sw_start_stop - Send START STOP UNIT command
|
||||
* @sdev: sdev command should be sent to
|
||||
*
|
||||
* Sending START STOP UNIT activates the SP.
|
||||
*/
|
||||
static int hp_sw_start_stop(struct scsi_device *sdev, struct hp_sw_dh_data *h)
|
||||
{
|
||||
struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
|
||||
struct request *req;
|
||||
int ret = SCSI_DH_RES_TEMP_UNAVAIL;
|
||||
int ret, retry;
|
||||
|
||||
req = blk_get_request(sdev->request_queue, WRITE, GFP_ATOMIC);
|
||||
req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO);
|
||||
if (!req)
|
||||
goto done;
|
||||
|
||||
sdev_printk(KERN_INFO, sdev, "sending START_STOP.");
|
||||
return SCSI_DH_RES_TEMP_UNAVAIL;
|
||||
|
||||
req->cmd_type = REQ_TYPE_BLOCK_PC;
|
||||
req->cmd_flags |= REQ_FAILFAST;
|
||||
@ -98,95 +214,153 @@ static int hp_sw_activate(struct scsi_device *sdev)
|
||||
req->sense = h->sense;
|
||||
memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
|
||||
req->sense_len = 0;
|
||||
retry = h->retries;
|
||||
|
||||
retry:
|
||||
ret = blk_execute_rq(req->q, NULL, req, 1);
|
||||
if (!ret) /* SUCCESS */
|
||||
ret = hp_sw_done(sdev);
|
||||
else
|
||||
if (ret == -EIO) {
|
||||
if (req->sense_len > 0) {
|
||||
ret = start_done(sdev, h->sense);
|
||||
} else {
|
||||
sdev_printk(KERN_WARNING, sdev,
|
||||
"%s: sending start_stop_unit failed with %x\n",
|
||||
HP_SW_NAME, req->errors);
|
||||
ret = SCSI_DH_IO;
|
||||
}
|
||||
} else
|
||||
ret = SCSI_DH_OK;
|
||||
|
||||
if (ret == SCSI_DH_RETRY) {
|
||||
if (--retry)
|
||||
goto retry;
|
||||
ret = SCSI_DH_IO;
|
||||
done:
|
||||
}
|
||||
|
||||
blk_put_request(req);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
char *vendor;
|
||||
char *model;
|
||||
} hp_sw_dh_data_list[] = {
|
||||
{"COMPAQ", "MSA"},
|
||||
{"HP", "HSV"},
|
||||
static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req)
|
||||
{
|
||||
struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
|
||||
int ret = BLKPREP_OK;
|
||||
|
||||
if (h->path_state != HP_SW_PATH_ACTIVE) {
|
||||
ret = BLKPREP_KILL;
|
||||
req->cmd_flags |= REQ_QUIET;
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* hp_sw_activate - Activate a path
|
||||
* @sdev: sdev on the path to be activated
|
||||
*
|
||||
* The HP Active/Passive firmware is pretty simple;
|
||||
* the passive path reports NOT READY with sense codes
|
||||
* 0x04/0x02; a START STOP UNIT command will then
|
||||
* activate the passive path (and deactivate the
|
||||
* previously active one).
|
||||
*/
|
||||
static int hp_sw_activate(struct scsi_device *sdev)
|
||||
{
|
||||
int ret = SCSI_DH_OK;
|
||||
struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
|
||||
|
||||
ret = hp_sw_tur(sdev, h);
|
||||
|
||||
if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE) {
|
||||
ret = hp_sw_start_stop(sdev, h);
|
||||
if (ret == SCSI_DH_OK)
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: activated path\n",
|
||||
HP_SW_NAME);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct scsi_dh_devlist hp_sw_dh_data_list[] = {
|
||||
{"COMPAQ", "MSA1000 VOLUME"},
|
||||
{"COMPAQ", "HSV110"},
|
||||
{"HP", "HSV100"},
|
||||
{"DEC", "HSG80"},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
static int hp_sw_bus_notify(struct notifier_block *, unsigned long, void *);
|
||||
static int hp_sw_bus_attach(struct scsi_device *sdev);
|
||||
static void hp_sw_bus_detach(struct scsi_device *sdev);
|
||||
|
||||
static struct scsi_device_handler hp_sw_dh = {
|
||||
.name = HP_SW_NAME,
|
||||
.module = THIS_MODULE,
|
||||
.nb.notifier_call = hp_sw_bus_notify,
|
||||
.devlist = hp_sw_dh_data_list,
|
||||
.attach = hp_sw_bus_attach,
|
||||
.detach = hp_sw_bus_detach,
|
||||
.activate = hp_sw_activate,
|
||||
.prep_fn = hp_sw_prep_fn,
|
||||
};
|
||||
|
||||
static int hp_sw_bus_notify(struct notifier_block *nb,
|
||||
unsigned long action, void *data)
|
||||
static int hp_sw_bus_attach(struct scsi_device *sdev)
|
||||
{
|
||||
struct device *dev = data;
|
||||
struct scsi_device *sdev;
|
||||
struct scsi_dh_data *scsi_dh_data;
|
||||
int i, found = 0;
|
||||
struct hp_sw_dh_data *h;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
if (!scsi_is_sdev_device(dev))
|
||||
scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
|
||||
+ sizeof(struct hp_sw_dh_data) , GFP_KERNEL);
|
||||
if (!scsi_dh_data) {
|
||||
sdev_printk(KERN_ERR, sdev, "%s: Attach Failed\n",
|
||||
HP_SW_NAME);
|
||||
return 0;
|
||||
|
||||
sdev = to_scsi_device(dev);
|
||||
|
||||
if (action == BUS_NOTIFY_ADD_DEVICE) {
|
||||
for (i = 0; hp_sw_dh_data_list[i].vendor; i++) {
|
||||
if (!strncmp(sdev->vendor, hp_sw_dh_data_list[i].vendor,
|
||||
strlen(hp_sw_dh_data_list[i].vendor)) &&
|
||||
!strncmp(sdev->model, hp_sw_dh_data_list[i].model,
|
||||
strlen(hp_sw_dh_data_list[i].model))) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
goto out;
|
||||
|
||||
scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
|
||||
+ sizeof(struct hp_sw_dh_data) , GFP_KERNEL);
|
||||
if (!scsi_dh_data) {
|
||||
sdev_printk(KERN_ERR, sdev, "Attach Failed %s.\n",
|
||||
HP_SW_NAME);
|
||||
goto out;
|
||||
}
|
||||
|
||||
scsi_dh_data->scsi_dh = &hp_sw_dh;
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
sdev->scsi_dh_data = scsi_dh_data;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
try_module_get(THIS_MODULE);
|
||||
|
||||
sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", HP_SW_NAME);
|
||||
} else if (action == BUS_NOTIFY_DEL_DEVICE) {
|
||||
if (sdev->scsi_dh_data == NULL ||
|
||||
sdev->scsi_dh_data->scsi_dh != &hp_sw_dh)
|
||||
goto out;
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
scsi_dh_data = sdev->scsi_dh_data;
|
||||
sdev->scsi_dh_data = NULL;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
module_put(THIS_MODULE);
|
||||
|
||||
sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", HP_SW_NAME);
|
||||
|
||||
kfree(scsi_dh_data);
|
||||
}
|
||||
|
||||
out:
|
||||
scsi_dh_data->scsi_dh = &hp_sw_dh;
|
||||
h = (struct hp_sw_dh_data *) scsi_dh_data->buf;
|
||||
h->path_state = HP_SW_PATH_UNINITIALIZED;
|
||||
h->retries = HP_SW_RETRIES;
|
||||
|
||||
ret = hp_sw_tur(sdev, h);
|
||||
if (ret != SCSI_DH_OK || h->path_state == HP_SW_PATH_UNINITIALIZED)
|
||||
goto failed;
|
||||
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
goto failed;
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
sdev->scsi_dh_data = scsi_dh_data;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
|
||||
sdev_printk(KERN_INFO, sdev, "%s: attached to %s path\n",
|
||||
HP_SW_NAME, h->path_state == HP_SW_PATH_ACTIVE?
|
||||
"active":"passive");
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
kfree(scsi_dh_data);
|
||||
sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
|
||||
HP_SW_NAME);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void hp_sw_bus_detach( struct scsi_device *sdev )
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
scsi_dh_data = sdev->scsi_dh_data;
|
||||
sdev->scsi_dh_data = NULL;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
module_put(THIS_MODULE);
|
||||
|
||||
sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", HP_SW_NAME);
|
||||
|
||||
kfree(scsi_dh_data);
|
||||
}
|
||||
|
||||
static int __init hp_sw_init(void)
|
||||
@ -202,6 +376,6 @@ static void __exit hp_sw_exit(void)
|
||||
module_init(hp_sw_init);
|
||||
module_exit(hp_sw_exit);
|
||||
|
||||
MODULE_DESCRIPTION("HP MSA 1000");
|
||||
MODULE_DESCRIPTION("HP Active/Passive driver");
|
||||
MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -173,6 +173,11 @@ struct rdac_dh_data {
|
||||
#define RDAC_STATE_ACTIVE 0
|
||||
#define RDAC_STATE_PASSIVE 1
|
||||
unsigned char state;
|
||||
|
||||
#define RDAC_LUN_UNOWNED 0
|
||||
#define RDAC_LUN_OWNED 1
|
||||
#define RDAC_LUN_AVT 2
|
||||
char lun_state;
|
||||
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
|
||||
union {
|
||||
struct c2_inquiry c2;
|
||||
@ -182,6 +187,13 @@ struct rdac_dh_data {
|
||||
} inq;
|
||||
};
|
||||
|
||||
static const char *lun_state[] =
|
||||
{
|
||||
"unowned",
|
||||
"owned",
|
||||
"owned (AVT mode)",
|
||||
};
|
||||
|
||||
static LIST_HEAD(ctlr_list);
|
||||
static DEFINE_SPINLOCK(list_lock);
|
||||
|
||||
@ -197,9 +209,8 @@ static struct request *get_rdac_req(struct scsi_device *sdev,
|
||||
{
|
||||
struct request *rq;
|
||||
struct request_queue *q = sdev->request_queue;
|
||||
struct rdac_dh_data *h = get_rdac_data(sdev);
|
||||
|
||||
rq = blk_get_request(q, rw, GFP_KERNEL);
|
||||
rq = blk_get_request(q, rw, GFP_NOIO);
|
||||
|
||||
if (!rq) {
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
@ -207,17 +218,14 @@ static struct request *get_rdac_req(struct scsi_device *sdev,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_KERNEL)) {
|
||||
if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) {
|
||||
blk_put_request(rq);
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"get_rdac_req: blk_rq_map_kern failed.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(&rq->cmd, 0, BLK_MAX_CDB);
|
||||
rq->sense = h->sense;
|
||||
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
|
||||
rq->sense_len = 0;
|
||||
memset(rq->cmd, 0, BLK_MAX_CDB);
|
||||
|
||||
rq->cmd_type = REQ_TYPE_BLOCK_PC;
|
||||
rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
|
||||
@ -227,12 +235,12 @@ static struct request *get_rdac_req(struct scsi_device *sdev,
|
||||
return rq;
|
||||
}
|
||||
|
||||
static struct request *rdac_failover_get(struct scsi_device *sdev)
|
||||
static struct request *rdac_failover_get(struct scsi_device *sdev,
|
||||
struct rdac_dh_data *h)
|
||||
{
|
||||
struct request *rq;
|
||||
struct rdac_mode_common *common;
|
||||
unsigned data_size;
|
||||
struct rdac_dh_data *h = get_rdac_data(sdev);
|
||||
|
||||
if (h->ctlr->use_ms10) {
|
||||
struct rdac_pg_expanded *rdac_pg;
|
||||
@ -277,6 +285,10 @@ static struct request *rdac_failover_get(struct scsi_device *sdev)
|
||||
}
|
||||
rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
|
||||
|
||||
rq->sense = h->sense;
|
||||
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
|
||||
rq->sense_len = 0;
|
||||
|
||||
return rq;
|
||||
}
|
||||
|
||||
@ -321,11 +333,10 @@ done:
|
||||
}
|
||||
|
||||
static int submit_inquiry(struct scsi_device *sdev, int page_code,
|
||||
unsigned int len)
|
||||
unsigned int len, struct rdac_dh_data *h)
|
||||
{
|
||||
struct request *rq;
|
||||
struct request_queue *q = sdev->request_queue;
|
||||
struct rdac_dh_data *h = get_rdac_data(sdev);
|
||||
int err = SCSI_DH_RES_TEMP_UNAVAIL;
|
||||
|
||||
rq = get_rdac_req(sdev, &h->inq, len, READ);
|
||||
@ -338,59 +349,68 @@ static int submit_inquiry(struct scsi_device *sdev, int page_code,
|
||||
rq->cmd[2] = page_code;
|
||||
rq->cmd[4] = len;
|
||||
rq->cmd_len = COMMAND_SIZE(INQUIRY);
|
||||
|
||||
rq->sense = h->sense;
|
||||
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
|
||||
rq->sense_len = 0;
|
||||
|
||||
err = blk_execute_rq(q, NULL, rq, 1);
|
||||
if (err == -EIO)
|
||||
err = SCSI_DH_IO;
|
||||
|
||||
blk_put_request(rq);
|
||||
done:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int get_lun(struct scsi_device *sdev)
|
||||
static int get_lun(struct scsi_device *sdev, struct rdac_dh_data *h)
|
||||
{
|
||||
int err;
|
||||
struct c8_inquiry *inqp;
|
||||
struct rdac_dh_data *h = get_rdac_data(sdev);
|
||||
|
||||
err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry));
|
||||
err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry), h);
|
||||
if (err == SCSI_DH_OK) {
|
||||
inqp = &h->inq.c8;
|
||||
h->lun = inqp->lun[7]; /* currently it uses only one byte */
|
||||
if (inqp->page_code != 0xc8)
|
||||
return SCSI_DH_NOSYS;
|
||||
if (inqp->page_id[0] != 'e' || inqp->page_id[1] != 'd' ||
|
||||
inqp->page_id[2] != 'i' || inqp->page_id[3] != 'd')
|
||||
return SCSI_DH_NOSYS;
|
||||
h->lun = scsilun_to_int((struct scsi_lun *)inqp->lun);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
#define RDAC_OWNED 0
|
||||
#define RDAC_UNOWNED 1
|
||||
#define RDAC_FAILED 2
|
||||
static int check_ownership(struct scsi_device *sdev)
|
||||
static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h)
|
||||
{
|
||||
int err;
|
||||
struct c9_inquiry *inqp;
|
||||
struct rdac_dh_data *h = get_rdac_data(sdev);
|
||||
|
||||
err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry));
|
||||
err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry), h);
|
||||
if (err == SCSI_DH_OK) {
|
||||
err = RDAC_UNOWNED;
|
||||
inqp = &h->inq.c9;
|
||||
/*
|
||||
* If in AVT mode or if the path already owns the LUN,
|
||||
* return RDAC_OWNED;
|
||||
*/
|
||||
if (((inqp->avte_cvp >> 7) == 0x1) ||
|
||||
((inqp->avte_cvp & 0x1) != 0))
|
||||
err = RDAC_OWNED;
|
||||
} else
|
||||
err = RDAC_FAILED;
|
||||
if ((inqp->avte_cvp >> 7) == 0x1) {
|
||||
/* LUN in AVT mode */
|
||||
sdev_printk(KERN_NOTICE, sdev,
|
||||
"%s: AVT mode detected\n",
|
||||
RDAC_NAME);
|
||||
h->lun_state = RDAC_LUN_AVT;
|
||||
} else if ((inqp->avte_cvp & 0x1) != 0) {
|
||||
/* LUN was owned by the controller */
|
||||
h->lun_state = RDAC_LUN_OWNED;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int initialize_controller(struct scsi_device *sdev)
|
||||
static int initialize_controller(struct scsi_device *sdev,
|
||||
struct rdac_dh_data *h)
|
||||
{
|
||||
int err;
|
||||
struct c4_inquiry *inqp;
|
||||
struct rdac_dh_data *h = get_rdac_data(sdev);
|
||||
|
||||
err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry));
|
||||
err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry), h);
|
||||
if (err == SCSI_DH_OK) {
|
||||
inqp = &h->inq.c4;
|
||||
h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id);
|
||||
@ -400,13 +420,12 @@ static int initialize_controller(struct scsi_device *sdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int set_mode_select(struct scsi_device *sdev)
|
||||
static int set_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h)
|
||||
{
|
||||
int err;
|
||||
struct c2_inquiry *inqp;
|
||||
struct rdac_dh_data *h = get_rdac_data(sdev);
|
||||
|
||||
err = submit_inquiry(sdev, 0xC2, sizeof(struct c2_inquiry));
|
||||
err = submit_inquiry(sdev, 0xC2, sizeof(struct c2_inquiry), h);
|
||||
if (err == SCSI_DH_OK) {
|
||||
inqp = &h->inq.c2;
|
||||
/*
|
||||
@ -421,13 +440,13 @@ static int set_mode_select(struct scsi_device *sdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mode_select_handle_sense(struct scsi_device *sdev)
|
||||
static int mode_select_handle_sense(struct scsi_device *sdev,
|
||||
unsigned char *sensebuf)
|
||||
{
|
||||
struct scsi_sense_hdr sense_hdr;
|
||||
struct rdac_dh_data *h = get_rdac_data(sdev);
|
||||
int sense, err = SCSI_DH_IO, ret;
|
||||
|
||||
ret = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sense_hdr);
|
||||
ret = scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, &sense_hdr);
|
||||
if (!ret)
|
||||
goto done;
|
||||
|
||||
@ -451,14 +470,13 @@ done:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int send_mode_select(struct scsi_device *sdev)
|
||||
static int send_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h)
|
||||
{
|
||||
struct request *rq;
|
||||
struct request_queue *q = sdev->request_queue;
|
||||
struct rdac_dh_data *h = get_rdac_data(sdev);
|
||||
int err = SCSI_DH_RES_TEMP_UNAVAIL;
|
||||
|
||||
rq = rdac_failover_get(sdev);
|
||||
rq = rdac_failover_get(sdev, h);
|
||||
if (!rq)
|
||||
goto done;
|
||||
|
||||
@ -466,9 +484,11 @@ static int send_mode_select(struct scsi_device *sdev)
|
||||
|
||||
err = blk_execute_rq(q, NULL, rq, 1);
|
||||
if (err != SCSI_DH_OK)
|
||||
err = mode_select_handle_sense(sdev);
|
||||
err = mode_select_handle_sense(sdev, h->sense);
|
||||
if (err == SCSI_DH_OK)
|
||||
h->state = RDAC_STATE_ACTIVE;
|
||||
|
||||
blk_put_request(rq);
|
||||
done:
|
||||
return err;
|
||||
}
|
||||
@ -478,38 +498,23 @@ static int rdac_activate(struct scsi_device *sdev)
|
||||
struct rdac_dh_data *h = get_rdac_data(sdev);
|
||||
int err = SCSI_DH_OK;
|
||||
|
||||
if (h->lun == UNINITIALIZED_LUN) {
|
||||
err = get_lun(sdev);
|
||||
if (err != SCSI_DH_OK)
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = check_ownership(sdev);
|
||||
switch (err) {
|
||||
case RDAC_UNOWNED:
|
||||
break;
|
||||
case RDAC_OWNED:
|
||||
err = SCSI_DH_OK;
|
||||
err = check_ownership(sdev, h);
|
||||
if (err != SCSI_DH_OK)
|
||||
goto done;
|
||||
case RDAC_FAILED:
|
||||
default:
|
||||
err = SCSI_DH_IO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!h->ctlr) {
|
||||
err = initialize_controller(sdev);
|
||||
err = initialize_controller(sdev, h);
|
||||
if (err != SCSI_DH_OK)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (h->ctlr->use_ms10 == -1) {
|
||||
err = set_mode_select(sdev);
|
||||
err = set_mode_select(sdev, h);
|
||||
if (err != SCSI_DH_OK)
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = send_mode_select(sdev);
|
||||
if (h->lun_state == RDAC_LUN_UNOWNED)
|
||||
err = send_mode_select(sdev, h);
|
||||
done:
|
||||
return err;
|
||||
}
|
||||
@ -569,10 +574,7 @@ static int rdac_check_sense(struct scsi_device *sdev,
|
||||
return SCSI_RETURN_NOT_HANDLED;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
char *vendor;
|
||||
char *model;
|
||||
} rdac_dev_list[] = {
|
||||
const struct scsi_dh_devlist rdac_dev_list[] = {
|
||||
{"IBM", "1722"},
|
||||
{"IBM", "1724"},
|
||||
{"IBM", "1726"},
|
||||
@ -590,89 +592,89 @@ static const struct {
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
static int rdac_bus_notify(struct notifier_block *, unsigned long, void *);
|
||||
static int rdac_bus_attach(struct scsi_device *sdev);
|
||||
static void rdac_bus_detach(struct scsi_device *sdev);
|
||||
|
||||
static struct scsi_device_handler rdac_dh = {
|
||||
.name = RDAC_NAME,
|
||||
.module = THIS_MODULE,
|
||||
.nb.notifier_call = rdac_bus_notify,
|
||||
.devlist = rdac_dev_list,
|
||||
.prep_fn = rdac_prep_fn,
|
||||
.check_sense = rdac_check_sense,
|
||||
.attach = rdac_bus_attach,
|
||||
.detach = rdac_bus_detach,
|
||||
.activate = rdac_activate,
|
||||
};
|
||||
|
||||
/*
|
||||
* TODO: need some interface so we can set trespass values
|
||||
*/
|
||||
static int rdac_bus_notify(struct notifier_block *nb,
|
||||
unsigned long action, void *data)
|
||||
static int rdac_bus_attach(struct scsi_device *sdev)
|
||||
{
|
||||
struct device *dev = data;
|
||||
struct scsi_device *sdev;
|
||||
struct scsi_dh_data *scsi_dh_data;
|
||||
struct rdac_dh_data *h;
|
||||
int i, found = 0;
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
if (!scsi_is_sdev_device(dev))
|
||||
scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
|
||||
+ sizeof(*h) , GFP_KERNEL);
|
||||
if (!scsi_dh_data) {
|
||||
sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
|
||||
RDAC_NAME);
|
||||
return 0;
|
||||
|
||||
sdev = to_scsi_device(dev);
|
||||
|
||||
if (action == BUS_NOTIFY_ADD_DEVICE) {
|
||||
for (i = 0; rdac_dev_list[i].vendor; i++) {
|
||||
if (!strncmp(sdev->vendor, rdac_dev_list[i].vendor,
|
||||
strlen(rdac_dev_list[i].vendor)) &&
|
||||
!strncmp(sdev->model, rdac_dev_list[i].model,
|
||||
strlen(rdac_dev_list[i].model))) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
goto out;
|
||||
|
||||
scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
|
||||
+ sizeof(*h) , GFP_KERNEL);
|
||||
if (!scsi_dh_data) {
|
||||
sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n",
|
||||
RDAC_NAME);
|
||||
goto out;
|
||||
}
|
||||
|
||||
scsi_dh_data->scsi_dh = &rdac_dh;
|
||||
h = (struct rdac_dh_data *) scsi_dh_data->buf;
|
||||
h->lun = UNINITIALIZED_LUN;
|
||||
h->state = RDAC_STATE_ACTIVE;
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
sdev->scsi_dh_data = scsi_dh_data;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
try_module_get(THIS_MODULE);
|
||||
|
||||
sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", RDAC_NAME);
|
||||
|
||||
} else if (action == BUS_NOTIFY_DEL_DEVICE) {
|
||||
if (sdev->scsi_dh_data == NULL ||
|
||||
sdev->scsi_dh_data->scsi_dh != &rdac_dh)
|
||||
goto out;
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
scsi_dh_data = sdev->scsi_dh_data;
|
||||
sdev->scsi_dh_data = NULL;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
|
||||
h = (struct rdac_dh_data *) scsi_dh_data->buf;
|
||||
if (h->ctlr)
|
||||
kref_put(&h->ctlr->kref, release_controller);
|
||||
kfree(scsi_dh_data);
|
||||
module_put(THIS_MODULE);
|
||||
sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", RDAC_NAME);
|
||||
}
|
||||
|
||||
out:
|
||||
scsi_dh_data->scsi_dh = &rdac_dh;
|
||||
h = (struct rdac_dh_data *) scsi_dh_data->buf;
|
||||
h->lun = UNINITIALIZED_LUN;
|
||||
h->state = RDAC_STATE_ACTIVE;
|
||||
|
||||
err = get_lun(sdev, h);
|
||||
if (err != SCSI_DH_OK)
|
||||
goto failed;
|
||||
|
||||
err = check_ownership(sdev, h);
|
||||
if (err != SCSI_DH_OK)
|
||||
goto failed;
|
||||
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
goto failed;
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
sdev->scsi_dh_data = scsi_dh_data;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
|
||||
sdev_printk(KERN_NOTICE, sdev,
|
||||
"%s: LUN %d (%s)\n",
|
||||
RDAC_NAME, h->lun, lun_state[(int)h->lun_state]);
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
kfree(scsi_dh_data);
|
||||
sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
|
||||
RDAC_NAME);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void rdac_bus_detach( struct scsi_device *sdev )
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data;
|
||||
struct rdac_dh_data *h;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
scsi_dh_data = sdev->scsi_dh_data;
|
||||
sdev->scsi_dh_data = NULL;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
|
||||
h = (struct rdac_dh_data *) scsi_dh_data->buf;
|
||||
if (h->ctlr)
|
||||
kref_put(&h->ctlr->kref, release_controller);
|
||||
kfree(scsi_dh_data);
|
||||
module_put(THIS_MODULE);
|
||||
sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", RDAC_NAME);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int __init rdac_init(void)
|
||||
{
|
||||
int r;
|
||||
|
@ -521,9 +521,10 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,
|
||||
static void ibmvfc_reinit_host(struct ibmvfc_host *vhost)
|
||||
{
|
||||
if (vhost->action == IBMVFC_HOST_ACTION_NONE) {
|
||||
scsi_block_requests(vhost->host);
|
||||
ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING);
|
||||
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
|
||||
if (!ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) {
|
||||
scsi_block_requests(vhost->host);
|
||||
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
|
||||
}
|
||||
} else
|
||||
vhost->reinit = 1;
|
||||
|
||||
@ -854,39 +855,41 @@ static void ibmvfc_retry_host_init(struct ibmvfc_host *vhost)
|
||||
}
|
||||
|
||||
/**
|
||||
* __ibmvfc_find_target - Find the specified scsi_target (no locking)
|
||||
* __ibmvfc_get_target - Find the specified scsi_target (no locking)
|
||||
* @starget: scsi target struct
|
||||
*
|
||||
* Return value:
|
||||
* ibmvfc_target struct / NULL if not found
|
||||
**/
|
||||
static struct ibmvfc_target *__ibmvfc_find_target(struct scsi_target *starget)
|
||||
static struct ibmvfc_target *__ibmvfc_get_target(struct scsi_target *starget)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||
struct ibmvfc_host *vhost = shost_priv(shost);
|
||||
struct ibmvfc_target *tgt;
|
||||
|
||||
list_for_each_entry(tgt, &vhost->targets, queue)
|
||||
if (tgt->target_id == starget->id)
|
||||
if (tgt->target_id == starget->id) {
|
||||
kref_get(&tgt->kref);
|
||||
return tgt;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ibmvfc_find_target - Find the specified scsi_target
|
||||
* ibmvfc_get_target - Find the specified scsi_target
|
||||
* @starget: scsi target struct
|
||||
*
|
||||
* Return value:
|
||||
* ibmvfc_target struct / NULL if not found
|
||||
**/
|
||||
static struct ibmvfc_target *ibmvfc_find_target(struct scsi_target *starget)
|
||||
static struct ibmvfc_target *ibmvfc_get_target(struct scsi_target *starget)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||
struct ibmvfc_target *tgt;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
tgt = __ibmvfc_find_target(starget);
|
||||
tgt = __ibmvfc_get_target(starget);
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
return tgt;
|
||||
}
|
||||
@ -963,6 +966,9 @@ static void ibmvfc_get_host_port_state(struct Scsi_Host *shost)
|
||||
case IBMVFC_HALTED:
|
||||
fc_host_port_state(shost) = FC_PORTSTATE_BLOCKED;
|
||||
break;
|
||||
case IBMVFC_NO_CRQ:
|
||||
fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
|
||||
break;
|
||||
default:
|
||||
ibmvfc_log(vhost, 3, "Unknown port state: %d\n", vhost->state);
|
||||
fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
|
||||
@ -987,6 +993,17 @@ static void ibmvfc_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
|
||||
rport->dev_loss_tmo = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ibmvfc_release_tgt - Free memory allocated for a target
|
||||
* @kref: kref struct
|
||||
*
|
||||
**/
|
||||
static void ibmvfc_release_tgt(struct kref *kref)
|
||||
{
|
||||
struct ibmvfc_target *tgt = container_of(kref, struct ibmvfc_target, kref);
|
||||
kfree(tgt);
|
||||
}
|
||||
|
||||
/**
|
||||
* ibmvfc_get_starget_node_name - Get SCSI target's node name
|
||||
* @starget: scsi target struct
|
||||
@ -996,8 +1013,10 @@ static void ibmvfc_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
|
||||
**/
|
||||
static void ibmvfc_get_starget_node_name(struct scsi_target *starget)
|
||||
{
|
||||
struct ibmvfc_target *tgt = ibmvfc_find_target(starget);
|
||||
struct ibmvfc_target *tgt = ibmvfc_get_target(starget);
|
||||
fc_starget_port_name(starget) = tgt ? tgt->ids.node_name : 0;
|
||||
if (tgt)
|
||||
kref_put(&tgt->kref, ibmvfc_release_tgt);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1009,8 +1028,10 @@ static void ibmvfc_get_starget_node_name(struct scsi_target *starget)
|
||||
**/
|
||||
static void ibmvfc_get_starget_port_name(struct scsi_target *starget)
|
||||
{
|
||||
struct ibmvfc_target *tgt = ibmvfc_find_target(starget);
|
||||
struct ibmvfc_target *tgt = ibmvfc_get_target(starget);
|
||||
fc_starget_port_name(starget) = tgt ? tgt->ids.port_name : 0;
|
||||
if (tgt)
|
||||
kref_put(&tgt->kref, ibmvfc_release_tgt);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1022,8 +1043,10 @@ static void ibmvfc_get_starget_port_name(struct scsi_target *starget)
|
||||
**/
|
||||
static void ibmvfc_get_starget_port_id(struct scsi_target *starget)
|
||||
{
|
||||
struct ibmvfc_target *tgt = ibmvfc_find_target(starget);
|
||||
struct ibmvfc_target *tgt = ibmvfc_get_target(starget);
|
||||
fc_starget_port_id(starget) = tgt ? tgt->scsi_id : -1;
|
||||
if (tgt)
|
||||
kref_put(&tgt->kref, ibmvfc_release_tgt);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1113,7 +1136,7 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost)
|
||||
login_info->max_cmds = max_requests + IBMVFC_NUM_INTERNAL_REQ;
|
||||
login_info->capabilities = IBMVFC_CAN_MIGRATE;
|
||||
login_info->async.va = vhost->async_crq.msg_token;
|
||||
login_info->async.len = vhost->async_crq.size;
|
||||
login_info->async.len = vhost->async_crq.size * sizeof(*vhost->async_crq.msgs);
|
||||
strncpy(login_info->partition_name, vhost->partition_name, IBMVFC_MAX_NAME);
|
||||
strncpy(login_info->device_name,
|
||||
vhost->host->shost_gendev.bus_id, IBMVFC_MAX_NAME);
|
||||
@ -1404,7 +1427,7 @@ static void ibmvfc_log_error(struct ibmvfc_event *evt)
|
||||
err = cmd_status[index].name;
|
||||
}
|
||||
|
||||
if (!logerr && (vhost->log_level <= IBMVFC_DEFAULT_LOG_LEVEL))
|
||||
if (!logerr && (vhost->log_level <= (IBMVFC_DEFAULT_LOG_LEVEL + 1)))
|
||||
return;
|
||||
|
||||
if (rsp->flags & FCP_RSP_LEN_VALID)
|
||||
@ -2054,7 +2077,7 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
|
||||
{
|
||||
const char *desc = ibmvfc_get_ae_desc(crq->event);
|
||||
|
||||
ibmvfc_log(vhost, 2, "%s event received\n", desc);
|
||||
ibmvfc_log(vhost, 3, "%s event received\n", desc);
|
||||
|
||||
switch (crq->event) {
|
||||
case IBMVFC_AE_LINK_UP:
|
||||
@ -2647,17 +2670,6 @@ static void ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt,
|
||||
ibmvfc_init_tgt(tgt, job_step);
|
||||
}
|
||||
|
||||
/**
|
||||
* ibmvfc_release_tgt - Free memory allocated for a target
|
||||
* @kref: kref struct
|
||||
*
|
||||
**/
|
||||
static void ibmvfc_release_tgt(struct kref *kref)
|
||||
{
|
||||
struct ibmvfc_target *tgt = container_of(kref, struct ibmvfc_target, kref);
|
||||
kfree(tgt);
|
||||
}
|
||||
|
||||
/**
|
||||
* ibmvfc_tgt_prli_done - Completion handler for Process Login
|
||||
* @evt: ibmvfc event struct
|
||||
@ -2901,6 +2913,139 @@ static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt)
|
||||
tgt_dbg(tgt, "Sent Implicit Logout\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* ibmvfc_adisc_needs_plogi - Does device need PLOGI?
|
||||
* @mad: ibmvfc passthru mad struct
|
||||
* @tgt: ibmvfc target struct
|
||||
*
|
||||
* Returns:
|
||||
* 1 if PLOGI needed / 0 if PLOGI not needed
|
||||
**/
|
||||
static int ibmvfc_adisc_needs_plogi(struct ibmvfc_passthru_mad *mad,
|
||||
struct ibmvfc_target *tgt)
|
||||
{
|
||||
if (memcmp(&mad->fc_iu.response[2], &tgt->ids.port_name,
|
||||
sizeof(tgt->ids.port_name)))
|
||||
return 1;
|
||||
if (memcmp(&mad->fc_iu.response[4], &tgt->ids.node_name,
|
||||
sizeof(tgt->ids.node_name)))
|
||||
return 1;
|
||||
if (mad->fc_iu.response[6] != tgt->scsi_id)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ibmvfc_tgt_adisc_done - Completion handler for ADISC
|
||||
* @evt: ibmvfc event struct
|
||||
*
|
||||
**/
|
||||
static void ibmvfc_tgt_adisc_done(struct ibmvfc_event *evt)
|
||||
{
|
||||
struct ibmvfc_target *tgt = evt->tgt;
|
||||
struct ibmvfc_host *vhost = evt->vhost;
|
||||
struct ibmvfc_passthru_mad *mad = &evt->xfer_iu->passthru;
|
||||
u32 status = mad->common.status;
|
||||
u8 fc_reason, fc_explain;
|
||||
|
||||
vhost->discovery_threads--;
|
||||
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
|
||||
|
||||
switch (status) {
|
||||
case IBMVFC_MAD_SUCCESS:
|
||||
tgt_dbg(tgt, "ADISC succeeded\n");
|
||||
if (ibmvfc_adisc_needs_plogi(mad, tgt))
|
||||
tgt->need_login = 1;
|
||||
break;
|
||||
case IBMVFC_MAD_DRIVER_FAILED:
|
||||
break;
|
||||
case IBMVFC_MAD_FAILED:
|
||||
default:
|
||||
tgt->need_login = 1;
|
||||
fc_reason = (mad->fc_iu.response[1] & 0x00ff0000) >> 16;
|
||||
fc_explain = (mad->fc_iu.response[1] & 0x0000ff00) >> 8;
|
||||
tgt_info(tgt, "ADISC failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
|
||||
ibmvfc_get_cmd_error(mad->iu.status, mad->iu.error),
|
||||
mad->iu.status, mad->iu.error,
|
||||
ibmvfc_get_fc_type(fc_reason), fc_reason,
|
||||
ibmvfc_get_ls_explain(fc_explain), fc_explain, status);
|
||||
break;
|
||||
};
|
||||
|
||||
kref_put(&tgt->kref, ibmvfc_release_tgt);
|
||||
ibmvfc_free_event(evt);
|
||||
wake_up(&vhost->work_wait_q);
|
||||
}
|
||||
|
||||
/**
|
||||
* ibmvfc_init_passthru - Initialize an event struct for FC passthru
|
||||
* @evt: ibmvfc event struct
|
||||
*
|
||||
**/
|
||||
static void ibmvfc_init_passthru(struct ibmvfc_event *evt)
|
||||
{
|
||||
struct ibmvfc_passthru_mad *mad = &evt->iu.passthru;
|
||||
|
||||
memset(mad, 0, sizeof(*mad));
|
||||
mad->common.version = 1;
|
||||
mad->common.opcode = IBMVFC_PASSTHRU;
|
||||
mad->common.length = sizeof(*mad) - sizeof(mad->fc_iu) - sizeof(mad->iu);
|
||||
mad->cmd_ioba.va = (u64)evt->crq.ioba +
|
||||
offsetof(struct ibmvfc_passthru_mad, iu);
|
||||
mad->cmd_ioba.len = sizeof(mad->iu);
|
||||
mad->iu.cmd_len = sizeof(mad->fc_iu.payload);
|
||||
mad->iu.rsp_len = sizeof(mad->fc_iu.response);
|
||||
mad->iu.cmd.va = (u64)evt->crq.ioba +
|
||||
offsetof(struct ibmvfc_passthru_mad, fc_iu) +
|
||||
offsetof(struct ibmvfc_passthru_fc_iu, payload);
|
||||
mad->iu.cmd.len = sizeof(mad->fc_iu.payload);
|
||||
mad->iu.rsp.va = (u64)evt->crq.ioba +
|
||||
offsetof(struct ibmvfc_passthru_mad, fc_iu) +
|
||||
offsetof(struct ibmvfc_passthru_fc_iu, response);
|
||||
mad->iu.rsp.len = sizeof(mad->fc_iu.response);
|
||||
}
|
||||
|
||||
/**
|
||||
* ibmvfc_tgt_adisc - Initiate an ADISC for specified target
|
||||
* @tgt: ibmvfc target struct
|
||||
*
|
||||
**/
|
||||
static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt)
|
||||
{
|
||||
struct ibmvfc_passthru_mad *mad;
|
||||
struct ibmvfc_host *vhost = tgt->vhost;
|
||||
struct ibmvfc_event *evt;
|
||||
|
||||
if (vhost->discovery_threads >= disc_threads)
|
||||
return;
|
||||
|
||||
kref_get(&tgt->kref);
|
||||
evt = ibmvfc_get_event(vhost);
|
||||
vhost->discovery_threads++;
|
||||
ibmvfc_init_event(evt, ibmvfc_tgt_adisc_done, IBMVFC_MAD_FORMAT);
|
||||
evt->tgt = tgt;
|
||||
|
||||
ibmvfc_init_passthru(evt);
|
||||
mad = &evt->iu.passthru;
|
||||
mad->iu.flags = IBMVFC_FC_ELS;
|
||||
mad->iu.scsi_id = tgt->scsi_id;
|
||||
|
||||
mad->fc_iu.payload[0] = IBMVFC_ADISC;
|
||||
memcpy(&mad->fc_iu.payload[2], &vhost->login_buf->resp.port_name,
|
||||
sizeof(vhost->login_buf->resp.port_name));
|
||||
memcpy(&mad->fc_iu.payload[4], &vhost->login_buf->resp.node_name,
|
||||
sizeof(vhost->login_buf->resp.node_name));
|
||||
mad->fc_iu.payload[6] = vhost->login_buf->resp.scsi_id & 0x00ffffff;
|
||||
|
||||
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT);
|
||||
if (ibmvfc_send_event(evt, vhost, default_timeout)) {
|
||||
vhost->discovery_threads--;
|
||||
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
|
||||
kref_put(&tgt->kref, ibmvfc_release_tgt);
|
||||
} else
|
||||
tgt_dbg(tgt, "Sent ADISC\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* ibmvfc_tgt_query_target_done - Completion handler for Query Target MAD
|
||||
* @evt: ibmvfc event struct
|
||||
@ -2921,6 +3066,8 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt)
|
||||
tgt->new_scsi_id = rsp->scsi_id;
|
||||
if (rsp->scsi_id != tgt->scsi_id)
|
||||
ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout);
|
||||
else
|
||||
ibmvfc_init_tgt(tgt, ibmvfc_tgt_adisc);
|
||||
break;
|
||||
case IBMVFC_MAD_DRIVER_FAILED:
|
||||
break;
|
||||
@ -3336,6 +3483,7 @@ static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt)
|
||||
tgt_dbg(tgt, "rport add succeeded\n");
|
||||
rport->maxframe_size = tgt->service_parms.common.bb_rcv_sz & 0x0fff;
|
||||
rport->supported_classes = 0;
|
||||
tgt->target_id = rport->scsi_target_id;
|
||||
if (tgt->service_parms.class1_parms[0] & 0x80000000)
|
||||
rport->supported_classes |= FC_COS_CLASS1;
|
||||
if (tgt->service_parms.class2_parms[0] & 0x80000000)
|
||||
@ -3800,10 +3948,12 @@ static int ibmvfc_remove(struct vio_dev *vdev)
|
||||
|
||||
ENTER;
|
||||
ibmvfc_remove_trace_file(&vhost->host->shost_dev.kobj, &ibmvfc_trace_attr);
|
||||
ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE);
|
||||
ibmvfc_wait_while_resetting(vhost);
|
||||
ibmvfc_release_crq_queue(vhost);
|
||||
kthread_stop(vhost->work_thread);
|
||||
fc_remove_host(vhost->host);
|
||||
scsi_remove_host(vhost->host);
|
||||
ibmvfc_release_crq_queue(vhost);
|
||||
|
||||
spin_lock_irqsave(vhost->host->host_lock, flags);
|
||||
ibmvfc_purge_requests(vhost, DID_ERROR);
|
||||
|
@ -29,8 +29,8 @@
|
||||
#include "viosrp.h"
|
||||
|
||||
#define IBMVFC_NAME "ibmvfc"
|
||||
#define IBMVFC_DRIVER_VERSION "1.0.0"
|
||||
#define IBMVFC_DRIVER_DATE "(July 1, 2008)"
|
||||
#define IBMVFC_DRIVER_VERSION "1.0.1"
|
||||
#define IBMVFC_DRIVER_DATE "(July 11, 2008)"
|
||||
|
||||
#define IBMVFC_DEFAULT_TIMEOUT 15
|
||||
#define IBMVFC_INIT_TIMEOUT 30
|
||||
@ -119,6 +119,7 @@ enum ibmvfc_mad_types {
|
||||
IBMVFC_PROCESS_LOGIN = 0x0008,
|
||||
IBMVFC_QUERY_TARGET = 0x0010,
|
||||
IBMVFC_IMPLICIT_LOGOUT = 0x0040,
|
||||
IBMVFC_PASSTHRU = 0x0200,
|
||||
IBMVFC_TMF_MAD = 0x0100,
|
||||
};
|
||||
|
||||
@ -439,6 +440,37 @@ struct ibmvfc_cmd {
|
||||
struct ibmvfc_fcp_rsp rsp;
|
||||
}__attribute__((packed, aligned (8)));
|
||||
|
||||
struct ibmvfc_passthru_fc_iu {
|
||||
u32 payload[7];
|
||||
#define IBMVFC_ADISC 0x52000000
|
||||
u32 response[7];
|
||||
};
|
||||
|
||||
struct ibmvfc_passthru_iu {
|
||||
u64 task_tag;
|
||||
u32 cmd_len;
|
||||
u32 rsp_len;
|
||||
u16 status;
|
||||
u16 error;
|
||||
u32 flags;
|
||||
#define IBMVFC_FC_ELS 0x01
|
||||
u32 cancel_key;
|
||||
u32 reserved;
|
||||
struct srp_direct_buf cmd;
|
||||
struct srp_direct_buf rsp;
|
||||
u64 correlation;
|
||||
u64 scsi_id;
|
||||
u64 tag;
|
||||
u64 reserved2[2];
|
||||
}__attribute__((packed, aligned (8)));
|
||||
|
||||
struct ibmvfc_passthru_mad {
|
||||
struct ibmvfc_mad_common common;
|
||||
struct srp_direct_buf cmd_ioba;
|
||||
struct ibmvfc_passthru_iu iu;
|
||||
struct ibmvfc_passthru_fc_iu fc_iu;
|
||||
}__attribute__((packed, aligned (8)));
|
||||
|
||||
struct ibmvfc_trace_start_entry {
|
||||
u32 xfer_len;
|
||||
}__attribute__((packed));
|
||||
@ -531,6 +563,7 @@ union ibmvfc_iu {
|
||||
struct ibmvfc_implicit_logout implicit_logout;
|
||||
struct ibmvfc_tmf tmf;
|
||||
struct ibmvfc_cmd cmd;
|
||||
struct ibmvfc_passthru_mad passthru;
|
||||
}__attribute__((packed, aligned (8)));
|
||||
|
||||
enum ibmvfc_target_action {
|
||||
@ -656,6 +689,9 @@ struct ibmvfc_host {
|
||||
#define tgt_dbg(t, fmt, ...) \
|
||||
DBG_CMD(dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__))
|
||||
|
||||
#define tgt_info(t, fmt, ...) \
|
||||
dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)
|
||||
|
||||
#define tgt_err(t, fmt, ...) \
|
||||
dev_err((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)
|
||||
|
||||
@ -668,8 +704,8 @@ struct ibmvfc_host {
|
||||
dev_err((vhost)->dev, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define ENTER DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Entering %s\n", __FUNCTION__))
|
||||
#define LEAVE DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Leaving %s\n", __FUNCTION__))
|
||||
#define ENTER DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Entering %s\n", __func__))
|
||||
#define LEAVE DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Leaving %s\n", __func__))
|
||||
|
||||
#ifdef CONFIG_SCSI_IBMVFC_TRACE
|
||||
#define ibmvfc_create_trace_file(kobj, attr) sysfs_create_bin_file(kobj, attr)
|
||||
|
@ -55,7 +55,7 @@
|
||||
/* tmp - will replace with SCSI logging stuff */
|
||||
#define eprintk(fmt, args...) \
|
||||
do { \
|
||||
printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args); \
|
||||
printk("%s(%d) " fmt, __func__, __LINE__, ##args); \
|
||||
} while (0)
|
||||
/* #define dprintk eprintk */
|
||||
#define dprintk(fmt, args...)
|
||||
|
@ -163,7 +163,7 @@ static int imm_proc_info(struct Scsi_Host *host, char *buffer, char **start,
|
||||
|
||||
#if IMM_DEBUG > 0
|
||||
#define imm_fail(x,y) printk("imm: imm_fail(%i) from %s at line %d\n",\
|
||||
y, __FUNCTION__, __LINE__); imm_fail_func(x,y);
|
||||
y, __func__, __LINE__); imm_fail_func(x,y);
|
||||
static inline void
|
||||
imm_fail_func(imm_struct *dev, int error_code)
|
||||
#else
|
||||
|
@ -1403,10 +1403,10 @@ struct ipr_ucode_image_header {
|
||||
}
|
||||
|
||||
#define ipr_trace ipr_dbg("%s: %s: Line: %d\n",\
|
||||
__FILE__, __FUNCTION__, __LINE__)
|
||||
__FILE__, __func__, __LINE__)
|
||||
|
||||
#define ENTER IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Entering %s\n", __FUNCTION__))
|
||||
#define LEAVE IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Leaving %s\n", __FUNCTION__))
|
||||
#define ENTER IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Entering %s\n", __func__))
|
||||
#define LEAVE IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Leaving %s\n", __func__))
|
||||
|
||||
#define ipr_err_separator \
|
||||
ipr_err("----------------------------------------------------------\n")
|
||||
|
@ -74,7 +74,7 @@ static enum ata_completion_errors sas_to_ata_err(struct task_status_struct *ts)
|
||||
case SAS_OPEN_TO:
|
||||
case SAS_OPEN_REJECT:
|
||||
SAS_DPRINTK("%s: Saw error %d. What to do?\n",
|
||||
__FUNCTION__, ts->stat);
|
||||
__func__, ts->stat);
|
||||
return AC_ERR_OTHER;
|
||||
|
||||
case SAS_ABORTED_TASK:
|
||||
@ -115,7 +115,7 @@ static void sas_ata_task_done(struct sas_task *task)
|
||||
} else if (stat->stat != SAM_STAT_GOOD) {
|
||||
ac = sas_to_ata_err(stat);
|
||||
if (ac) {
|
||||
SAS_DPRINTK("%s: SAS error %x\n", __FUNCTION__,
|
||||
SAS_DPRINTK("%s: SAS error %x\n", __func__,
|
||||
stat->stat);
|
||||
/* We saw a SAS error. Send a vague error. */
|
||||
qc->err_mask = ac;
|
||||
@ -244,20 +244,20 @@ static void sas_ata_phy_reset(struct ata_port *ap)
|
||||
res = i->dft->lldd_I_T_nexus_reset(dev);
|
||||
|
||||
if (res != TMF_RESP_FUNC_COMPLETE)
|
||||
SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __FUNCTION__);
|
||||
SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __func__);
|
||||
|
||||
switch (dev->sata_dev.command_set) {
|
||||
case ATA_COMMAND_SET:
|
||||
SAS_DPRINTK("%s: Found ATA device.\n", __FUNCTION__);
|
||||
SAS_DPRINTK("%s: Found ATA device.\n", __func__);
|
||||
ap->link.device[0].class = ATA_DEV_ATA;
|
||||
break;
|
||||
case ATAPI_COMMAND_SET:
|
||||
SAS_DPRINTK("%s: Found ATAPI device.\n", __FUNCTION__);
|
||||
SAS_DPRINTK("%s: Found ATAPI device.\n", __func__);
|
||||
ap->link.device[0].class = ATA_DEV_ATAPI;
|
||||
break;
|
||||
default:
|
||||
SAS_DPRINTK("%s: Unknown SATA command set: %d.\n",
|
||||
__FUNCTION__,
|
||||
__func__,
|
||||
dev->sata_dev.command_set);
|
||||
ap->link.device[0].class = ATA_DEV_UNKNOWN;
|
||||
break;
|
||||
@ -299,7 +299,7 @@ static int sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
|
||||
{
|
||||
struct domain_device *dev = ap->private_data;
|
||||
|
||||
SAS_DPRINTK("STUB %s\n", __FUNCTION__);
|
||||
SAS_DPRINTK("STUB %s\n", __func__);
|
||||
switch (sc_reg_in) {
|
||||
case SCR_STATUS:
|
||||
dev->sata_dev.sstatus = val;
|
||||
@ -324,7 +324,7 @@ static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in,
|
||||
{
|
||||
struct domain_device *dev = ap->private_data;
|
||||
|
||||
SAS_DPRINTK("STUB %s\n", __FUNCTION__);
|
||||
SAS_DPRINTK("STUB %s\n", __func__);
|
||||
switch (sc_reg_in) {
|
||||
case SCR_STATUS:
|
||||
*val = dev->sata_dev.sstatus;
|
||||
|
@ -121,7 +121,7 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
|
||||
break;
|
||||
} else {
|
||||
SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
|
||||
"status 0x%x\n", __FUNCTION__,
|
||||
"status 0x%x\n", __func__,
|
||||
SAS_ADDR(dev->sas_addr),
|
||||
task->task_status.resp,
|
||||
task->task_status.stat);
|
||||
@ -1279,7 +1279,7 @@ static int sas_configure_present(struct domain_device *dev, int phy_id,
|
||||
goto out;
|
||||
} else if (res != SMP_RESP_FUNC_ACC) {
|
||||
SAS_DPRINTK("%s: dev %016llx phy 0x%x index 0x%x "
|
||||
"result 0x%x\n", __FUNCTION__,
|
||||
"result 0x%x\n", __func__,
|
||||
SAS_ADDR(dev->sas_addr), phy_id, i, res);
|
||||
goto out;
|
||||
}
|
||||
@ -1901,7 +1901,7 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
|
||||
|
||||
if (!rsp) {
|
||||
printk("%s: space for a smp response is missing\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1914,20 +1914,20 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
|
||||
if (type != SAS_EDGE_EXPANDER_DEVICE &&
|
||||
type != SAS_FANOUT_EXPANDER_DEVICE) {
|
||||
printk("%s: can we send a smp request to a device?\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev = sas_find_dev_by_rphy(rphy);
|
||||
if (!dev) {
|
||||
printk("%s: fail to find a domain_device?\n", __FUNCTION__);
|
||||
printk("%s: fail to find a domain_device?\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* do we need to support multiple segments? */
|
||||
if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
|
||||
printk("%s: multiple segments req %u %u, rsp %u %u\n",
|
||||
__FUNCTION__, req->bio->bi_vcnt, req->data_len,
|
||||
__func__, req->bio->bi_vcnt, req->data_len,
|
||||
rsp->bio->bi_vcnt, rsp->data_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
|
||||
sas_deform_port(phy);
|
||||
else {
|
||||
SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n",
|
||||
__FUNCTION__, phy->id, phy->port->id,
|
||||
__func__, phy->id, phy->port->id,
|
||||
phy->port->num_phys);
|
||||
return;
|
||||
}
|
||||
@ -78,7 +78,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
|
||||
|
||||
if (i >= sas_ha->num_phys) {
|
||||
printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
@ -343,7 +343,7 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task)
|
||||
flags);
|
||||
SAS_DPRINTK("%s: task 0x%p aborted from "
|
||||
"task_queue\n",
|
||||
__FUNCTION__, task);
|
||||
__func__, task);
|
||||
return TASK_IS_ABORTED;
|
||||
}
|
||||
}
|
||||
@ -351,13 +351,13 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task)
|
||||
}
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task);
|
||||
SAS_DPRINTK("%s: aborting task 0x%p\n", __func__, task);
|
||||
res = si->dft->lldd_abort_task(task);
|
||||
|
||||
spin_lock_irqsave(&task->task_state_lock, flags);
|
||||
if (task->task_state_flags & SAS_TASK_STATE_DONE) {
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
|
||||
SAS_DPRINTK("%s: task 0x%p is done\n", __func__,
|
||||
task);
|
||||
return TASK_IS_DONE;
|
||||
}
|
||||
@ -365,24 +365,24 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task)
|
||||
|
||||
if (res == TMF_RESP_FUNC_COMPLETE) {
|
||||
SAS_DPRINTK("%s: task 0x%p is aborted\n",
|
||||
__FUNCTION__, task);
|
||||
__func__, task);
|
||||
return TASK_IS_ABORTED;
|
||||
} else if (si->dft->lldd_query_task) {
|
||||
SAS_DPRINTK("%s: querying task 0x%p\n",
|
||||
__FUNCTION__, task);
|
||||
__func__, task);
|
||||
res = si->dft->lldd_query_task(task);
|
||||
switch (res) {
|
||||
case TMF_RESP_FUNC_SUCC:
|
||||
SAS_DPRINTK("%s: task 0x%p at LU\n",
|
||||
__FUNCTION__, task);
|
||||
__func__, task);
|
||||
return TASK_IS_AT_LU;
|
||||
case TMF_RESP_FUNC_COMPLETE:
|
||||
SAS_DPRINTK("%s: task 0x%p not at LU\n",
|
||||
__FUNCTION__, task);
|
||||
__func__, task);
|
||||
return TASK_IS_NOT_AT_LU;
|
||||
case TMF_RESP_FUNC_FAILED:
|
||||
SAS_DPRINTK("%s: task 0x%p failed to abort\n",
|
||||
__FUNCTION__, task);
|
||||
__func__, task);
|
||||
return TASK_ABORT_FAILED;
|
||||
}
|
||||
|
||||
@ -545,7 +545,7 @@ Again:
|
||||
|
||||
if (need_reset) {
|
||||
SAS_DPRINTK("%s: task 0x%p requests reset\n",
|
||||
__FUNCTION__, task);
|
||||
__func__, task);
|
||||
goto reset;
|
||||
}
|
||||
|
||||
@ -556,13 +556,13 @@ Again:
|
||||
|
||||
switch (res) {
|
||||
case TASK_IS_DONE:
|
||||
SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
|
||||
SAS_DPRINTK("%s: task 0x%p is done\n", __func__,
|
||||
task);
|
||||
sas_eh_finish_cmd(cmd);
|
||||
continue;
|
||||
case TASK_IS_ABORTED:
|
||||
SAS_DPRINTK("%s: task 0x%p is aborted\n",
|
||||
__FUNCTION__, task);
|
||||
__func__, task);
|
||||
sas_eh_finish_cmd(cmd);
|
||||
continue;
|
||||
case TASK_IS_AT_LU:
|
||||
@ -633,7 +633,7 @@ Again:
|
||||
}
|
||||
return list_empty(work_q);
|
||||
clear_q:
|
||||
SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__);
|
||||
SAS_DPRINTK("--- Exit %s -- clear_q\n", __func__);
|
||||
list_for_each_entry_safe(cmd, n, work_q, eh_entry)
|
||||
sas_eh_finish_cmd(cmd);
|
||||
|
||||
@ -650,7 +650,7 @@ void sas_scsi_recover_host(struct Scsi_Host *shost)
|
||||
list_splice_init(&shost->eh_cmd_q, &eh_work_q);
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
|
||||
SAS_DPRINTK("Enter %s\n", __FUNCTION__);
|
||||
SAS_DPRINTK("Enter %s\n", __func__);
|
||||
/*
|
||||
* Deal with commands that still have SAS tasks (i.e. they didn't
|
||||
* complete via the normal sas_task completion mechanism)
|
||||
@ -669,7 +669,7 @@ void sas_scsi_recover_host(struct Scsi_Host *shost)
|
||||
|
||||
out:
|
||||
scsi_eh_flush_done_q(&ha->eh_done_q);
|
||||
SAS_DPRINTK("--- Exit %s\n", __FUNCTION__);
|
||||
SAS_DPRINTK("--- Exit %s\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -990,7 +990,7 @@ int __sas_task_abort(struct sas_task *task)
|
||||
if (task->task_state_flags & SAS_TASK_STATE_ABORTED ||
|
||||
task->task_state_flags & SAS_TASK_STATE_DONE) {
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
SAS_DPRINTK("%s: Task %p already finished.\n", __FUNCTION__,
|
||||
SAS_DPRINTK("%s: Task %p already finished.\n", __func__,
|
||||
task);
|
||||
return 0;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ enum srp_task_attributes {
|
||||
/* tmp - will replace with SCSI logging stuff */
|
||||
#define eprintk(fmt, args...) \
|
||||
do { \
|
||||
printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args); \
|
||||
printk("%s(%d) " fmt, __func__, __LINE__, ##args); \
|
||||
} while (0)
|
||||
/* #define dprintk eprintk */
|
||||
#define dprintk(fmt, args...)
|
||||
|
@ -2083,7 +2083,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
|
||||
if (iocbq_entry == NULL) {
|
||||
printk(KERN_ERR "%s: only allocated %d iocbs of "
|
||||
"expected %d count. Unloading driver.\n",
|
||||
__FUNCTION__, i, LPFC_IOCB_LIST_CNT);
|
||||
__func__, i, LPFC_IOCB_LIST_CNT);
|
||||
error = -ENOMEM;
|
||||
goto out_free_iocbq;
|
||||
}
|
||||
@ -2093,7 +2093,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
|
||||
kfree (iocbq_entry);
|
||||
printk(KERN_ERR "%s: failed to allocate IOTAG. "
|
||||
"Unloading driver.\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
error = -ENOMEM;
|
||||
goto out_free_iocbq;
|
||||
}
|
||||
|
@ -341,7 +341,7 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
|
||||
if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) {
|
||||
printk(KERN_ERR "%s: Too many sg segments from "
|
||||
"dma_map_sg. Config %d, seg_cnt %d",
|
||||
__FUNCTION__, phba->cfg_sg_seg_cnt,
|
||||
__func__, phba->cfg_sg_seg_cnt,
|
||||
lpfc_cmd->seg_cnt);
|
||||
scsi_dma_unmap(scsi_cmnd);
|
||||
return 1;
|
||||
|
@ -219,7 +219,7 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
|
||||
case CMD_IOCB_LOGENTRY_CN:
|
||||
case CMD_IOCB_LOGENTRY_ASYNC_CN:
|
||||
printk("%s - Unhandled SLI-3 Command x%x\n",
|
||||
__FUNCTION__, iocb_cmnd);
|
||||
__func__, iocb_cmnd);
|
||||
type = LPFC_UNKNOWN_IOCB;
|
||||
break;
|
||||
default:
|
||||
@ -1715,7 +1715,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
|
||||
rspiocbp = __lpfc_sli_get_iocbq(phba);
|
||||
if (rspiocbp == NULL) {
|
||||
printk(KERN_ERR "%s: out of buffers! Failing "
|
||||
"completion.\n", __FUNCTION__);
|
||||
"completion.\n", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3793,7 +3793,7 @@ lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport,
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "%s: Unknown context cmd type, value %d\n",
|
||||
__FUNCTION__, ctx_cmd);
|
||||
__func__, ctx_cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -265,7 +265,7 @@ typedef struct {
|
||||
#define ASSERT(expression) \
|
||||
if (!(expression)) { \
|
||||
ASSERT_ACTION("assertion failed:(%s), file: %s, line: %d:%s\n", \
|
||||
#expression, __FILE__, __LINE__, __FUNCTION__); \
|
||||
#expression, __FILE__, __LINE__, __func__); \
|
||||
}
|
||||
#else
|
||||
#define ASSERT(expression)
|
||||
|
@ -458,7 +458,7 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
|
||||
if (adapter == NULL) {
|
||||
con_log(CL_ANN, (KERN_WARNING
|
||||
"megaraid: out of memory, %s %d.\n", __FUNCTION__, __LINE__));
|
||||
"megaraid: out of memory, %s %d.\n", __func__, __LINE__));
|
||||
|
||||
goto out_probe_one;
|
||||
}
|
||||
@ -1002,7 +1002,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
|
||||
|
||||
if (!raid_dev->una_mbox64) {
|
||||
con_log(CL_ANN, (KERN_WARNING
|
||||
"megaraid: out of memory, %s %d\n", __FUNCTION__,
|
||||
"megaraid: out of memory, %s %d\n", __func__,
|
||||
__LINE__));
|
||||
return -1;
|
||||
}
|
||||
@ -1030,7 +1030,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
|
||||
if (!adapter->ibuf) {
|
||||
|
||||
con_log(CL_ANN, (KERN_WARNING
|
||||
"megaraid: out of memory, %s %d\n", __FUNCTION__,
|
||||
"megaraid: out of memory, %s %d\n", __func__,
|
||||
__LINE__));
|
||||
|
||||
goto out_free_common_mbox;
|
||||
@ -1052,7 +1052,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
|
||||
|
||||
if (adapter->kscb_list == NULL) {
|
||||
con_log(CL_ANN, (KERN_WARNING
|
||||
"megaraid: out of memory, %s %d\n", __FUNCTION__,
|
||||
"megaraid: out of memory, %s %d\n", __func__,
|
||||
__LINE__));
|
||||
goto out_free_ibuf;
|
||||
}
|
||||
@ -1060,7 +1060,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
|
||||
// memory allocation for our command packets
|
||||
if (megaraid_mbox_setup_dma_pools(adapter) != 0) {
|
||||
con_log(CL_ANN, (KERN_WARNING
|
||||
"megaraid: out of memory, %s %d\n", __FUNCTION__,
|
||||
"megaraid: out of memory, %s %d\n", __func__,
|
||||
__LINE__));
|
||||
goto out_free_scb_list;
|
||||
}
|
||||
@ -2981,7 +2981,7 @@ megaraid_mbox_product_info(adapter_t *adapter)
|
||||
|
||||
if (pinfo == NULL) {
|
||||
con_log(CL_ANN, (KERN_WARNING
|
||||
"megaraid: out of memory, %s %d\n", __FUNCTION__,
|
||||
"megaraid: out of memory, %s %d\n", __func__,
|
||||
__LINE__));
|
||||
|
||||
return -1;
|
||||
@ -3508,7 +3508,7 @@ megaraid_cmm_register(adapter_t *adapter)
|
||||
|
||||
if (adapter->uscb_list == NULL) {
|
||||
con_log(CL_ANN, (KERN_WARNING
|
||||
"megaraid: out of memory, %s %d\n", __FUNCTION__,
|
||||
"megaraid: out of memory, %s %d\n", __func__,
|
||||
__LINE__));
|
||||
return -1;
|
||||
}
|
||||
@ -3879,7 +3879,7 @@ megaraid_sysfs_alloc_resources(adapter_t *adapter)
|
||||
!raid_dev->sysfs_buffer) {
|
||||
|
||||
con_log(CL_ANN, (KERN_WARNING
|
||||
"megaraid: out of memory, %s %d\n", __FUNCTION__,
|
||||
"megaraid: out of memory, %s %d\n", __func__,
|
||||
__LINE__));
|
||||
|
||||
rval = -ENOMEM;
|
||||
|
@ -929,7 +929,7 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp)
|
||||
!adapter->pthru_dma_pool) {
|
||||
|
||||
con_log(CL_ANN, (KERN_WARNING
|
||||
"megaraid cmm: out of memory, %s %d\n", __FUNCTION__,
|
||||
"megaraid cmm: out of memory, %s %d\n", __func__,
|
||||
__LINE__));
|
||||
|
||||
rval = (-ENOMEM);
|
||||
@ -957,7 +957,7 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp)
|
||||
|
||||
con_log(CL_ANN, (KERN_WARNING
|
||||
"megaraid cmm: out of memory, %s %d\n",
|
||||
__FUNCTION__, __LINE__));
|
||||
__func__, __LINE__));
|
||||
|
||||
rval = (-ENOMEM);
|
||||
|
||||
|
@ -299,9 +299,9 @@ static struct scsi_host_template nsp32_template = {
|
||||
#else
|
||||
# define NSP32_DEBUG_MASK 0xffffff
|
||||
# define nsp32_msg(type, args...) \
|
||||
nsp32_message (__FUNCTION__, __LINE__, (type), args)
|
||||
nsp32_message (__func__, __LINE__, (type), args)
|
||||
# define nsp32_dbg(mask, args...) \
|
||||
nsp32_dmessage(__FUNCTION__, __LINE__, (mask), args)
|
||||
nsp32_dmessage(__func__, __LINE__, (mask), args)
|
||||
#endif
|
||||
|
||||
#define NSP32_DEBUG_QUEUECOMMAND BIT(0)
|
||||
|
@ -88,7 +88,7 @@ static void print_commandk (unsigned char *command)
|
||||
int i,s;
|
||||
// printk(KERN_DEBUG);
|
||||
print_opcodek(command[0]);
|
||||
/*printk(KERN_DEBUG "%s ", __FUNCTION__);*/
|
||||
/*printk(KERN_DEBUG "%s ", __func__);*/
|
||||
if ((command[0] >> 5) == 6 ||
|
||||
(command[0] >> 5) == 7 ) {
|
||||
s = 12; /* vender specific */
|
||||
|
@ -107,9 +107,9 @@ static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
|
||||
#else
|
||||
# define NSP_DEBUG_MASK 0xffffff
|
||||
# define nsp_msg(type, args...) \
|
||||
nsp_cs_message (__FUNCTION__, __LINE__, (type), args)
|
||||
nsp_cs_message (__func__, __LINE__, (type), args)
|
||||
# define nsp_dbg(mask, args...) \
|
||||
nsp_cs_dmessage(__FUNCTION__, __LINE__, (mask), args)
|
||||
nsp_cs_dmessage(__func__, __LINE__, (mask), args)
|
||||
#endif
|
||||
|
||||
#define NSP_DEBUG_QUEUECOMMAND BIT(0)
|
||||
|
@ -90,7 +90,7 @@ static void print_commandk (unsigned char *command)
|
||||
int i, s;
|
||||
printk(KERN_DEBUG);
|
||||
print_opcodek(command[0]);
|
||||
/*printk(KERN_DEBUG "%s ", __FUNCTION__);*/
|
||||
/*printk(KERN_DEBUG "%s ", __func__);*/
|
||||
if ((command[0] >> 5) == 6 ||
|
||||
(command[0] >> 5) == 7 ) {
|
||||
s = 12; /* vender specific */
|
||||
|
@ -171,7 +171,7 @@ static int device_check(ppa_struct *dev);
|
||||
|
||||
#if PPA_DEBUG > 0
|
||||
#define ppa_fail(x,y) printk("ppa: ppa_fail(%i) from %s at line %d\n",\
|
||||
y, __FUNCTION__, __LINE__); ppa_fail_func(x,y);
|
||||
y, __func__, __LINE__); ppa_fail_func(x,y);
|
||||
static inline void ppa_fail_func(ppa_struct *dev, int error_code)
|
||||
#else
|
||||
static inline void ppa_fail(ppa_struct *dev, int error_code)
|
||||
|
@ -1695,7 +1695,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha)
|
||||
risc_code_size = *ql1280_board_tbl[ha->devnum].fwlen;
|
||||
|
||||
dprintk(1, "%s: DMA RISC code (%i) words\n",
|
||||
__FUNCTION__, risc_code_size);
|
||||
__func__, risc_code_size);
|
||||
|
||||
num = 0;
|
||||
while (risc_code_size > 0) {
|
||||
@ -1721,7 +1721,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha)
|
||||
mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff;
|
||||
mb[6] = pci_dma_hi32(ha->request_dma) >> 16;
|
||||
dprintk(2, "%s: op=%d 0x%p = 0x%4x,0x%4x,0x%4x,0x%4x\n",
|
||||
__FUNCTION__, mb[0],
|
||||
__func__, mb[0],
|
||||
(void *)(long)ha->request_dma,
|
||||
mb[6], mb[7], mb[2], mb[3]);
|
||||
err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 |
|
||||
@ -1753,10 +1753,10 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha)
|
||||
if (tbuf[i] != sp[i] && warn++ < 10) {
|
||||
printk(KERN_ERR "%s: FW compare error @ "
|
||||
"byte(0x%x) loop#=%x\n",
|
||||
__FUNCTION__, i, num);
|
||||
__func__, i, num);
|
||||
printk(KERN_ERR "%s: FWbyte=%x "
|
||||
"FWfromChip=%x\n",
|
||||
__FUNCTION__, sp[i], tbuf[i]);
|
||||
__func__, sp[i], tbuf[i]);
|
||||
/*break; */
|
||||
}
|
||||
}
|
||||
@ -1781,7 +1781,7 @@ qla1280_start_firmware(struct scsi_qla_host *ha)
|
||||
int err;
|
||||
|
||||
dprintk(1, "%s: Verifying checksum of loaded RISC code.\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
|
||||
/* Verify checksum of loaded RISC code. */
|
||||
mb[0] = MBC_VERIFY_CHECKSUM;
|
||||
@ -1794,7 +1794,7 @@ qla1280_start_firmware(struct scsi_qla_host *ha)
|
||||
}
|
||||
|
||||
/* Start firmware execution. */
|
||||
dprintk(1, "%s: start firmware running.\n", __FUNCTION__);
|
||||
dprintk(1, "%s: start firmware running.\n", __func__);
|
||||
mb[0] = MBC_EXECUTE_FIRMWARE;
|
||||
mb[1] = *ql1280_board_tbl[ha->devnum].fwstart;
|
||||
err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]);
|
||||
|
@ -20,18 +20,12 @@ qla2x00_sysfs_read_fw_dump(struct kobject *kobj,
|
||||
{
|
||||
struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
|
||||
struct device, kobj)));
|
||||
char *rbuf = (char *)ha->fw_dump;
|
||||
|
||||
if (ha->fw_dump_reading == 0)
|
||||
return 0;
|
||||
if (off > ha->fw_dump_len)
|
||||
return 0;
|
||||
if (off + count > ha->fw_dump_len)
|
||||
count = ha->fw_dump_len - off;
|
||||
|
||||
memcpy(buf, &rbuf[off], count);
|
||||
|
||||
return (count);
|
||||
return memory_read_from_buffer(buf, count, &off, ha->fw_dump,
|
||||
ha->fw_dump_len);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
@ -94,20 +88,13 @@ qla2x00_sysfs_read_nvram(struct kobject *kobj,
|
||||
{
|
||||
struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
|
||||
struct device, kobj)));
|
||||
int size = ha->nvram_size;
|
||||
char *nvram_cache = ha->nvram;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN) || off > size || count == 0)
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return 0;
|
||||
if (off + count > size) {
|
||||
size -= off;
|
||||
count = size;
|
||||
}
|
||||
|
||||
/* Read NVRAM data from cache. */
|
||||
memcpy(buf, &nvram_cache[off], count);
|
||||
|
||||
return count;
|
||||
return memory_read_from_buffer(buf, count, &off, ha->nvram,
|
||||
ha->nvram_size);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
@ -175,14 +162,9 @@ qla2x00_sysfs_read_optrom(struct kobject *kobj,
|
||||
|
||||
if (ha->optrom_state != QLA_SREADING)
|
||||
return 0;
|
||||
if (off > ha->optrom_region_size)
|
||||
return 0;
|
||||
if (off + count > ha->optrom_region_size)
|
||||
count = ha->optrom_region_size - off;
|
||||
|
||||
memcpy(buf, &ha->optrom_buffer[off], count);
|
||||
|
||||
return count;
|
||||
return memory_read_from_buffer(buf, count, &off, ha->optrom_buffer,
|
||||
ha->optrom_region_size);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
@ -374,20 +356,12 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj,
|
||||
{
|
||||
struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
|
||||
struct device, kobj)));
|
||||
int size = ha->vpd_size;
|
||||
char *vpd_cache = ha->vpd;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN) || off > size || count == 0)
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return 0;
|
||||
if (off + count > size) {
|
||||
size -= off;
|
||||
count = size;
|
||||
}
|
||||
|
||||
/* Read NVRAM data from cache. */
|
||||
memcpy(buf, &vpd_cache[off], count);
|
||||
|
||||
return count;
|
||||
return memory_read_from_buffer(buf, count, &off, ha->vpd, ha->vpd_size);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
@ -557,8 +531,10 @@ qla2x00_serial_num_show(struct device *dev, struct device_attribute *attr,
|
||||
scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
|
||||
uint32_t sn;
|
||||
|
||||
if (IS_FWI2_CAPABLE(ha))
|
||||
return snprintf(buf, PAGE_SIZE, "\n");
|
||||
if (IS_FWI2_CAPABLE(ha)) {
|
||||
qla2xxx_get_vpd_field(ha, "SN", buf, PAGE_SIZE);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", buf);
|
||||
}
|
||||
|
||||
sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1;
|
||||
return snprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000,
|
||||
@ -809,6 +785,16 @@ qla2x00_optrom_fw_version_show(struct device *dev,
|
||||
ha->fw_revision[3]);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qla2x00_total_isp_aborts_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
ha->qla_stats.total_isp_aborts);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL);
|
||||
static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
|
||||
static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
|
||||
@ -831,6 +817,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(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show,
|
||||
NULL);
|
||||
|
||||
struct device_attribute *qla2x00_host_attrs[] = {
|
||||
&dev_attr_driver_version,
|
||||
@ -849,6 +837,7 @@ struct device_attribute *qla2x00_host_attrs[] = {
|
||||
&dev_attr_optrom_efi_version,
|
||||
&dev_attr_optrom_fcode_version,
|
||||
&dev_attr_optrom_fw_version,
|
||||
&dev_attr_total_isp_aborts,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -972,26 +961,39 @@ qla2x00_get_starget_port_id(struct scsi_target *starget)
|
||||
}
|
||||
|
||||
static void
|
||||
qla2x00_get_rport_loss_tmo(struct fc_rport *rport)
|
||||
qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
|
||||
{
|
||||
struct Scsi_Host *host = rport_to_shost(rport);
|
||||
scsi_qla_host_t *ha = shost_priv(host);
|
||||
|
||||
rport->dev_loss_tmo = ha->port_down_retry_count + 5;
|
||||
if (timeout)
|
||||
rport->dev_loss_tmo = timeout;
|
||||
else
|
||||
rport->dev_loss_tmo = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
|
||||
qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport)
|
||||
{
|
||||
struct Scsi_Host *host = rport_to_shost(rport);
|
||||
scsi_qla_host_t *ha = shost_priv(host);
|
||||
fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
|
||||
|
||||
if (timeout)
|
||||
ha->port_down_retry_count = timeout;
|
||||
else
|
||||
ha->port_down_retry_count = 1;
|
||||
qla2x00_abort_fcport_cmds(fcport);
|
||||
|
||||
rport->dev_loss_tmo = ha->port_down_retry_count + 5;
|
||||
/*
|
||||
* Transport has effectively 'deleted' the rport, clear
|
||||
* all local references.
|
||||
*/
|
||||
spin_lock_irq(host->host_lock);
|
||||
fcport->rport = NULL;
|
||||
*((fc_port_t **)rport->dd_data) = NULL;
|
||||
spin_unlock_irq(host->host_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
qla2x00_terminate_rport_io(struct fc_rport *rport)
|
||||
{
|
||||
fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
|
||||
|
||||
qla2x00_abort_fcport_cmds(fcport);
|
||||
scsi_target_unblock(&rport->dev);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1045,6 +1047,7 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
|
||||
pfc_host_stat->invalid_tx_word_count = stats->inval_xmit_word_cnt;
|
||||
pfc_host_stat->invalid_crc_count = stats->inval_crc_cnt;
|
||||
if (IS_FWI2_CAPABLE(ha)) {
|
||||
pfc_host_stat->lip_count = stats->lip_cnt;
|
||||
pfc_host_stat->tx_frames = stats->tx_frames;
|
||||
pfc_host_stat->rx_frames = stats->rx_frames;
|
||||
pfc_host_stat->dumped_frames = stats->dumped_frames;
|
||||
@ -1173,17 +1176,16 @@ vport_create_failed_2:
|
||||
static int
|
||||
qla24xx_vport_delete(struct fc_vport *fc_vport)
|
||||
{
|
||||
scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
|
||||
scsi_qla_host_t *vha = fc_vport->dd_data;
|
||||
scsi_qla_host_t *pha = to_qla_parent(vha);
|
||||
|
||||
while (test_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags) ||
|
||||
test_bit(FCPORT_UPDATE_NEEDED, &pha->dpc_flags))
|
||||
msleep(1000);
|
||||
|
||||
qla24xx_disable_vp(vha);
|
||||
qla24xx_deallocate_vp_id(vha);
|
||||
|
||||
mutex_lock(&ha->vport_lock);
|
||||
ha->cur_vport_count--;
|
||||
clear_bit(vha->vp_idx, ha->vp_idx_map);
|
||||
mutex_unlock(&ha->vport_lock);
|
||||
|
||||
kfree(vha->node_name);
|
||||
kfree(vha->port_name);
|
||||
|
||||
@ -1248,11 +1250,12 @@ struct fc_function_template qla2xxx_transport_functions = {
|
||||
.get_starget_port_id = qla2x00_get_starget_port_id,
|
||||
.show_starget_port_id = 1,
|
||||
|
||||
.get_rport_dev_loss_tmo = qla2x00_get_rport_loss_tmo,
|
||||
.set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
|
||||
.show_rport_dev_loss_tmo = 1,
|
||||
|
||||
.issue_fc_host_lip = qla2x00_issue_lip,
|
||||
.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,
|
||||
|
||||
.vport_create = qla24xx_vport_create,
|
||||
@ -1291,11 +1294,12 @@ struct fc_function_template qla2xxx_transport_vport_functions = {
|
||||
.get_starget_port_id = qla2x00_get_starget_port_id,
|
||||
.show_starget_port_id = 1,
|
||||
|
||||
.get_rport_dev_loss_tmo = qla2x00_get_rport_loss_tmo,
|
||||
.set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
|
||||
.show_rport_dev_loss_tmo = 1,
|
||||
|
||||
.issue_fc_host_lip = qla2x00_issue_lip,
|
||||
.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,
|
||||
};
|
||||
|
||||
|
@ -216,7 +216,7 @@ qla24xx_soft_reset(scsi_qla_host_t *ha)
|
||||
|
||||
static int
|
||||
qla2xxx_dump_ram(scsi_qla_host_t *ha, uint32_t addr, uint16_t *ram,
|
||||
uint16_t ram_words, void **nxt)
|
||||
uint32_t ram_words, void **nxt)
|
||||
{
|
||||
int rval;
|
||||
uint32_t cnt, stat, timer, words, idx;
|
||||
|
@ -864,7 +864,8 @@ struct link_statistics {
|
||||
uint32_t prim_seq_err_cnt;
|
||||
uint32_t inval_xmit_word_cnt;
|
||||
uint32_t inval_crc_cnt;
|
||||
uint32_t unused1[0x1b];
|
||||
uint32_t lip_cnt;
|
||||
uint32_t unused1[0x1a];
|
||||
uint32_t tx_frames;
|
||||
uint32_t rx_frames;
|
||||
uint32_t dumped_frames;
|
||||
@ -1544,7 +1545,6 @@ typedef struct fc_port {
|
||||
int login_retry;
|
||||
atomic_t port_down_timer;
|
||||
|
||||
spinlock_t rport_lock;
|
||||
struct fc_rport *rport, *drport;
|
||||
u32 supported_classes;
|
||||
|
||||
@ -2155,6 +2155,10 @@ struct qla_chip_state_84xx {
|
||||
uint32_t gold_fw_version;
|
||||
};
|
||||
|
||||
struct qla_statistics {
|
||||
uint32_t total_isp_aborts;
|
||||
};
|
||||
|
||||
/*
|
||||
* Linux Host Adapter structure
|
||||
*/
|
||||
@ -2166,7 +2170,6 @@ typedef struct scsi_qla_host {
|
||||
struct pci_dev *pdev;
|
||||
|
||||
unsigned long host_no;
|
||||
unsigned long instance;
|
||||
|
||||
volatile struct {
|
||||
uint32_t init_done :1;
|
||||
@ -2515,7 +2518,7 @@ typedef struct scsi_qla_host {
|
||||
|
||||
uint8_t model_number[16+1];
|
||||
#define BINZERO "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
char *model_desc;
|
||||
char model_desc[80];
|
||||
uint8_t adapter_id[16+1];
|
||||
|
||||
uint8_t *node_name;
|
||||
@ -2596,6 +2599,7 @@ typedef struct scsi_qla_host {
|
||||
int cur_vport_count;
|
||||
|
||||
struct qla_chip_state_84xx *cs84xx;
|
||||
struct qla_statistics qla_stats;
|
||||
} scsi_qla_host_t;
|
||||
|
||||
|
||||
|
@ -62,7 +62,7 @@ extern int ql2xfdmienable;
|
||||
extern int ql2xallocfwdump;
|
||||
extern int ql2xextended_error_logging;
|
||||
extern int ql2xqfullrampup;
|
||||
extern int num_hosts;
|
||||
extern int ql2xiidmaenable;
|
||||
|
||||
extern int qla2x00_loop_reset(scsi_qla_host_t *);
|
||||
extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
|
||||
@ -71,6 +71,8 @@ extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum
|
||||
extern int qla2x00_post_hwe_work(struct scsi_qla_host *, uint16_t , uint16_t,
|
||||
uint16_t, uint16_t);
|
||||
|
||||
extern void qla2x00_abort_fcport_cmds(fc_port_t *);
|
||||
|
||||
/*
|
||||
* Global Functions in qla_mid.c source file.
|
||||
*/
|
||||
@ -312,6 +314,7 @@ extern int qla2xxx_hw_event_log(scsi_qla_host_t *, uint16_t , uint16_t,
|
||||
uint16_t, uint16_t);
|
||||
|
||||
extern void qla2xxx_get_flash_info(scsi_qla_host_t *);
|
||||
extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t);
|
||||
|
||||
/*
|
||||
* Global Function Prototypes in qla_dbg.c source file.
|
||||
|
@ -1661,6 +1661,12 @@ qla2x00_fdmi_register(scsi_qla_host_t *ha)
|
||||
{
|
||||
int rval;
|
||||
|
||||
if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
|
||||
DEBUG2(printk("scsi(%ld): FDMI unsupported on "
|
||||
"ISP2100/ISP2200.\n", ha->host_no));
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
rval = qla2x00_mgmt_svr_login(ha);
|
||||
if (rval)
|
||||
return rval;
|
||||
|
@ -334,6 +334,8 @@ static int
|
||||
qla2x00_isp_firmware(scsi_qla_host_t *ha)
|
||||
{
|
||||
int rval;
|
||||
uint16_t loop_id, topo, sw_cap;
|
||||
uint8_t domain, area, al_pa;
|
||||
|
||||
/* Assume loading risc code */
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
@ -345,6 +347,11 @@ qla2x00_isp_firmware(scsi_qla_host_t *ha)
|
||||
|
||||
/* Verify checksum of loaded RISC code. */
|
||||
rval = qla2x00_verify_checksum(ha, ha->fw_srisc_address);
|
||||
if (rval == QLA_SUCCESS) {
|
||||
/* And, verify we are not in ROM code. */
|
||||
rval = qla2x00_get_adapter_id(ha, &loop_id, &al_pa,
|
||||
&area, &domain, &topo, &sw_cap);
|
||||
}
|
||||
}
|
||||
|
||||
if (rval) {
|
||||
@ -722,7 +729,7 @@ qla24xx_chip_diag(scsi_qla_host_t *ha)
|
||||
/* Perform RISC reset. */
|
||||
qla24xx_reset_risc(ha);
|
||||
|
||||
ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024;
|
||||
ha->fw_transfer_size = REQUEST_ENTRY_SIZE * ha->request_q_length;
|
||||
|
||||
rval = qla2x00_mbx_reg_test(ha);
|
||||
if (rval) {
|
||||
@ -768,6 +775,38 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
|
||||
mem_size = (ha->fw_memory_size - 0x100000 + 1) *
|
||||
sizeof(uint32_t);
|
||||
|
||||
/* Allocate memory for Fibre Channel Event Buffer. */
|
||||
if (!IS_QLA25XX(ha))
|
||||
goto try_eft;
|
||||
|
||||
tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
|
||||
GFP_KERNEL);
|
||||
if (!tc) {
|
||||
qla_printk(KERN_WARNING, ha, "Unable to allocate "
|
||||
"(%d KB) for FCE.\n", FCE_SIZE / 1024);
|
||||
goto try_eft;
|
||||
}
|
||||
|
||||
memset(tc, 0, FCE_SIZE);
|
||||
rval = qla2x00_enable_fce_trace(ha, tc_dma, FCE_NUM_BUFFERS,
|
||||
ha->fce_mb, &ha->fce_bufs);
|
||||
if (rval) {
|
||||
qla_printk(KERN_WARNING, ha, "Unable to initialize "
|
||||
"FCE (%d).\n", rval);
|
||||
dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc,
|
||||
tc_dma);
|
||||
ha->flags.fce_enabled = 0;
|
||||
goto try_eft;
|
||||
}
|
||||
|
||||
qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n",
|
||||
FCE_SIZE / 1024);
|
||||
|
||||
fce_size = sizeof(struct qla2xxx_fce_chain) + EFT_SIZE;
|
||||
ha->flags.fce_enabled = 1;
|
||||
ha->fce_dma = tc_dma;
|
||||
ha->fce = tc;
|
||||
try_eft:
|
||||
/* Allocate memory for Extended Trace Buffer. */
|
||||
tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
|
||||
GFP_KERNEL);
|
||||
@ -793,38 +832,6 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
|
||||
eft_size = EFT_SIZE;
|
||||
ha->eft_dma = tc_dma;
|
||||
ha->eft = tc;
|
||||
|
||||
/* Allocate memory for Fibre Channel Event Buffer. */
|
||||
if (!IS_QLA25XX(ha))
|
||||
goto cont_alloc;
|
||||
|
||||
tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
|
||||
GFP_KERNEL);
|
||||
if (!tc) {
|
||||
qla_printk(KERN_WARNING, ha, "Unable to allocate "
|
||||
"(%d KB) for FCE.\n", FCE_SIZE / 1024);
|
||||
goto cont_alloc;
|
||||
}
|
||||
|
||||
memset(tc, 0, FCE_SIZE);
|
||||
rval = qla2x00_enable_fce_trace(ha, tc_dma, FCE_NUM_BUFFERS,
|
||||
ha->fce_mb, &ha->fce_bufs);
|
||||
if (rval) {
|
||||
qla_printk(KERN_WARNING, ha, "Unable to initialize "
|
||||
"FCE (%d).\n", rval);
|
||||
dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc,
|
||||
tc_dma);
|
||||
ha->flags.fce_enabled = 0;
|
||||
goto cont_alloc;
|
||||
}
|
||||
|
||||
qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n",
|
||||
FCE_SIZE / 1024);
|
||||
|
||||
fce_size = sizeof(struct qla2xxx_fce_chain) + EFT_SIZE;
|
||||
ha->flags.fce_enabled = 1;
|
||||
ha->fce_dma = tc_dma;
|
||||
ha->fce = tc;
|
||||
}
|
||||
cont_alloc:
|
||||
req_q_size = ha->request_q_length * sizeof(request_t);
|
||||
@ -1501,18 +1508,25 @@ qla2x00_set_model_info(scsi_qla_host_t *ha, uint8_t *model, size_t len, char *de
|
||||
index = (ha->pdev->subsystem_device & 0xff);
|
||||
if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
|
||||
index < QLA_MODEL_NAMES)
|
||||
ha->model_desc = qla2x00_model_name[index * 2 + 1];
|
||||
strncpy(ha->model_desc,
|
||||
qla2x00_model_name[index * 2 + 1],
|
||||
sizeof(ha->model_desc) - 1);
|
||||
} else {
|
||||
index = (ha->pdev->subsystem_device & 0xff);
|
||||
if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
|
||||
index < QLA_MODEL_NAMES) {
|
||||
strcpy(ha->model_number,
|
||||
qla2x00_model_name[index * 2]);
|
||||
ha->model_desc = qla2x00_model_name[index * 2 + 1];
|
||||
strncpy(ha->model_desc,
|
||||
qla2x00_model_name[index * 2 + 1],
|
||||
sizeof(ha->model_desc) - 1);
|
||||
} else {
|
||||
strcpy(ha->model_number, def);
|
||||
}
|
||||
}
|
||||
if (IS_FWI2_CAPABLE(ha))
|
||||
qla2xxx_get_vpd_field(ha, "\x82", ha->model_desc,
|
||||
sizeof(ha->model_desc));
|
||||
}
|
||||
|
||||
/* On sparc systems, obtain port and node WWN from firmware
|
||||
@ -1864,12 +1878,11 @@ qla2x00_rport_del(void *data)
|
||||
{
|
||||
fc_port_t *fcport = data;
|
||||
struct fc_rport *rport;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&fcport->rport_lock, flags);
|
||||
spin_lock_irq(fcport->ha->host->host_lock);
|
||||
rport = fcport->drport;
|
||||
fcport->drport = NULL;
|
||||
spin_unlock_irqrestore(&fcport->rport_lock, flags);
|
||||
spin_unlock_irq(fcport->ha->host->host_lock);
|
||||
if (rport)
|
||||
fc_remote_port_delete(rport);
|
||||
}
|
||||
@ -1898,7 +1911,6 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags)
|
||||
atomic_set(&fcport->state, FCS_UNCONFIGURED);
|
||||
fcport->flags = FCF_RLC_SUPPORT;
|
||||
fcport->supported_classes = FC_COS_UNSPECIFIED;
|
||||
spin_lock_init(&fcport->rport_lock);
|
||||
|
||||
return fcport;
|
||||
}
|
||||
@ -2007,8 +2019,10 @@ qla2x00_configure_loop(scsi_qla_host_t *ha)
|
||||
if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
|
||||
if (test_bit(LOCAL_LOOP_UPDATE, &save_flags))
|
||||
set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
|
||||
if (test_bit(RSCN_UPDATE, &save_flags))
|
||||
if (test_bit(RSCN_UPDATE, &save_flags)) {
|
||||
ha->flags.rscn_queue_overflow = 1;
|
||||
set_bit(RSCN_UPDATE, &ha->dpc_flags);
|
||||
}
|
||||
}
|
||||
|
||||
return (rval);
|
||||
@ -2243,28 +2257,24 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport)
|
||||
{
|
||||
struct fc_rport_identifiers rport_ids;
|
||||
struct fc_rport *rport;
|
||||
unsigned long flags;
|
||||
|
||||
if (fcport->drport)
|
||||
qla2x00_rport_del(fcport);
|
||||
if (fcport->rport)
|
||||
return;
|
||||
|
||||
rport_ids.node_name = wwn_to_u64(fcport->node_name);
|
||||
rport_ids.port_name = wwn_to_u64(fcport->port_name);
|
||||
rport_ids.port_id = fcport->d_id.b.domain << 16 |
|
||||
fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
|
||||
rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
|
||||
rport = fc_remote_port_add(ha->host, 0, &rport_ids);
|
||||
fcport->rport = rport = fc_remote_port_add(ha->host, 0, &rport_ids);
|
||||
if (!rport) {
|
||||
qla_printk(KERN_WARNING, ha,
|
||||
"Unable to allocate fc remote port!\n");
|
||||
return;
|
||||
}
|
||||
spin_lock_irqsave(&fcport->rport_lock, flags);
|
||||
fcport->rport = rport;
|
||||
spin_lock_irq(fcport->ha->host->host_lock);
|
||||
*((fc_port_t **)rport->dd_data) = fcport;
|
||||
spin_unlock_irqrestore(&fcport->rport_lock, flags);
|
||||
spin_unlock_irq(fcport->ha->host->host_lock);
|
||||
|
||||
rport->supported_classes = fcport->supported_classes;
|
||||
|
||||
@ -2565,7 +2575,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
|
||||
} else if (qla2x00_gnn_id(ha, swl) != QLA_SUCCESS) {
|
||||
kfree(swl);
|
||||
swl = NULL;
|
||||
} else if (qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) {
|
||||
} else if (ql2xiidmaenable &&
|
||||
qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) {
|
||||
qla2x00_gpsc(ha, swl);
|
||||
}
|
||||
}
|
||||
@ -3220,7 +3231,8 @@ qla2x00_update_fcports(scsi_qla_host_t *ha)
|
||||
|
||||
/* Go with deferred removal of rport references. */
|
||||
list_for_each_entry(fcport, &ha->fcports, list)
|
||||
if (fcport->drport)
|
||||
if (fcport->drport &&
|
||||
atomic_read(&fcport->state) != FCS_UNCONFIGURED)
|
||||
qla2x00_rport_del(fcport);
|
||||
}
|
||||
|
||||
@ -3243,6 +3255,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
|
||||
if (ha->flags.online) {
|
||||
ha->flags.online = 0;
|
||||
clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
|
||||
ha->qla_stats.total_isp_aborts++;
|
||||
|
||||
qla_printk(KERN_INFO, ha,
|
||||
"Performing ISP error recovery - ha= %p.\n", ha);
|
||||
@ -3283,17 +3296,6 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
|
||||
ha->isp_abort_cnt = 0;
|
||||
clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
|
||||
|
||||
if (ha->eft) {
|
||||
memset(ha->eft, 0, EFT_SIZE);
|
||||
rval = qla2x00_enable_eft_trace(ha,
|
||||
ha->eft_dma, EFT_NUM_BUFFERS);
|
||||
if (rval) {
|
||||
qla_printk(KERN_WARNING, ha,
|
||||
"Unable to reinitialize EFT "
|
||||
"(%d).\n", rval);
|
||||
}
|
||||
}
|
||||
|
||||
if (ha->fce) {
|
||||
ha->flags.fce_enabled = 1;
|
||||
memset(ha->fce, 0,
|
||||
@ -3308,6 +3310,17 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
|
||||
ha->flags.fce_enabled = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ha->eft) {
|
||||
memset(ha->eft, 0, EFT_SIZE);
|
||||
rval = qla2x00_enable_eft_trace(ha,
|
||||
ha->eft_dma, EFT_NUM_BUFFERS);
|
||||
if (rval) {
|
||||
qla_printk(KERN_WARNING, ha,
|
||||
"Unable to reinitialize EFT "
|
||||
"(%d).\n", rval);
|
||||
}
|
||||
}
|
||||
} else { /* failed the ISP abort */
|
||||
ha->flags.online = 1;
|
||||
if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
|
||||
@ -4026,8 +4039,8 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
|
||||
ret = qla2x00_stop_firmware(ha);
|
||||
for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT &&
|
||||
retries ; retries--) {
|
||||
qla2x00_reset_chip(ha);
|
||||
if (qla2x00_chip_diag(ha) != QLA_SUCCESS)
|
||||
ha->isp_ops->reset_chip(ha);
|
||||
if (ha->isp_ops->chip_diag(ha) != QLA_SUCCESS)
|
||||
continue;
|
||||
if (qla2x00_setup_chip(ha) != QLA_SUCCESS)
|
||||
continue;
|
||||
@ -4049,7 +4062,7 @@ qla24xx_configure_vhba(scsi_qla_host_t *ha)
|
||||
rval = qla2x00_fw_ready(ha->parent);
|
||||
if (rval == QLA_SUCCESS) {
|
||||
clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
|
||||
qla2x00_marker(ha->parent, 0, 0, MK_SYNC_ALL);
|
||||
qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
|
||||
}
|
||||
|
||||
ha->flags.management_server_logged_in = 0;
|
||||
|
@ -454,10 +454,11 @@ qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
|
||||
{
|
||||
int ret;
|
||||
unsigned long flags = 0;
|
||||
scsi_qla_host_t *pha = to_qla_parent(ha);
|
||||
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
spin_lock_irqsave(&pha->hardware_lock, flags);
|
||||
ret = __qla2x00_marker(ha, loop_id, lun, type);
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
spin_unlock_irqrestore(&pha->hardware_lock, flags);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
@ -672,7 +673,7 @@ qla24xx_start_scsi(srb_t *sp)
|
||||
{
|
||||
int ret, nseg;
|
||||
unsigned long flags;
|
||||
scsi_qla_host_t *ha;
|
||||
scsi_qla_host_t *ha, *pha;
|
||||
struct scsi_cmnd *cmd;
|
||||
uint32_t *clr_ptr;
|
||||
uint32_t index;
|
||||
@ -686,6 +687,7 @@ qla24xx_start_scsi(srb_t *sp)
|
||||
/* Setup device pointers. */
|
||||
ret = 0;
|
||||
ha = sp->ha;
|
||||
pha = to_qla_parent(ha);
|
||||
reg = &ha->iobase->isp24;
|
||||
cmd = sp->cmd;
|
||||
/* So we know we haven't pci_map'ed anything yet */
|
||||
@ -700,7 +702,7 @@ qla24xx_start_scsi(srb_t *sp)
|
||||
}
|
||||
|
||||
/* Acquire ring specific lock */
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
spin_lock_irqsave(&pha->hardware_lock, flags);
|
||||
|
||||
/* Check for room in outstanding command list. */
|
||||
handle = ha->current_outstanding_cmd;
|
||||
@ -795,14 +797,14 @@ qla24xx_start_scsi(srb_t *sp)
|
||||
ha->response_ring_ptr->signature != RESPONSE_PROCESSED)
|
||||
qla24xx_process_response_queue(ha);
|
||||
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
spin_unlock_irqrestore(&pha->hardware_lock, flags);
|
||||
return QLA_SUCCESS;
|
||||
|
||||
queuing_error:
|
||||
if (tot_dsds)
|
||||
scsi_dma_unmap(cmd);
|
||||
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
spin_unlock_irqrestore(&pha->hardware_lock, flags);
|
||||
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
@ -542,10 +542,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
|
||||
break;
|
||||
|
||||
case MBA_PORT_UPDATE: /* Port database update */
|
||||
/* Only handle SCNs for our Vport index. */
|
||||
if (ha->parent && ha->vp_idx != (mb[3] & 0xff))
|
||||
break;
|
||||
|
||||
/*
|
||||
* If PORT UPDATE is global (recieved LIP_OCCURED/LIP_RESET
|
||||
* event etc. earlier indicating loop is down) then process
|
||||
|
@ -918,6 +918,8 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
|
||||
rval = qla2x00_mailbox_command(ha, mcp);
|
||||
if (mcp->mb[0] == MBS_COMMAND_ERROR)
|
||||
rval = QLA_COMMAND_ERROR;
|
||||
else if (mcp->mb[0] == MBS_INVALID_COMMAND)
|
||||
rval = QLA_INVALID_COMMAND;
|
||||
|
||||
/* Return data. */
|
||||
*id = mcp->mb[1];
|
||||
@ -2161,17 +2163,18 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp)
|
||||
struct abort_entry_24xx *abt;
|
||||
dma_addr_t abt_dma;
|
||||
uint32_t handle;
|
||||
scsi_qla_host_t *pha = to_qla_parent(ha);
|
||||
|
||||
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
|
||||
|
||||
fcport = sp->fcport;
|
||||
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
spin_lock_irqsave(&pha->hardware_lock, flags);
|
||||
for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) {
|
||||
if (ha->outstanding_cmds[handle] == sp)
|
||||
if (pha->outstanding_cmds[handle] == sp)
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
spin_unlock_irqrestore(&pha->hardware_lock, flags);
|
||||
if (handle == MAX_OUTSTANDING_COMMANDS) {
|
||||
/* Command not found. */
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
@ -43,6 +43,7 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
|
||||
|
||||
set_bit(vp_id, ha->vp_idx_map);
|
||||
ha->num_vhosts++;
|
||||
ha->cur_vport_count++;
|
||||
vha->vp_idx = vp_id;
|
||||
list_add_tail(&vha->vp_list, &ha->vp_list);
|
||||
mutex_unlock(&ha->vport_lock);
|
||||
@ -58,6 +59,7 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
|
||||
mutex_lock(&ha->vport_lock);
|
||||
vp_id = vha->vp_idx;
|
||||
ha->num_vhosts--;
|
||||
ha->cur_vport_count--;
|
||||
clear_bit(vp_id, ha->vp_idx_map);
|
||||
list_del(&vha->vp_list);
|
||||
mutex_unlock(&ha->vport_lock);
|
||||
@ -103,8 +105,8 @@ qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha)
|
||||
"loop_id=0x%04x :%x\n",
|
||||
vha->host_no, fcport->loop_id, fcport->vp_idx));
|
||||
|
||||
atomic_set(&fcport->state, FCS_DEVICE_DEAD);
|
||||
qla2x00_mark_device_lost(vha, fcport, 0, 0);
|
||||
atomic_set(&fcport->state, FCS_UNCONFIGURED);
|
||||
}
|
||||
}
|
||||
|
||||
@ -276,7 +278,8 @@ qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
|
||||
clear_bit(RESET_ACTIVE, &vha->dpc_flags);
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
|
||||
if (atomic_read(&vha->vp_state) == VP_ACTIVE &&
|
||||
test_and_clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
|
||||
if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))) {
|
||||
qla2x00_loop_resync(vha);
|
||||
clear_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags);
|
||||
@ -390,7 +393,6 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
|
||||
vha->parent = ha;
|
||||
vha->fc_vport = fc_vport;
|
||||
vha->device_flags = 0;
|
||||
vha->instance = num_hosts;
|
||||
vha->vp_idx = qla24xx_allocate_vp_id(vha);
|
||||
if (vha->vp_idx > ha->max_npiv_vports) {
|
||||
DEBUG15(printk("scsi(%ld): Couldn't allocate vp_id.\n",
|
||||
@ -428,7 +430,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
|
||||
host->max_cmd_len = MAX_CMDSZ;
|
||||
host->max_channel = MAX_BUSES - 1;
|
||||
host->max_lun = MAX_LUNS;
|
||||
host->unique_id = vha->instance;
|
||||
host->unique_id = host->host_no;
|
||||
host->max_id = MAX_TARGETS_2200;
|
||||
host->transportt = qla2xxx_transport_vport_template;
|
||||
|
||||
@ -436,12 +438,6 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
|
||||
vha->host_no, vha));
|
||||
|
||||
vha->flags.init_done = 1;
|
||||
num_hosts++;
|
||||
|
||||
mutex_lock(&ha->vport_lock);
|
||||
set_bit(vha->vp_idx, ha->vp_idx_map);
|
||||
ha->cur_vport_count++;
|
||||
mutex_unlock(&ha->vport_lock);
|
||||
|
||||
return vha;
|
||||
|
||||
|
@ -27,7 +27,6 @@ char qla2x00_version_str[40];
|
||||
*/
|
||||
static struct kmem_cache *srb_cachep;
|
||||
|
||||
int num_hosts;
|
||||
int ql2xlogintimeout = 20;
|
||||
module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
|
||||
MODULE_PARM_DESC(ql2xlogintimeout,
|
||||
@ -87,6 +86,13 @@ MODULE_PARM_DESC(ql2xqfullrampup,
|
||||
"depth for a device after a queue-full condition has been "
|
||||
"detected. Default is 120 seconds.");
|
||||
|
||||
int ql2xiidmaenable=1;
|
||||
module_param(ql2xiidmaenable, int, S_IRUGO|S_IRUSR);
|
||||
MODULE_PARM_DESC(ql2xiidmaenable,
|
||||
"Enables iIDMA settings "
|
||||
"Default is 1 - perform iIDMA. 0 - no iIDMA.");
|
||||
|
||||
|
||||
/*
|
||||
* SCSI host template entry points
|
||||
*/
|
||||
@ -388,7 +394,7 @@ qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
|
||||
}
|
||||
|
||||
/* Close window on fcport/rport state-transitioning. */
|
||||
if (!*(fc_port_t **)rport->dd_data) {
|
||||
if (fcport->drport) {
|
||||
cmd->result = DID_IMM_RETRY << 16;
|
||||
goto qc_fail_command;
|
||||
}
|
||||
@ -443,7 +449,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
|
||||
int rval;
|
||||
scsi_qla_host_t *pha = to_qla_parent(ha);
|
||||
|
||||
if (unlikely(pci_channel_offline(ha->pdev))) {
|
||||
if (unlikely(pci_channel_offline(pha->pdev))) {
|
||||
cmd->result = DID_REQUEUE << 16;
|
||||
goto qc24_fail_command;
|
||||
}
|
||||
@ -455,7 +461,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
|
||||
}
|
||||
|
||||
/* Close window on fcport/rport state-transitioning. */
|
||||
if (!*(fc_port_t **)rport->dd_data) {
|
||||
if (fcport->drport) {
|
||||
cmd->result = DID_IMM_RETRY << 16;
|
||||
goto qc24_fail_command;
|
||||
}
|
||||
@ -617,6 +623,40 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha)
|
||||
return (return_status);
|
||||
}
|
||||
|
||||
void
|
||||
qla2x00_abort_fcport_cmds(fc_port_t *fcport)
|
||||
{
|
||||
int cnt;
|
||||
unsigned long flags;
|
||||
srb_t *sp;
|
||||
scsi_qla_host_t *ha = fcport->ha;
|
||||
scsi_qla_host_t *pha = to_qla_parent(ha);
|
||||
|
||||
spin_lock_irqsave(&pha->hardware_lock, flags);
|
||||
for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
|
||||
sp = pha->outstanding_cmds[cnt];
|
||||
if (!sp)
|
||||
continue;
|
||||
if (sp->fcport != fcport)
|
||||
continue;
|
||||
|
||||
spin_unlock_irqrestore(&pha->hardware_lock, flags);
|
||||
if (ha->isp_ops->abort_command(ha, sp)) {
|
||||
DEBUG2(qla_printk(KERN_WARNING, ha,
|
||||
"Abort failed -- %lx\n", sp->cmd->serial_number));
|
||||
} else {
|
||||
if (qla2x00_eh_wait_on_command(ha, sp->cmd) !=
|
||||
QLA_SUCCESS)
|
||||
DEBUG2(qla_printk(KERN_WARNING, ha,
|
||||
"Abort failed while waiting -- %lx\n",
|
||||
sp->cmd->serial_number));
|
||||
|
||||
}
|
||||
spin_lock_irqsave(&pha->hardware_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&pha->hardware_lock, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
qla2x00_block_error_handler(struct scsi_cmnd *cmnd)
|
||||
{
|
||||
@ -1073,7 +1113,7 @@ qla2xxx_slave_configure(struct scsi_device *sdev)
|
||||
else
|
||||
scsi_deactivate_tcq(sdev, ha->max_q_depth);
|
||||
|
||||
rport->dev_loss_tmo = ha->port_down_retry_count + 5;
|
||||
rport->dev_loss_tmo = ha->port_down_retry_count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1629,9 +1669,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
}
|
||||
host->can_queue = ha->request_q_length + 128;
|
||||
|
||||
/* load the F/W, read paramaters, and init the H/W */
|
||||
ha->instance = num_hosts;
|
||||
|
||||
mutex_init(&ha->vport_lock);
|
||||
init_completion(&ha->mbx_cmd_comp);
|
||||
complete(&ha->mbx_cmd_comp);
|
||||
@ -1679,7 +1716,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
|
||||
host->this_id = 255;
|
||||
host->cmd_per_lun = 3;
|
||||
host->unique_id = ha->instance;
|
||||
host->unique_id = host->host_no;
|
||||
host->max_cmd_len = MAX_CMDSZ;
|
||||
host->max_channel = MAX_BUSES - 1;
|
||||
host->max_lun = MAX_LUNS;
|
||||
@ -1700,8 +1737,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
ha->flags.init_done = 1;
|
||||
ha->flags.online = 1;
|
||||
|
||||
num_hosts++;
|
||||
|
||||
ret = scsi_add_host(host, &pdev->dev);
|
||||
if (ret)
|
||||
goto probe_failed;
|
||||
@ -1813,27 +1848,21 @@ static inline void
|
||||
qla2x00_schedule_rport_del(struct scsi_qla_host *ha, fc_port_t *fcport,
|
||||
int defer)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct fc_rport *rport;
|
||||
scsi_qla_host_t *pha = to_qla_parent(ha);
|
||||
|
||||
if (!fcport->rport)
|
||||
return;
|
||||
|
||||
rport = fcport->rport;
|
||||
if (defer) {
|
||||
spin_lock_irqsave(&fcport->rport_lock, flags);
|
||||
spin_lock_irq(ha->host->host_lock);
|
||||
fcport->drport = rport;
|
||||
fcport->rport = NULL;
|
||||
*(fc_port_t **)rport->dd_data = NULL;
|
||||
spin_unlock_irqrestore(&fcport->rport_lock, flags);
|
||||
set_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags);
|
||||
} else {
|
||||
spin_lock_irqsave(&fcport->rport_lock, flags);
|
||||
fcport->rport = NULL;
|
||||
*(fc_port_t **)rport->dd_data = NULL;
|
||||
spin_unlock_irqrestore(&fcport->rport_lock, flags);
|
||||
spin_unlock_irq(ha->host->host_lock);
|
||||
set_bit(FCPORT_UPDATE_NEEDED, &pha->dpc_flags);
|
||||
qla2xxx_wake_dpc(pha);
|
||||
} else
|
||||
fc_remote_port_delete(rport);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1903,7 +1932,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
|
||||
scsi_qla_host_t *pha = to_qla_parent(ha);
|
||||
|
||||
list_for_each_entry(fcport, &pha->fcports, list) {
|
||||
if (ha->vp_idx != 0 && ha->vp_idx != fcport->vp_idx)
|
||||
if (ha->vp_idx != fcport->vp_idx)
|
||||
continue;
|
||||
/*
|
||||
* No point in marking the device as lost, if the device is
|
||||
@ -1911,17 +1940,10 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
|
||||
*/
|
||||
if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
|
||||
continue;
|
||||
if (atomic_read(&fcport->state) == FCS_ONLINE) {
|
||||
if (defer)
|
||||
qla2x00_schedule_rport_del(ha, fcport, defer);
|
||||
else if (ha->vp_idx == fcport->vp_idx)
|
||||
qla2x00_schedule_rport_del(ha, fcport, defer);
|
||||
}
|
||||
if (atomic_read(&fcport->state) == FCS_ONLINE)
|
||||
qla2x00_schedule_rport_del(ha, fcport, defer);
|
||||
atomic_set(&fcport->state, FCS_DEVICE_LOST);
|
||||
}
|
||||
|
||||
if (defer)
|
||||
qla2xxx_wake_dpc(ha);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2156,7 +2178,7 @@ qla2x00_alloc_work(struct scsi_qla_host *ha, enum qla_work_type type,
|
||||
static int
|
||||
qla2x00_post_work(struct scsi_qla_host *ha, struct qla_work_evt *e, int locked)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long uninitialized_var(flags);
|
||||
scsi_qla_host_t *pha = to_qla_parent(ha);
|
||||
|
||||
if (!locked)
|
||||
@ -2313,8 +2335,10 @@ qla2x00_do_dpc(void *data)
|
||||
ha->host_no));
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags))
|
||||
if (test_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags)) {
|
||||
qla2x00_update_fcports(ha);
|
||||
clear_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags);
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) &&
|
||||
(!(test_and_set_bit(RESET_ACTIVE, &ha->dpc_flags)))) {
|
||||
|
@ -869,11 +869,9 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
|
||||
uint32_t i;
|
||||
uint32_t *dwptr;
|
||||
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
|
||||
unsigned long flags;
|
||||
|
||||
ret = QLA_SUCCESS;
|
||||
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
/* Enable flash write. */
|
||||
WRT_REG_DWORD(®->ctrl_status,
|
||||
RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE);
|
||||
@ -907,7 +905,6 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
|
||||
WRT_REG_DWORD(®->ctrl_status,
|
||||
RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE);
|
||||
RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -2305,6 +2302,51 @@ qla24xx_get_flash_version(scsi_qla_host_t *ha, void *mbuf)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
qla2xxx_is_vpd_valid(uint8_t *pos, uint8_t *end)
|
||||
{
|
||||
if (pos >= end || *pos != 0x82)
|
||||
return 0;
|
||||
|
||||
pos += 3 + pos[1];
|
||||
if (pos >= end || *pos != 0x90)
|
||||
return 0;
|
||||
|
||||
pos += 3 + pos[1];
|
||||
if (pos >= end || *pos != 0x78)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
qla2xxx_get_vpd_field(scsi_qla_host_t *ha, char *key, char *str, size_t size)
|
||||
{
|
||||
uint8_t *pos = ha->vpd;
|
||||
uint8_t *end = pos + ha->vpd_size;
|
||||
int len = 0;
|
||||
|
||||
if (!IS_FWI2_CAPABLE(ha) || !qla2xxx_is_vpd_valid(pos, end))
|
||||
return 0;
|
||||
|
||||
while (pos < end && *pos != 0x78) {
|
||||
len = (*pos == 0x82) ? pos[1] : pos[2];
|
||||
|
||||
if (!strncmp(pos, key, strlen(key)))
|
||||
break;
|
||||
|
||||
if (*pos != 0x90 && *pos != 0x91)
|
||||
pos += len;
|
||||
|
||||
pos += 3;
|
||||
}
|
||||
|
||||
if (pos < end - len && *pos != 0x78)
|
||||
return snprintf(str, size, "%.*s", len, pos + 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
qla2xxx_hw_event_store(scsi_qla_host_t *ha, uint32_t *fdata)
|
||||
{
|
||||
|
@ -7,7 +7,7 @@
|
||||
/*
|
||||
* Driver version
|
||||
*/
|
||||
#define QLA2XXX_VERSION "8.02.01-k4"
|
||||
#define QLA2XXX_VERSION "8.02.01-k6"
|
||||
|
||||
#define QLA_DRIVER_MAJOR_VER 8
|
||||
#define QLA_DRIVER_MINOR_VER 2
|
||||
|
@ -46,6 +46,8 @@ MODULE_PARM_DESC(ql4xextended_error_logging,
|
||||
|
||||
int ql4_mod_unload = 0;
|
||||
|
||||
#define QL4_DEF_QDEPTH 32
|
||||
|
||||
/*
|
||||
* SCSI host template entry points
|
||||
*/
|
||||
@ -1387,7 +1389,7 @@ static int qla4xxx_slave_alloc(struct scsi_device *sdev)
|
||||
|
||||
sdev->hostdata = ddb;
|
||||
sdev->tagged_supported = 1;
|
||||
scsi_activate_tcq(sdev, sdev->host->can_queue);
|
||||
scsi_activate_tcq(sdev, QL4_DEF_QDEPTH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -197,10 +197,42 @@ static void
|
||||
scsi_pool_free_command(struct scsi_host_cmd_pool *pool,
|
||||
struct scsi_cmnd *cmd)
|
||||
{
|
||||
if (cmd->prot_sdb)
|
||||
kmem_cache_free(scsi_sdb_cache, cmd->prot_sdb);
|
||||
|
||||
kmem_cache_free(pool->sense_slab, cmd->sense_buffer);
|
||||
kmem_cache_free(pool->cmd_slab, cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* scsi_host_alloc_command - internal function to allocate command
|
||||
* @shost: SCSI host whose pool to allocate from
|
||||
* @gfp_mask: mask for the allocation
|
||||
*
|
||||
* Returns a fully allocated command with sense buffer and protection
|
||||
* data buffer (where applicable) or NULL on failure
|
||||
*/
|
||||
static struct scsi_cmnd *
|
||||
scsi_host_alloc_command(struct Scsi_Host *shost, gfp_t gfp_mask)
|
||||
{
|
||||
struct scsi_cmnd *cmd;
|
||||
|
||||
cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
|
||||
if (!cmd)
|
||||
return NULL;
|
||||
|
||||
if (scsi_host_get_prot(shost) >= SHOST_DIX_TYPE0_PROTECTION) {
|
||||
cmd->prot_sdb = kmem_cache_zalloc(scsi_sdb_cache, gfp_mask);
|
||||
|
||||
if (!cmd->prot_sdb) {
|
||||
scsi_pool_free_command(shost->cmd_pool, cmd);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
* __scsi_get_command - Allocate a struct scsi_cmnd
|
||||
* @shost: host to transmit command
|
||||
@ -214,7 +246,7 @@ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
|
||||
struct scsi_cmnd *cmd;
|
||||
unsigned char *buf;
|
||||
|
||||
cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
|
||||
cmd = scsi_host_alloc_command(shost, gfp_mask);
|
||||
|
||||
if (unlikely(!cmd)) {
|
||||
unsigned long flags;
|
||||
@ -457,7 +489,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
|
||||
/*
|
||||
* Get one backup command for this host.
|
||||
*/
|
||||
cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
|
||||
cmd = scsi_host_alloc_command(shost, gfp_mask);
|
||||
if (!cmd) {
|
||||
scsi_put_host_cmd_pool(gfp_mask);
|
||||
shost->cmd_pool = NULL;
|
||||
@ -902,11 +934,20 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
|
||||
/* Check to see if the queue is managed by the block layer.
|
||||
* If it is, and we fail to adjust the depth, exit. */
|
||||
if (blk_queue_tagged(sdev->request_queue) &&
|
||||
blk_queue_resize_tags(sdev->request_queue, tags) != 0)
|
||||
goto out;
|
||||
/*
|
||||
* Check to see if the queue is managed by the block layer.
|
||||
* If it is, and we fail to adjust the depth, exit.
|
||||
*
|
||||
* Do not resize the tag map if it is a host wide share bqt,
|
||||
* because the size should be the hosts's can_queue. If there
|
||||
* is more IO than the LLD's can_queue (so there are not enuogh
|
||||
* tags) request_fn's host queue ready check will handle it.
|
||||
*/
|
||||
if (!sdev->host->bqt) {
|
||||
if (blk_queue_tagged(sdev->request_queue) &&
|
||||
blk_queue_resize_tags(sdev->request_queue, tags) != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
sdev->queue_depth = tags;
|
||||
switch (tagged) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user