Initial commit

git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2006-10-12 13:47:28 +00:00
commit 445fa5ca1f
74 changed files with 88370 additions and 0 deletions
+102
View File
@@ -0,0 +1,102 @@
#
# Common makefile for SCSI target mid-level and its drivers
#
# Copyright (C) 2006 Vladislav Bolkhovitin <vst@vlnb.net>
#
# 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, version 2
# of the License.
#
# 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.
#
#
# Decide to use which kernel src. If not specified, is current running kernel.
#export KDIR=/usr/src/linux-2.6
SCST_DIR=scst
QLA_INI_DIR=qla2x00t
QLA_DIR=qla2x00t/qla2x00-target
all:
cd $(SCST_DIR) && $(MAKE) $@
@if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
install:
cd $(SCST_DIR) && $(MAKE) $@
@if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
uninstall:
cd $(SCST_DIR) && $(MAKE) $@
@if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
clean:
cd $(SCST_DIR) && $(MAKE) $@
@if [ -d $(QLA_INI_DIR) ]; then cd $(QLA_INI_DIR) && $(MAKE) $@; fi
@if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
extraclean:
cd $(SCST_DIR) && $(MAKE) $@
@if [ -d $(QLA_INI_DIR) ]; then cd $(QLA_INI_DIR) && $(MAKE) $@; fi
@if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
scst:
cd $(SCST_DIR) && $(MAKE)
scst_install:
cd $(SCST_DIR) && $(MAKE) install
scst_uninstall:
cd $(SCST_DIR) && $(MAKE) uninstall
scst_clean:
cd $(SCST_DIR) && $(MAKE) clean
scst_extraclean:
cd $(SCST_DIR) && $(MAKE) extraclean
qla:
cd $(QLA_DIR) && $(MAKE)
qla_install:
cd $(QLA_DIR) && $(MAKE) install
qla_uninstall:
cd $(QLA_DIR) && $(MAKE) uninstall
qla_clean:
cd $(QLA_INI_DIR) && $(MAKE) clean
cd $(QLA_DIR) && $(MAKE) clean
qla_extraclean:
cd $(QLA_INI_DIR)/.. && $(MAKE) extraclean
cd $(QLA_DIR) && $(MAKE) extraclean
help:
@echo " all (the default) : make all"
@echo " clean : clean files"
@echo " extraclean : clean + clean dependencies"
@echo " install : install"
@echo " uninstall : uninstall"
@echo ""
@echo " scst : make scst only"
@echo " scst_clean : scst: clean "
@echo " scst_extraclean : scst: clean + clean dependencies"
@echo " scst_install : scst: install"
@echo " scst_uninstall : scst: uninstall"
@echo ""
@echo " qla : make new qla target using 2.6.x kernel qla2xxx"
@echo " qla_clean : 2.6 qla target: clean "
@echo " qla_extraclean : 2.6 qla target: clean + clean dependencies"
@echo " qla_install : 2.6 qla target: install"
@echo " qla_uninstall : 2.6 qla target: uninstall"
@echo " Notes :"
@echo " - install and uninstall must be made as root"
.PHONY: all install uninstall clean extraclean help \
qla qla_install qla_uninstall qla_clean qla_extraclean \
scst scst_install scst_uninstall scst_clean scst_extraclean
+82
View File
@@ -0,0 +1,82 @@
config SCSI_QLA_FC
tristate "QLogic QLA2XXX Fibre Channel Support"
depends on PCI && SCSI
select SCSI_FC_ATTRS
select FW_LOADER
---help---
This qla2xxx driver supports all QLogic Fibre Channel
PCI and PCIe host adapters.
By default, firmware for the ISP parts will be loaded
via the Firmware Loader interface.
ISP Firmware Filename
---------- -----------------
21xx ql2100_fw.bin
22xx ql2200_fw.bin
2300, 2312, 6312 ql2300_fw.bin
2322, 6322 ql2322_fw.bin
24xx ql2400_fw.bin
Upon request, the driver caches the firmware image until
the driver is unloaded.
Firmware images can be retrieved from:
ftp://ftp.qlogic.com/outgoing/linux/firmware/
NOTE: The original method of building firmware-loader
modules has been deprecated as the firmware-images will
be removed from the kernel sources.
config SCSI_QLA2XXX_TARGET
bool "QLogic 2xxx target mode support"
depends on SCSI_QLA_FC
default y
---help---
This option enables target mode hooks used by the SCST QLA2x00tgt driver.
Once the qla2x00tgt module is loaded, target mode can be enable via a
sysfs interface under scsi_host, thus enabling target mode for specific
cards.
You will also need the SCST middle level drivers from http://scst.sf.net/.
config SCSI_QLA2XXX_EMBEDDED_FIRMWARE
bool " Use firmware-loader modules (DEPRECATED)"
depends on SCSI_QLA_FC
help
This option offers you the deprecated firmware-loader
modules that have been obsoleted by the usage of the
Firmware Loader interface in the qla2xxx driver.
config SCSI_QLA21XX
tristate " Build QLogic ISP2100 firmware-module"
depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE
---help---
This driver supports the QLogic 21xx (ISP2100) host adapter family.
config SCSI_QLA22XX
tristate " Build QLogic ISP2200 firmware-module"
depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE
---help---
This driver supports the QLogic 22xx (ISP2200) host adapter family.
config SCSI_QLA2300
tristate " Build QLogic ISP2300/ISP6312 firmware-module"
depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE
---help---
This driver supports the QLogic 2300 (ISP2300, ISP2312 and
ISP6312) host adapter family.
config SCSI_QLA2322
tristate " Build QLogic ISP2322/ISP6322 firmware-module"
depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE
---help---
This driver supports the QLogic 2322 (ISP2322 and ISP6322) host
adapter family.
config SCSI_QLA24XX
tristate " Build QLogic ISP24xx firmware-module"
depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE
---help---
This driver supports the QLogic 24xx (ISP2422 and ISP2432) host
adapter family.
+48
View File
@@ -0,0 +1,48 @@
ifneq ($(KERNELRELEASE),)
EXTRA_CFLAGS += -DUNIQUE_FW_NAME
qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
qla_dbg.o qla_sup.o qla_rscn.o qla_attr.o
obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
qla2100-y := ql2100.o ql2100_fw.o
qla2200-y := ql2200.o ql2200_fw.o
qla2300-y := ql2300.o ql2300_fw.o
qla2322-y := ql2322.o ql2322_fw.o
qla2400-y := ql2400.o ql2400_fw.o
obj-$(CONFIG_SCSI_QLA21XX) += qla2xxx.o qla2100.o
obj-$(CONFIG_SCSI_QLA22XX) += qla2xxx.o qla2200.o
obj-$(CONFIG_SCSI_QLA2300) += qla2xxx.o qla2300.o
obj-$(CONFIG_SCSI_QLA2322) += qla2xxx.o qla2322.o
obj-$(CONFIG_SCSI_QLA24XX) += qla2xxx.o qla2400.o
else
ifeq ($(KVER),)
ifeq ($(KDIR),)
KDIR := /lib/modules/$(shell uname -r)/build
endif
else
KDIR := /lib/modules/$(KVER)/build
endif
all:
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)
install: all
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \
modules_install
uninstall:
rm -f $(INSTALL_DIR)/qla2[2-3]00.ko $(INSTALL_DIR)/qla2xxx.ko
-/sbin/depmod -a
endif
clean:
rm -f *.o *.ko .*.cmd *.mod.c .*.d .depend *~ Modules.symvers
rm -rf .tmp_versions
extraclean: clean
.PHONY: all install uninstall clean extraclean
+91
View File
@@ -0,0 +1,91 @@
/*
* QLogic Fibre Channel HBA Driver
* Copyright (C) 2003 Christoph Hellwig.
* Copyright (c) 2003-2005 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#include "qla_def.h"
static char qla_driver_name[] = "qla2100";
extern unsigned char fw2100tp_version[];
extern unsigned char fw2100tp_version_str[];
extern unsigned short fw2100tp_addr01;
extern unsigned short fw2100tp_code01[];
extern unsigned short fw2100tp_length01;
static struct qla_fw_info qla_fw_tbl[] = {
{
.addressing = FW_INFO_ADDR_NORMAL,
.fwcode = &fw2100tp_code01[0],
.fwlen = &fw2100tp_length01,
.fwstart = &fw2100tp_addr01,
},
{ FW_INFO_ADDR_NOMORE, },
};
static struct qla_board_info qla_board_tbl = {
.drv_name = qla_driver_name,
.isp_name = "ISP2100",
.fw_info = qla_fw_tbl,
};
static struct pci_device_id qla2100_pci_tbl[] = {
{
.vendor = PCI_VENDOR_ID_QLOGIC,
.device = PCI_DEVICE_ID_QLOGIC_ISP2100,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (unsigned long)&qla_board_tbl,
},
{0, 0},
};
MODULE_DEVICE_TABLE(pci, qla2100_pci_tbl);
static int __devinit
qla2100_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
return qla2x00_probe_one(pdev,
(struct qla_board_info *)id->driver_data);
}
static void __devexit
qla2100_remove_one(struct pci_dev *pdev)
{
qla2x00_remove_one(pdev);
}
static struct pci_driver qla2100_pci_driver = {
.name = "qla2100",
.id_table = qla2100_pci_tbl,
.probe = qla2100_probe_one,
.remove = __devexit_p(qla2100_remove_one),
};
static int __init
qla2100_init(void)
{
return pci_module_init(&qla2100_pci_driver);
}
static void __exit
qla2100_exit(void)
{
pci_unregister_driver(&qla2100_pci_driver);
}
module_init(qla2100_init);
module_exit(qla2100_exit);
MODULE_AUTHOR("QLogic Corporation");
MODULE_DESCRIPTION("QLogic ISP21xx FC-SCSI Host Bus Adapter driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(QLA2XXX_VERSION);
+4848
View File
File diff suppressed because it is too large Load Diff
+91
View File
@@ -0,0 +1,91 @@
/*
* QLogic Fibre Channel HBA Driver
* Copyright (C) 2003 Christoph Hellwig.
* Copyright (c) 2003-2005 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#include "qla_def.h"
static char qla_driver_name[] = "qla2200";
extern unsigned char fw2200tp_version[];
extern unsigned char fw2200tp_version_str[];
extern unsigned short fw2200tp_addr01;
extern unsigned short fw2200tp_code01[];
extern unsigned short fw2200tp_length01;
static struct qla_fw_info qla_fw_tbl[] = {
{
.addressing = FW_INFO_ADDR_NORMAL,
.fwcode = &fw2200tp_code01[0],
.fwlen = &fw2200tp_length01,
.fwstart = &fw2200tp_addr01,
},
{ FW_INFO_ADDR_NOMORE, },
};
static struct qla_board_info qla_board_tbl = {
.drv_name = qla_driver_name,
.isp_name = "ISP2200",
.fw_info = qla_fw_tbl,
};
static struct pci_device_id qla2200_pci_tbl[] = {
{
.vendor = PCI_VENDOR_ID_QLOGIC,
.device = PCI_DEVICE_ID_QLOGIC_ISP2200,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (unsigned long)&qla_board_tbl,
},
{0, 0},
};
MODULE_DEVICE_TABLE(pci, qla2200_pci_tbl);
static int __devinit
qla2200_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
return qla2x00_probe_one(pdev,
(struct qla_board_info *)id->driver_data);
}
static void __devexit
qla2200_remove_one(struct pci_dev *pdev)
{
qla2x00_remove_one(pdev);
}
static struct pci_driver qla2200_pci_driver = {
.name = "qla2200",
.id_table = qla2200_pci_tbl,
.probe = qla2200_probe_one,
.remove = __devexit_p(qla2200_remove_one),
};
static int __init
qla2200_init(void)
{
return pci_module_init(&qla2200_pci_driver);
}
static void __exit
qla2200_exit(void)
{
pci_unregister_driver(&qla2200_pci_driver);
}
module_init(qla2200_init);
module_exit(qla2200_exit);
MODULE_AUTHOR("QLogic Corporation");
MODULE_DESCRIPTION("QLogic ISP22xx FC-SCSI Host Bus Adapter driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(QLA2XXX_VERSION);
+5333
View File
File diff suppressed because it is too large Load Diff
+114
View File
@@ -0,0 +1,114 @@
/*
* QLogic Fibre Channel HBA Driver
* Copyright (C) 2003 Christoph Hellwig.
* Copyright (c) 2003-2005 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#include "qla_def.h"
static char qla_driver_name[] = "qla2300";
extern unsigned char fw2300ipx_version[];
extern unsigned char fw2300ipx_version_str[];
extern unsigned short fw2300ipx_addr01;
extern unsigned short fw2300ipx_code01[];
extern unsigned short fw2300ipx_length01;
static struct qla_fw_info qla_fw_tbl[] = {
{
.addressing = FW_INFO_ADDR_NORMAL,
.fwcode = &fw2300ipx_code01[0],
.fwlen = &fw2300ipx_length01,
.fwstart = &fw2300ipx_addr01,
},
{ FW_INFO_ADDR_NOMORE, },
};
static struct qla_board_info qla_board_tbl[] = {
{
.drv_name = qla_driver_name,
.isp_name = "ISP2300",
.fw_info = qla_fw_tbl,
},
{
.drv_name = qla_driver_name,
.isp_name = "ISP2312",
.fw_info = qla_fw_tbl,
},
{
.drv_name = qla_driver_name,
.isp_name = "ISP6312",
.fw_info = qla_fw_tbl,
},
};
static struct pci_device_id qla2300_pci_tbl[] = {
{
.vendor = PCI_VENDOR_ID_QLOGIC,
.device = PCI_DEVICE_ID_QLOGIC_ISP2300,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (unsigned long)&qla_board_tbl[0],
},
{
.vendor = PCI_VENDOR_ID_QLOGIC,
.device = PCI_DEVICE_ID_QLOGIC_ISP2312,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (unsigned long)&qla_board_tbl[1],
},
{
.vendor = PCI_VENDOR_ID_QLOGIC,
.device = PCI_DEVICE_ID_QLOGIC_ISP6312,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (unsigned long)&qla_board_tbl[2],
},
{0, 0},
};
MODULE_DEVICE_TABLE(pci, qla2300_pci_tbl);
static int __devinit
qla2300_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
return qla2x00_probe_one(pdev,
(struct qla_board_info *)id->driver_data);
}
static void __devexit
qla2300_remove_one(struct pci_dev *pdev)
{
qla2x00_remove_one(pdev);
}
static struct pci_driver qla2300_pci_driver = {
.name = "qla2300",
.id_table = qla2300_pci_tbl,
.probe = qla2300_probe_one,
.remove = __devexit_p(qla2300_remove_one),
};
static int __init
qla2300_init(void)
{
return pci_module_init(&qla2300_pci_driver);
}
static void __exit
qla2300_exit(void)
{
pci_unregister_driver(&qla2300_pci_driver);
}
module_init(qla2300_init);
module_exit(qla2300_exit);
MODULE_AUTHOR("QLogic Corporation");
MODULE_DESCRIPTION("QLogic ISP23xx FC-SCSI Host Bus Adapter driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(QLA2XXX_VERSION);
+7746
View File
File diff suppressed because it is too large Load Diff
+119
View File
@@ -0,0 +1,119 @@
/*
* QLogic Fibre Channel HBA Driver
* Copyright (c) 2003-2005 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#include "qla_def.h"
static char qla_driver_name[] = "qla2322";
extern unsigned char fw2322ipx_version[];
extern unsigned char fw2322ipx_version_str[];
extern unsigned short fw2322ipx_addr01;
extern unsigned short fw2322ipx_code01[];
extern unsigned short fw2322ipx_length01;
extern unsigned long rseqipx_code_addr01;
extern unsigned short rseqipx_code01[];
extern unsigned short rseqipx_code_length01;
extern unsigned long xseqipx_code_addr01;
extern unsigned short xseqipx_code01[];
extern unsigned short xseqipx_code_length01;
static struct qla_fw_info qla_fw_tbl[] = {
{
.addressing = FW_INFO_ADDR_NORMAL,
.fwcode = &fw2322ipx_code01[0],
.fwlen = &fw2322ipx_length01,
.fwstart = &fw2322ipx_addr01,
},
{
.addressing = FW_INFO_ADDR_EXTENDED,
.fwcode = &rseqipx_code01[0],
.fwlen = &rseqipx_code_length01,
.lfwstart = &rseqipx_code_addr01,
},
{
.addressing = FW_INFO_ADDR_EXTENDED,
.fwcode = &xseqipx_code01[0],
.fwlen = &xseqipx_code_length01,
.lfwstart = &xseqipx_code_addr01,
},
{ FW_INFO_ADDR_NOMORE, },
};
static struct qla_board_info qla_board_tbl[] = {
{
.drv_name = qla_driver_name,
.isp_name = "ISP2322",
.fw_info = qla_fw_tbl,
},
{
.drv_name = qla_driver_name,
.isp_name = "ISP6322",
.fw_info = qla_fw_tbl,
},
};
static struct pci_device_id qla2322_pci_tbl[] = {
{
.vendor = PCI_VENDOR_ID_QLOGIC,
.device = PCI_DEVICE_ID_QLOGIC_ISP2322,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (unsigned long)&qla_board_tbl[0],
},
{
.vendor = PCI_VENDOR_ID_QLOGIC,
.device = PCI_DEVICE_ID_QLOGIC_ISP6322,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (unsigned long)&qla_board_tbl[1],
},
{0, 0},
};
MODULE_DEVICE_TABLE(pci, qla2322_pci_tbl);
static int __devinit
qla2322_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
return qla2x00_probe_one(pdev,
(struct qla_board_info *)id->driver_data);
}
static void __devexit
qla2322_remove_one(struct pci_dev *pdev)
{
qla2x00_remove_one(pdev);
}
static struct pci_driver qla2322_pci_driver = {
.name = "qla2322",
.id_table = qla2322_pci_tbl,
.probe = qla2322_probe_one,
.remove = __devexit_p(qla2322_remove_one),
};
static int __init
qla2322_init(void)
{
return pci_module_init(&qla2322_pci_driver);
}
static void __exit
qla2322_exit(void)
{
pci_unregister_driver(&qla2322_pci_driver);
}
module_init(qla2322_init);
module_exit(qla2322_exit);
MODULE_AUTHOR("QLogic Corporation");
MODULE_DESCRIPTION("QLogic ISP2322 FC-SCSI Host Bus Adapter driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(QLA2XXX_VERSION);
+8376
View File
File diff suppressed because it is too large Load Diff
+138
View File
@@ -0,0 +1,138 @@
/*
* QLogic Fibre Channel HBA Driver
* Copyright (c) 2003-2005 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#include "qla_def.h"
static char qla_driver_name[] = "qla2400";
extern uint32_t fw2400_version_str[];
extern uint32_t fw2400_addr01;
extern uint32_t fw2400_code01[];
extern uint32_t fw2400_length01;
extern uint32_t fw2400_addr02;
extern uint32_t fw2400_code02[];
extern uint32_t fw2400_length02;
static struct qla_fw_info qla_fw_tbl[] = {
{
.addressing = FW_INFO_ADDR_EXTENDED,
.fwcode = (unsigned short *)&fw2400_code01[0],
.fwlen = (unsigned short *)&fw2400_length01,
.lfwstart = (unsigned long *)&fw2400_addr01,
},
{
.addressing = FW_INFO_ADDR_EXTENDED,
.fwcode = (unsigned short *)&fw2400_code02[0],
.fwlen = (unsigned short *)&fw2400_length02,
.lfwstart = (unsigned long *)&fw2400_addr02,
},
{ FW_INFO_ADDR_NOMORE, },
};
static struct qla_board_info qla_board_tbl[] = {
{
.drv_name = qla_driver_name,
.isp_name = "ISP2422",
.fw_info = qla_fw_tbl,
.fw_fname = "ql2400_fw.bin",
},
{
.drv_name = qla_driver_name,
.isp_name = "ISP2432",
.fw_info = qla_fw_tbl,
.fw_fname = "ql2400_fw.bin",
},
{
.drv_name = qla_driver_name,
.isp_name = "ISP5422",
.fw_info = qla_fw_tbl,
.fw_fname = "ql2400_fw.bin",
},
{
.drv_name = qla_driver_name,
.isp_name = "ISP5432",
.fw_info = qla_fw_tbl,
.fw_fname = "ql2400_fw.bin",
},
};
static struct pci_device_id qla24xx_pci_tbl[] = {
{
.vendor = PCI_VENDOR_ID_QLOGIC,
.device = PCI_DEVICE_ID_QLOGIC_ISP2422,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (unsigned long)&qla_board_tbl[0],
},
{
.vendor = PCI_VENDOR_ID_QLOGIC,
.device = PCI_DEVICE_ID_QLOGIC_ISP2432,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (unsigned long)&qla_board_tbl[1],
},
{
.vendor = PCI_VENDOR_ID_QLOGIC,
.device = PCI_DEVICE_ID_QLOGIC_ISP5422,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (unsigned long)&qla_board_tbl[2],
},
{
.vendor = PCI_VENDOR_ID_QLOGIC,
.device = PCI_DEVICE_ID_QLOGIC_ISP5432,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (unsigned long)&qla_board_tbl[3],
},
{0, 0},
};
MODULE_DEVICE_TABLE(pci, qla24xx_pci_tbl);
static int __devinit
qla24xx_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
return qla2x00_probe_one(pdev,
(struct qla_board_info *)id->driver_data);
}
static void __devexit
qla24xx_remove_one(struct pci_dev *pdev)
{
qla2x00_remove_one(pdev);
}
static struct pci_driver qla24xx_pci_driver = {
.name = "qla2400",
.id_table = qla24xx_pci_tbl,
.probe = qla24xx_probe_one,
.remove = __devexit_p(qla24xx_remove_one),
};
static int __init
qla24xx_init(void)
{
return pci_module_init(&qla24xx_pci_driver);
}
static void __exit
qla24xx_exit(void)
{
pci_unregister_driver(&qla24xx_pci_driver);
}
module_init(qla24xx_init);
module_exit(qla24xx_exit);
MODULE_AUTHOR("QLogic Corporation");
MODULE_DESCRIPTION("QLogic ISP24xx FC-SCSI Host Bus Adapter driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(QLA2XXX_VERSION);
+12346
View File
File diff suppressed because it is too large Load Diff
+74
View File
@@ -0,0 +1,74 @@
Summary of changes between versions 0.9.3.8 and 0.9.3.9
-------------------------------------------------------
Patch vs: qla2xxx v8.01.03-k (in kernels 2.6.15.x+, including 2.6.16-prex)
- Fixed problem when "out-of-order frames rassembly" bit was wrongly set,
which lead to only 1Gbps speed of 23xx cards.
- Removed all code that deals with "use_sg == 0" data, since staring
from SCST 0.9.5 commands data are always in SG-vector.
- Fixed hungup on the module unload.
- Minor cleanups and fixes
Summary of changes between versions 0.9.3.7 and 0.9.3.8
-------------------------------------------------------
Patch vs: qla2xxx v8.01.03-k (in kernels 2.6.15.x+, including 2.6.16-prex)
- Minor cleanups
Summary of changes between versions 0.9.3.6 and 0.9.3.7
-------------------------------------------------------
Patch vs: qla2xxx v8.01.03-k (in kernels 2.6.15.x+, including 2.6.16-prex)
- Fix null pointer dereference in do_ctio_complete (thanks to Calvin Morrow)
Summary of changes between versions 0.9.3.5 and 0.9.3.6
-------------------------------------------------------
Patch vs: qla2xxx v8.01.03-k (in kernels 2.6.15.x+, including 2.6.16-prex)
- Include MEMSET, MEMCPY definitions
- Patched to compile on 64bit cleanly (thanks to Ming Zhang <mingz@ele.uri.edu>
for patch)
- Fixed possible race during initial enabling of Target Mode (thanks to
Mark Buechler <mark.buechler@gmail.com> for finding)
Summary of changes between versions 0.9.3.4 and 0.9.3.5
-------------------------------------------------------
Patch vs: qla2xxx v8.01.03-k (in kernels 2.6.15.x)
- Reset chip when switching from initiator to initator/target and back
implemented
- Use 2K loop_id's for 23xx chips and thus change how sessions are
tracked.
- Added Module Info
- Fixed module counting with initiator module preventing it from going
away w/out telling us (pointed out by Vladislav Bolkhovitin
<vst@vlnb.net>)
- Some minor debugging changes
Summary of changes between versions 0.9.3.2 of old driver and 0.9.3.4
---------------------------------------------------------------------
- Support for the latest in-tree Qlogic initiator added by Nathaniel
Clark <nate@misrule.us>
- Only one module is build and it interacts with a patched kernel
qla2xxx driver. The single module is called qla2x00tgt.ko instead of
having one for each driver type.
- Target mode can be enabled via a sysfs interface on a per card basis.
Under the appropriate scsi_host there is now an entry
target_mode_enabled, which can read and written.
NOTES:
The initiator's req_pkt function has never updated the request queue pointers.
So the implementation for continuation packets, has never worked correctly.
+84
View File
@@ -0,0 +1,84 @@
#
# Qlogic 2x00 SCSI target driver makefile
#
# Copyright (C) 2004 Vladislav Bolkhovitin <vst@vlnb.net>
# and Leonid Stoljar
#
# 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, version 2
# of the License.
#
# 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.
#
#
# Main targets:
# all (the default) : make all
# clean : clean files
# extraclean : clean + clean dependencies
# install : install
# uninstall : uninstall
#
# Notes :
# - install and uninstall must be made as root
#
#SCST_INC_DIR := /usr/local/include/scst
SCST_INC_DIR := $(SUBDIRS)/../../scst/include
SCST_DIR := $(shell pwd)/../../scst/src
EXTRA_CFLAGS += -I$(SCST_INC_DIR) -DFC_TARGET_SUPPORT
EXTRA_CFLAGS += -DFC_SCST_WWN_AUTH
EXTRA_CFLAGS += -DEXTRACHECKS
INSTALL_DIR := /lib/modules/$(shell uname -r)/extra
#EXTRA_CFLAGS += -DTRACING
EXTRA_CFLAGS += -DDEBUG_TGT -DDEBUG_WORK_IN_THREAD
#EXTRA_CFLAGS += -DDEBUG_WORK_IN_THREAD
ifeq ($(KVER),)
ifeq ($(KDIR),)
KDIR := /lib/modules/$(shell uname -r)/build
endif
else
KDIR := /lib/modules/$(KVER)/build
endif
QLA2XXX_INC_DIR := $(KDIR)/drivers/scsi/qla2xxx
EXTRA_CFLAGS += -I$(QLA2XXX_INC_DIR)
ifneq ($(KERNELRELEASE),)
obj-m := qla2x00tgt.o
qla2x00tgt-objs := qla2x00t.o
else
all: Modules.symvers
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m
tgt: Modules.symvers
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=n
install: all
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \
modules_install
-depmod -a
Modules.symvers: $(SCST_DIR)/Modules.symvers
-cp $(SCST_DIR)/Modules.symvers .
uninstall:
rm -f $(INSTALL_DIR)/qla2[23x]00tgt.ko
-/sbin/depmod -a
endif
clean:
rm -f *.o *.ko .*.cmd *.mod.c .*.d .depend *~ Modules.symvers
rm -rf .tmp_versions
extraclean: clean
.PHONY: all tgt install uninstall clean extraclean
+99
View File
@@ -0,0 +1,99 @@
Target driver for Qlogic 2200/2300 Fibre Channel cards
======================================================
Version 0.9.5-pre1, XX XXX 2006
-------------------------------
This driver has all required features and looks to be quite stable (for
beta) and useful. It is designed to work in conjunction with the
initiator driver from Linux kernel version 2.6, which is intended to
perform all the initialization and shutdown tasks. This driver needs to
be patched to enable the target mode and provide all necessary
callbacks, but it's still capable to work as initiator only. Mode, when
a host acts as the initiator and the target simultaneously, is supported
as well.
This version is compatible with SCST version 0.9.5 and higher.
Tested on stable kernels from http://www.kernel.org
NOTE: WWN-based authentification on 2200 cards doesn't always work from
---- the first "connect", but works on all subsequent attempts.
On this error message "Unable to find wwn login for loop
id XX, using loop id instead" is logged. So, just try again, eg
unload/load FC card driver on the initiator host. This is the
current limitation. Everyone who fix it or found a usable
workaround is welcome.
See also "ToDo" file for list of known issues and unimplemented
features.
Installation
------------
At first, make sure that the link "/lib/modules/`you_kernel_version`/build"
points to the source code for your currently running kernel.
Then, edit Makefile and set SCST_INC_DIR variable to point to the
directory, where SCST's public include files are located. If you install
QLA2x00 target driver's source code in the SCST's directory, then
SCST_INC_DIR will be set correctly for you ("../include").
The driver consists of two parts: the patch for initiator driver
"linux-2.6-qla2xxx-target.patch" and target driver in the
"qla2x00-target" directory.
Patch the kernel tree with "linux-2.6-qla2xxx-target.patch" patch.
To compile, type 'make'. It will build qla2x00tgt.ko module.
To install, type 'make install'. The target driver will be installed in
/lib/modules/`you_kernel_version`/kernel/drivers/scsi/scsi_tgt.
To uninstall, type 'make uninstall'.
The initiator driver must be loaded before the target one.
Then the target mode should be enabled via a sysfs interface on a per
card basis. Under the appropriate scsi_host there is an entry
target_mode_enabled, where you should write "1", like:
echo "1" >/sys/class/scsi_host/host0/target_mode_enabled
Compilation options
-------------------
There are the following compilation options, that could be commented
in/out in Makefile:
- FC_SCST_WWN_AUTH - turns on using remote initiator's WWN as
authentification name for scst_register_session_ex(). See note above
about limitations of this mode. If it is off, LOOP ID used instead of
WWN.
- DEBUG_TGT - turns on some debugging code, including some logging. Makes
the driver considerably bigger and slower, producing large amount of
log data.
- TRACING - turns on ability to log events. Makes the driver considerably
bigger and lead to some performance loss.
- DEBUG_WORK_IN_THREAD - makes SCST process incoming commands and
call the driver's callbacks in SCST thread context instead of tasklet
one. Useful for debugging and lead to some performance loss.
Credits
-------
Thanks to
* Nathaniel Clark <nate@misrule.us> for porting to new 2.6 kernel
initiator driver.
* Mark Buechler <mark.buechler@gmail.com> for the original
WWN-based authentification, a lot of useful suggestions, bug reports and
help in debugging.
* Ming Zhang <mingz@ele.uri.edu> for his fixes.
Vladislav Bolkhovitin <vst@vlnb.net>, http://scst.sourceforge.net
+29
View File
@@ -0,0 +1,29 @@
Known issues and unimplemented features
---------------------------------------
- If a Linux initiator asks for devices using INQUIRY command too soon
before the controller on the target is fully initialized in the
target mode, the initiator could receive garbage devices and the
messages "scsi: unknown device type 31" will be printed in the kernel
log on the initiator. After rescan on the initiator (eg by
rmmod/modprobe the driver) the correct devices will be added instead
of the garbage ones. This is actually Linux SCSI mid-level's problem
(although also could be the Qlogic firmware's one): type 31 is
"unknown or no device type", but the SCSI mid-level treats such
devices as real and adds them to the system. To avoid it, try to
leave the target enough time for initialization (some 10th seconds).
- Minor "ToDo"'s spread in the code.
- SNS support.
- Support for sense with length > 26 (is it possible at all?)
- Queue types (simple, ordered, etc.) support (needs appropriate support
from SCST and Linux kernel)
- On 2300 if on a tape with block size 0 we write block with size X
and then read it with bs <X the tape skips all blocks with size X
until the next correct block or filemark found, instead of returning
ILI with negative counter. Looks like the initiator retries the
command quetly. 2200 works correctly.
File diff suppressed because it is too large Load Diff
+180
View File
@@ -0,0 +1,180 @@
/*
* qla2x00t.h
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Leonid Stoljar
* Nathaniel Clark <nate@misrule.us>
*
* Significant modification 2006 by Nathaniel Clark <nate@misrule.us>
*
* Qlogic 2x00 SCSI target driver.
*
* 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, version 2
* of the License.
*
* 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.
*/
#ifndef __QLA2X00T_H
#define __QLA2X00T_H
/* Sneaky hack to skip redefinitions from qla_dbg.h */
#define __QLA_DBG_H
#include <qla_def.h>
#include "qla2x_tgt_def.h"
/* Version numbers, the same as for the kernel */
#define Q2T_VERSION(a,b,c,d) (((a) << 030) + ((b) << 020) + (c) << 010 + (d))
#define Q2T_VERSION_CODE Q2T_VERSION(0,9,5,0)
#define Q2T_VERSION_STRING "0.9.5-pre1"
#define Q2T_MAX_CDB_LEN 16
#define Q2T_TIMEOUT 10 /* in seconds */
/* Immediate notify status constants */
#define IMM_NTFY_LIP_RESET 0x000E
#define IMM_NTFY_IOCB_OVERFLOW 0x0016
#define IMM_NTFY_ABORT_TASK 0x0020
#define IMM_NTFY_PORT_LOGOUT 0x0029
#define IMM_NTFY_PORT_CONFIG 0x002A
#define IMM_NTFY_GLBL_TPRLO 0x002D
#define IMM_NTFY_GLBL_LOGO 0x002E
#define IMM_NTFY_RESOURCE 0x0034
#define IMM_NTFY_MSG_RX 0x0036
/* Immediate notify task flags */
#define IMM_NTFY_CLEAR_ACA 0x4000
#define IMM_NTFY_TARGET_RESET 0x2000
#define IMM_NTFY_LUN_RESET 0x1000
#define IMM_NTFY_CLEAR_TS 0x0400
#define IMM_NTFY_ABORT_TS 0x0200
/* Notify Acknowledge flags */
#define NOTIFY_ACK_RES_COUNT BIT_8
#define NOTIFY_ACK_CLEAR_LIP_RESET BIT_5
#define NOTIFY_ACK_TM_RESP_CODE_VALID BIT_4
/* Command's states */
#define Q2T_STATE_NEW 0 /* New command and SCST processes it */
#define Q2T_STATE_PROCESSED 1 /* SCST done processing */
#define Q2T_STATE_NEED_DATA 2 /* SCST needs data to process */
#define Q2T_STATE_DATA_IN 3 /* Data arrived and SCST processes it */
#define Q2T_STATE_ABORTED 4 /* Command aborted */
/* Misc */
#define Q2T_NULL_HANDLE 0
#define Q2T_SKIP_HANDLE (0xFFFFFFFE & ~CTIO_COMPLETION_HANDLE_MARK)
#define Q2T_BUSY_HANDLE (0xFFFFFFFF & ~CTIO_COMPLETION_HANDLE_MARK)
#define Q2T_DISABLE_LUN_STATUS_NOT_SET -1
/* ATIO task_codes fields */
#define ATIO_SIMPLE_QUEUE 0
#define ATIO_HEAD_OF_QUEUE 1
#define ATIO_ORDERED_QUEUE 2
#define ATIO_ACA_QUEUE 4
#define ATIO_UNTAGGED 5
/* CTIO additional flag ToDo: move to the appropriate place */
#define OF_TERM_EXCH BIT_14 /* Terminate exchange */
/* ToDo: move to the appropriate place */
#define CTIO_INVALID_RX_ID 0x08
#define CTIO_TIMEOUT 0x0B
#define CTIO_LIP_RESET 0x0E
#define CTIO_TARGET_RESET 0x17
#define CTIO_PORT_UNAVAILABLE 0x28
#define CTIO_PORT_LOGGED_OUT 0x29
/* TM failed response code, see FCP */
#define FC_TM_FAILED 0x5
#if (BITS_PER_LONG > 32) || defined(CONFIG_HIGHMEM64G)
#define pci_dma_lo32(a) (a & 0xffffffff)
#define pci_dma_hi32(a) ((((a) >> 16)>>16) & 0xffffffff)
#else
#define pci_dma_lo32(a) (a & 0xffffffff)
#define pci_dma_hi32(a) 0
#endif
/*
* Equivilant to IT Nexus (Initiator-Target)
*/
struct q2t_sess
{
struct list_head list;
struct scst_session *scst_sess;
struct q2t_tgt *tgt;
int loop_id;
};
struct q2t_cmd
{
struct q2t_sess *sess;
struct scst_cmd *scst_cmd;
int state;
atio_entry_t atio;
dma_addr_t dma_handle;
uint32_t iocb_cnt;
};
struct q2t_tgt
{
struct scst_tgt *scst_tgt;
uint32_t handle;
scsi_qla_host_t *ha;
int datasegs_per_cmd, datasegs_per_cont;
/* Target's flags, serialized by ha->hardware_lock */
unsigned int tgt_shutdown:1; /* The driver is being released */
unsigned int tgt_enable_64bit_addr:1; /* 64-bits PCI addressing anables */
wait_queue_head_t waitQ;
int notify_ack_expected;
volatile int modify_lun_expected;
volatile int disable_lun_status;
atomic_t sess_count; /* count sessions refing q2t_tgt */
struct list_head sess_list;
};
struct q2t_mgmt_cmd
{
struct q2t_sess *sess;
notify_entry_t notify_entry;
};
struct q2t_prm
{
struct q2t_tgt *tgt;
uint16_t req_cnt;
uint16_t seg_cnt;
int sg_cnt;
struct scatterlist *sg;
int bufflen;
scst_data_direction data_direction;
uint16_t rq_result;
uint16_t scsi_status;
unsigned char *sense_buffer;
unsigned int sense_buffer_len;
int residual;
struct q2t_cmd *cmd;
ctio_common_entry_t *pkt;
};
/* ha->hardware_lock supposed to be held on entry (to protect tgt->sess_list) */
static inline struct q2t_sess *q2t_find_sess_by_lid(struct q2t_tgt *tgt,
uint16_t lid)
{
struct q2t_sess *sess, *sess_tmp;
BUG_ON(tgt == NULL);
list_for_each_entry_safe(sess, sess_tmp, &tgt->sess_list, list) {
if (lid == (sess->loop_id))
return sess;
}
return NULL;
}
#endif /* __QLA2X00T_H */
+121
View File
@@ -0,0 +1,121 @@
/*
* qla2x_tgt.h
*
* Copyright (C) 2004-2005 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* Additional file for the target driver support.
*
* 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.
*/
/*
* This should be included only from within qla2xxx module.
*/
#ifndef __QLA2X_TGT_H
#define __QLA2X_TGT_H
#ifndef FC_TARGET_SUPPORT
#error __FILE__ " included without FC_TARGET_SUPPORT"
#endif
#include "qla2x_tgt_def.h"
extern struct qla2x_tgt_initiator qla_target;
/* declare here because it doesn't appear in any .h file just in qla_iocb.c */
extern request_t *qla2x00_req_pkt(scsi_qla_host_t *ha);
/********************************************************************\
* ISP Queue types left out of new QLogic driver (from old version)
\********************************************************************/
/*
* qla2x00_do_en_dis_lun
* Issue enable or disable LUN entry IOCB.
* Also set enable_target_mode in ha
*
* Input:
* ha = adapter block pointer.
*/
/* Caller MUST have hardware lock held */
static inline void
__qla2x00_en_dis_lun(scsi_qla_host_t *ha, int enable)
{
elun_entry_t *pkt;
if ((pkt = (elun_entry_t *)qla2x00_req_pkt(ha)) != NULL) {
pkt->entry_type = ENABLE_LUN_TYPE;
if (enable) {
pkt->command_count = QLA2X00_COMMAND_COUNT_INIT;
pkt->immed_notify_count = QLA2X00_IMMED_NOTIFY_COUNT_INIT;
pkt->timeout = 0xffff;
}
else
{
pkt->command_count = 0;
pkt->immed_notify_count = 0;
pkt->timeout = 0;
}
DEBUG2(printk(KERN_DEBUG
"scsi%lu:ENABLE_LUN IOCB imm %u cmd %u timeout %u\n",
ha->host_no, pkt->immed_notify_count,
pkt->command_count, pkt->timeout));
/* Issue command to ISP */
qla2x00_isp_cmd(ha);
ha->flags.enable_target_mode = enable;
}
#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
if (!pkt)
printk("qla2100_en_dis_lun: **** FAILED ****\n");
#endif
}
/* get-lock version */
static inline void
qla2x00_en_dis_lun(scsi_qla_host_t *ha, int enable)
{
unsigned long flags = 0;
spin_lock_irqsave(&ha->hardware_lock, flags);
__qla2x00_en_dis_lun(ha, enable);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
/*
* qla2x00_enable_lun
* Issue enable LUN entry IOCB.
*
* Input:
* ha = adapter block pointer.
*/
static inline void
qla2x00_enable_lun(scsi_qla_host_t *ha)
{
qla2x00_en_dis_lun(ha, 1);
}
/*
* qla2x00_disable_lun
* Issue enable LUN entry IOCB (command_count = 0).
*
* Input:
* ha = adapter block pointer.
*/
static inline void
qla2x00_disable_lun(scsi_qla_host_t *ha)
{
qla2x00_en_dis_lun(ha, 0);
}
#endif /* __QLA2X_TGT_H */
+370
View File
@@ -0,0 +1,370 @@
/*
* qla2x_tgt_def.h
*
* Copyright (C) 2004-2005 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* Additional file for the target driver support. Intended to define
* for 2200 and 2300 thier own exported symbols with unique names.
*
* 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.
*/
/*
* This is the global def file that is useful for including from the
* target portion.
*/
#ifndef __QLA2X_TGT_DEF_H
#define __QLA2X_TGT_DEF_H
#include "qla_def.h"
#ifndef FC_TARGET_SUPPORT
#error __FILE__ " included without FC_TARGET_SUPPORT"
#endif
#ifndef ENTER
#define ENTER(a)
#endif
#ifndef LEAVE
#define LEAVE(a)
#endif
#define QLA2X_TARGET_MAGIC 153
#define QLA2X_INITIATOR_MAGIC 54203
#define QLA2X00_COMMAND_COUNT_INIT 250
#define QLA2X00_IMMED_NOTIFY_COUNT_INIT 250
#define QLA_EXTENDED_LUN 1
/*
* Used to mark which completion handles (for RIO Status's) are for CTIO's
* vs. regular (non-target) info.
*/
#define CTIO_COMPLETION_HANDLE_MARK BIT_15
#if (CTIO_COMPLETION_HANDLE_MARK <= MAX_OUTSTANDING_COMMANDS)
#error "Hackish CTIO_COMPLETION_HANDLE_MARK no longer larger than MAX_OUTSTANDING_COMMANDS"
#endif
#define HANDLE_IS_CTIO_COMP(h) (h & CTIO_COMPLETION_HANDLE_MARK)
#ifndef OF_SS_MODE_0
/*
* ISP target entries - Flags bit definitions.
*/
#define OF_SS_MODE_0 0
#define OF_SS_MODE_1 1
#define OF_SS_MODE_2 2
#define OF_SS_MODE_3 3
#define OF_RESET BIT_5 /* Reset LIP flag */
#define OF_DATA_IN BIT_6 /* Data in to initiator */
/* (data from target to initiator) */
#define OF_DATA_OUT BIT_7 /* Data out from initiator */
/* (data from initiator to target) */
#define OF_NO_DATA (BIT_7 | BIT_6)
#define OF_INC_RC BIT_8 /* Increment command resource count */
#define OF_FAST_POST BIT_9 /* Enable mailbox fast posting. */
#define OF_SSTS BIT_15 /* Send SCSI status */
#endif
#ifndef DATASEGS_PER_COMMAND32
#define DATASEGS_PER_COMMAND32 3
#define DATASEGS_PER_CONT32 7
#define QLA_MAX_SG32(ql) \
(DATASEGS_PER_COMMAND32 + (((ql) > 0) ? DATASEGS_PER_CONT32*((ql) - 1) : 0))
#define DATASEGS_PER_COMMAND64 2
#define DATASEGS_PER_CONT64 5
#define QLA_MAX_SG64(ql) \
(DATASEGS_PER_COMMAND64 + (((ql) > 0) ? DATASEGS_PER_CONT64*((ql) - 1) : 0))
#endif
/********************************************************************\
* ISP Queue types left out of new QLogic driver (from old version)
\********************************************************************/
#ifndef ENABLE_LUN_TYPE
#define ENABLE_LUN_TYPE 0x0B /* Enable LUN entry. */
/*!
* ISP queue - enable LUN entry structure definition.
*/
typedef struct
{
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
uint32_t sys_define_2; /* System defined. */
uint8_t reserved_8;
uint8_t reserved_1;
uint16_t reserved_2;
uint32_t reserved_3;
uint8_t status;
uint8_t reserved_4;
uint8_t command_count; /* Number of ATIOs allocated. */
uint8_t immed_notify_count; /* Number of Immediate Notify entries allocated. */
uint16_t reserved_5;
uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */
uint16_t reserved_6[20];
} elun_entry_t;
#define ENABLE_LUN_SUCCESS 0x01
#define ENABLE_LUN_RC_NONZERO 0x04
#define ENABLE_LUN_INVALID_REQUEST 0x06
#define ENABLE_LUN_ALREADY_ENABLED 0x3E
#endif
#ifndef MODIFY_LUN_TYPE
#define MODIFY_LUN_TYPE 0x0C //!< Modify LUN entry.
/*
* ISP queue - modify LUN entry structure definition.
*/
typedef struct
{
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
uint32_t sys_define_2; /* System defined. */
uint8_t reserved_8;
uint8_t reserved_1;
uint8_t operators;
uint8_t reserved_2;
uint32_t reserved_3;
uint8_t status;
uint8_t reserved_4;
uint8_t command_count; /* Number of ATIOs allocated. */
uint8_t immed_notify_count; /* Number of Immediate Notify */
/* entries allocated. */
uint16_t reserved_5;
uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */
uint16_t reserved_7[20];
}modify_lun_entry_t;
#define MODIFY_LUN_SUCCESS 0x01
#define MODIFY_LUN_CMD_ADD BIT_0
#define MODIFY_LUN_CMD_SUB BIT_1
#define MODIFY_LUN_IMM_ADD BIT_2
#define MODIFY_LUN_IMM_SUB BIT_3
#endif
#define GET_TARGET_ID(ha, iocb) ((HAS_EXTENDED_IDS(ha)) \
? le16_to_cpu((iocb)->target.extended) \
: (uint16_t)(iocb)->target.id.standard)
#ifndef IMMED_NOTIFY_TYPE
#define IMMED_NOTIFY_TYPE 0x0D/* Immediate notify entry. */
/*
* ISP queue - immediate notify entry structure definition.
*/
typedef struct
{
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
uint32_t sys_define_2; /* System defined. */
target_id_t target;
uint16_t lun;
uint32_t reserved_2;
uint16_t status;
uint16_t task_flags;
uint16_t seq_id;
uint16_t reserved_5[11];
uint16_t scsi_status;
uint8_t sense_data[18];
}notify_entry_t;
#endif
#ifndef NOTIFY_ACK_TYPE
#define NOTIFY_ACK_TYPE 0x0E /* Notify acknowledge entry. */
/*
* ISP queue - notify acknowledge entry structure definition.
*/
typedef struct
{
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
uint32_t sys_define_2; /* System defined. */
target_id_t target;
uint8_t reserved_1;
uint8_t target_id;
uint16_t flags;
uint16_t resp_code;
uint16_t status;
uint16_t task_flags;
uint16_t seq_id;
uint16_t reserved_3[21];
}nack_entry_t;
#define NOTIFY_ACK_SUCCESS 0x01
#endif
#ifndef ACCEPT_TGT_IO_TYPE
#define ACCEPT_TGT_IO_TYPE 0x16 /* Accept target I/O entry. */
/*
* ISP queue - Accept Target I/O (ATIO) entry structure definition.
*/
typedef struct
{
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
uint32_t sys_define_2; /* System defined. */
target_id_t target;
uint16_t exchange_id;
uint16_t flags;
uint16_t status;
uint8_t command_ref;
uint8_t task_codes;
uint8_t task_flags;
uint8_t execution_codes;
uint8_t cdb[MAX_CMDSZ];
uint32_t data_length;
uint16_t lun;
uint8_t initiator_port_name[WWN_SIZE]; /* on qla23xx */
uint16_t reserved_32[6];
uint16_t ox_id;
}atio_entry_t;
#endif
#ifndef CONTINUE_TGT_IO_TYPE
#define CONTINUE_TGT_IO_TYPE 0x17
/*
* ISP queue - Continue Target I/O (CTIO) entry for status mode 0
* structure definition.
*/
typedef struct
{
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
uint32_t handle; /* System defined handle */
target_id_t target;
uint16_t exchange_id;
uint16_t flags;
uint16_t status;
uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */
uint16_t dseg_count; /* Data segment count. */
uint32_t relative_offset;
uint32_t residual;
uint16_t reserved_1[3];
uint16_t scsi_status;
uint32_t transfer_length;
uint32_t dseg_0_address[0];
}ctio_common_entry_t;
#define ATIO_PATH_INVALID 0x07
#define ATIO_CANT_PROV_CAP 0x16
#define ATIO_CDB_VALID 0x3D
#define ATIO_EXEC_READ BIT_1
#define ATIO_EXEC_WRITE BIT_0
#endif
#ifndef CTIO_A64_TYPE
#define CTIO_A64_TYPE 0x1F
typedef struct
{
ctio_common_entry_t common;
uint32_t dseg_0_address; /* Data segment 0 address. */
uint32_t dseg_0_length; /* Data segment 0 length. */
uint32_t dseg_1_address; /* Data segment 1 address. */
uint32_t dseg_1_length; /* Data segment 1 length. */
uint32_t dseg_2_address; /* Data segment 2 address. */
uint32_t dseg_2_length; /* Data segment 2 length. */
}ctio_entry_t;
#define CTIO_SUCCESS 0x01
#define CTIO_ABORTED 0x02
#define CTIO_ERROR_INVALID_RX_ID 0x08
#define CTIO_ERROR_PORT_LOGGED_OUT 0x29
#endif
#ifndef CTIO_RET_TYPE
#define CTIO_RET_TYPE 0x17 /* CTIO return entry */
/*
* ISP queue - CTIO returned entry structure definition.
*/
typedef struct
{
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
uint32_t handle; /* System defined handle. */
target_id_t target;
uint16_t exchange_id;
uint16_t flags;
uint16_t status;
uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */
uint16_t dseg_count; /* Data segment count. */
uint32_t relative_offset;
uint32_t residual;
uint16_t reserved_1[2];
uint16_t sense_length;
uint16_t scsi_status;
uint16_t response_length;
uint8_t sense_data[26];
}ctio_ret_entry_t;
#endif
/********************************************************************\
* Type Definitions used by initiator & target halves
\********************************************************************/
typedef enum {
DISABLE_TARGET_MODE = 0,
ENABLE_TARGET_MODE = 1
} qla2x_tgt_host_action_t;
struct qla2x_tgt_initiator
{
int magic;
/* Callbacks */
void (*tgt_response_pkt)(scsi_qla_host_t *ha, sts_entry_t *pkt);
void (*tgt_ctio_completion)(scsi_qla_host_t *ha, uint32_t handle);
void (*tgt_async_event)(uint16_t code, scsi_qla_host_t *ha, uint16_t *mailbox);
void (*tgt_host_action)(scsi_qla_host_t *ha, qla2x_tgt_host_action_t action);
};
struct qla2x_tgt_target
{
int magic;
/* Callbacks - H/W lock MUST be held while calling any*/
request_t *(*req_pkt)(scsi_qla_host_t *ha);
void (*isp_cmd)(scsi_qla_host_t *ha);
void (*enable_lun)(scsi_qla_host_t *ha);
void (*disable_lun)(scsi_qla_host_t *ha);
int (*issue_marker)(scsi_qla_host_t *ha);
cont_entry_t *(*req_cont_pkt)(scsi_qla_host_t *ha);
int (*get_counts)(scsi_qla_host_t *ha, uint8_t *cmd, uint8_t *imm);
};
int qla2xxx_tgt_register_driver(/* IN */ struct qla2x_tgt_initiator *tgt,
/* OUT */ struct qla2x_tgt_target *init);
void qla2xxx_tgt_unregister_driver(void);
/* from qla_os.c for __qla2x00_host_reset in qla_init.c*/
int
qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha);
int
qla2x00_wait_for_hba_online(scsi_qla_host_t *ha);
int
qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha);
#endif
+1183
View File
File diff suppressed because it is too large Load Diff
+2113
View File
File diff suppressed because it is too large Load Diff
+259
View File
@@ -0,0 +1,259 @@
/*
* QLogic Fibre Channel HBA Driver
* Copyright (c) 2003-2005 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
/*
* Driver debug definitions.
*/
/* #define QL_DEBUG_LEVEL_1 */ /* Output register accesses to COM1 */
/* #define QL_DEBUG_LEVEL_2 */ /* Output error msgs to COM1 */
/* #define QL_DEBUG_LEVEL_3 */ /* Output function trace msgs to COM1 */
/* #define QL_DEBUG_LEVEL_4 */ /* Output NVRAM trace msgs to COM1 */
/* #define QL_DEBUG_LEVEL_5 */ /* Output ring trace msgs to COM1 */
/* #define QL_DEBUG_LEVEL_6 */ /* Output WATCHDOG timer trace to COM1 */
/* #define QL_DEBUG_LEVEL_7 */ /* Output RISC load trace msgs to COM1 */
/* #define QL_DEBUG_LEVEL_8 */ /* Output ring saturation msgs to COM1 */
/* #define QL_DEBUG_LEVEL_9 */ /* Output IOCTL trace msgs */
/* #define QL_DEBUG_LEVEL_10 */ /* Output IOCTL error msgs */
/* #define QL_DEBUG_LEVEL_11 */ /* Output Mbx Cmd trace msgs */
/* #define QL_DEBUG_LEVEL_12 */ /* Output IP trace msgs */
/* #define QL_DEBUG_LEVEL_13 */ /* Output fdmi function trace msgs */
/* #define QL_DEBUG_LEVEL_14 */ /* Output RSCN trace msgs */
/*
* Local Macro Definitions.
*/
#if defined(QL_DEBUG_LEVEL_1) || defined(QL_DEBUG_LEVEL_2) || \
defined(QL_DEBUG_LEVEL_3) || defined(QL_DEBUG_LEVEL_4) || \
defined(QL_DEBUG_LEVEL_5) || defined(QL_DEBUG_LEVEL_6) || \
defined(QL_DEBUG_LEVEL_7) || defined(QL_DEBUG_LEVEL_8) || \
defined(QL_DEBUG_LEVEL_9) || defined(QL_DEBUG_LEVEL_10) || \
defined(QL_DEBUG_LEVEL_11) || defined(QL_DEBUG_LEVEL_12) || \
defined(QL_DEBUG_LEVEL_13) || defined(QL_DEBUG_LEVEL_14)
#define QL_DEBUG_ROUTINES
#endif
/*
* Macros use for debugging the driver.
*/
#undef ENTER_TRACE
#if defined(ENTER_TRACE)
#define ENTER(x) do { printk("qla2100 : Entering %s()\n", x); } while (0)
#define LEAVE(x) do { printk("qla2100 : Leaving %s()\n", x); } while (0)
#define ENTER_INTR(x) do { printk("qla2100 : Entering %s()\n", x); } while (0)
#define LEAVE_INTR(x) do { printk("qla2100 : Leaving %s()\n", x); } while (0)
#else
#define ENTER(x) do {} while (0)
#define LEAVE(x) do {} while (0)
#define ENTER_INTR(x) do {} while (0)
#define LEAVE_INTR(x) do {} while (0)
#endif
#if DEBUG_QLA2100
#define DEBUG(x) do {x;} while (0);
#else
#define DEBUG(x) do {} while (0);
#endif
#if defined(QL_DEBUG_LEVEL_1)
#define DEBUG1(x) do {x;} while (0);
#else
#define DEBUG1(x) do {} while (0);
#endif
#if defined(QL_DEBUG_LEVEL_2)
#define DEBUG2(x) do {x;} while (0);
#define DEBUG2_3(x) do {x;} while (0);
#define DEBUG2_3_11(x) do {x;} while (0);
#define DEBUG2_9_10(x) do {x;} while (0);
#define DEBUG2_11(x) do {x;} while (0);
#define DEBUG2_13(x) do {x;} while (0);
#else
#define DEBUG2(x) do {} while (0);
#endif
#if defined(QL_DEBUG_LEVEL_3)
#define DEBUG3(x) do {x;} while (0);
#define DEBUG2_3(x) do {x;} while (0);
#define DEBUG2_3_11(x) do {x;} while (0);
#define DEBUG3_11(x) do {x;} while (0);
#else
#define DEBUG3(x) do {} while (0);
#if !defined(QL_DEBUG_LEVEL_2)
#define DEBUG2_3(x) do {} while (0);
#endif
#endif
#if defined(QL_DEBUG_LEVEL_4)
#define DEBUG4(x) do {x;} while (0);
#else
#define DEBUG4(x) do {} while (0);
#endif
#if defined(QL_DEBUG_LEVEL_5)
#define DEBUG5(x) do {x;} while (0);
#else
#define DEBUG5(x) do {} while (0);
#endif
#if defined(QL_DEBUG_LEVEL_7)
#define DEBUG7(x) do {x;} while (0);
#else
#define DEBUG7(x) do {} while (0);
#endif
#if defined(QL_DEBUG_LEVEL_9)
#define DEBUG9(x) do {x;} while (0);
#define DEBUG9_10(x) do {x;} while (0);
#define DEBUG2_9_10(x) do {x;} while (0);
#else
#define DEBUG9(x) do {} while (0);
#endif
#if defined(QL_DEBUG_LEVEL_10)
#define DEBUG10(x) do {x;} while (0);
#define DEBUG2_9_10(x) do {x;} while (0);
#define DEBUG9_10(x) do {x;} while (0);
#else
#define DEBUG10(x) do {} while (0);
#if !defined(DEBUG2_9_10)
#define DEBUG2_9_10(x) do {} while (0);
#endif
#if !defined(DEBUG9_10)
#define DEBUG9_10(x) do {} while (0);
#endif
#endif
#if defined(QL_DEBUG_LEVEL_11)
#define DEBUG11(x) do{x;} while(0);
#if !defined(DEBUG2_11)
#define DEBUG2_11(x) do{x;} while(0);
#endif
#if !defined(DEBUG2_3_11)
#define DEBUG2_3_11(x) do{x;} while(0);
#endif
#if !defined(DEBUG3_11)
#define DEBUG3_11(x) do{x;} while(0);
#endif
#else
#define DEBUG11(x) do{} while(0);
#if !defined(QL_DEBUG_LEVEL_2)
#define DEBUG2_11(x) do{} while(0);
#if !defined(QL_DEBUG_LEVEL_3)
#define DEBUG2_3_11(x) do{} while(0);
#endif
#endif
#if !defined(QL_DEBUG_LEVEL_3)
#define DEBUG3_11(x) do{} while(0);
#endif
#endif
#if defined(QL_DEBUG_LEVEL_12)
#define DEBUG12(x) do {x;} while (0);
#else
#define DEBUG12(x) do {} while (0);
#endif
#if defined(QL_DEBUG_LEVEL_13)
#define DEBUG13(x) do {x;} while (0)
#if !defined(DEBUG2_13)
#define DEBUG2_13(x) do {x;} while(0)
#endif
#else
#define DEBUG13(x) do {} while (0)
#if !defined(QL_DEBUG_LEVEL_2)
#define DEBUG2_13(x) do {} while(0)
#endif
#endif
#if defined(QL_DEBUG_LEVEL_14)
#define DEBUG14(x) do {x;} while (0)
#else
#define DEBUG14(x) do {} while (0)
#endif
/*
* Firmware Dump structure definition
*/
#define FW_DUMP_SIZE_128K 0xBC000
#define FW_DUMP_SIZE_512K 0x2FC000
#define FW_DUMP_SIZE_1M 0x5FC000
struct qla2300_fw_dump {
uint16_t hccr;
uint16_t pbiu_reg[8];
uint16_t risc_host_reg[8];
uint16_t mailbox_reg[32];
uint16_t resp_dma_reg[32];
uint16_t dma_reg[48];
uint16_t risc_hdw_reg[16];
uint16_t risc_gp0_reg[16];
uint16_t risc_gp1_reg[16];
uint16_t risc_gp2_reg[16];
uint16_t risc_gp3_reg[16];
uint16_t risc_gp4_reg[16];
uint16_t risc_gp5_reg[16];
uint16_t risc_gp6_reg[16];
uint16_t risc_gp7_reg[16];
uint16_t frame_buf_hdw_reg[64];
uint16_t fpm_b0_reg[64];
uint16_t fpm_b1_reg[64];
uint16_t risc_ram[0xf800];
uint16_t stack_ram[0x1000];
uint16_t data_ram[1];
};
struct qla2100_fw_dump {
uint16_t hccr;
uint16_t pbiu_reg[8];
uint16_t mailbox_reg[32];
uint16_t dma_reg[48];
uint16_t risc_hdw_reg[16];
uint16_t risc_gp0_reg[16];
uint16_t risc_gp1_reg[16];
uint16_t risc_gp2_reg[16];
uint16_t risc_gp3_reg[16];
uint16_t risc_gp4_reg[16];
uint16_t risc_gp5_reg[16];
uint16_t risc_gp6_reg[16];
uint16_t risc_gp7_reg[16];
uint16_t frame_buf_hdw_reg[16];
uint16_t fpm_b0_reg[64];
uint16_t fpm_b1_reg[64];
uint16_t risc_ram[0xf000];
};
#define FW_DUMP_SIZE_24XX 0x2B0000
struct qla24xx_fw_dump {
uint32_t host_status;
uint32_t host_reg[32];
uint32_t shadow_reg[7];
uint16_t mailbox_reg[32];
uint32_t xseq_gp_reg[128];
uint32_t xseq_0_reg[16];
uint32_t xseq_1_reg[16];
uint32_t rseq_gp_reg[128];
uint32_t rseq_0_reg[16];
uint32_t rseq_1_reg[16];
uint32_t rseq_2_reg[16];
uint32_t cmd_dma_reg[16];
uint32_t req0_dma_reg[15];
uint32_t resp0_dma_reg[15];
uint32_t req1_dma_reg[15];
uint32_t xmt0_dma_reg[32];
uint32_t xmt1_dma_reg[32];
uint32_t xmt2_dma_reg[32];
uint32_t xmt3_dma_reg[32];
uint32_t xmt4_dma_reg[32];
uint32_t xmt_data_dma_reg[16];
uint32_t rcvt0_data_dma_reg[32];
uint32_t rcvt1_data_dma_reg[32];
uint32_t risc_gp_reg[128];
uint32_t lmc_reg[112];
uint32_t fpm_hdw_reg[192];
uint32_t fb_hdw_reg[176];
uint32_t code_ram[0x2000];
uint32_t ext_mem[1];
};
+2598
View File
File diff suppressed because it is too large Load Diff
+81
View File
@@ -0,0 +1,81 @@
#define QLA_MODEL_NAMES 0x4A
/*
* Adapter model names and descriptions.
*/
static char *qla2x00_model_name[QLA_MODEL_NAMES*2] = {
"QLA2340", "133MHz PCI-X to 2Gb FC, Single Channel", /* 0x100 */
"QLA2342", "133MHz PCI-X to 2Gb FC, Dual Channel", /* 0x101 */
"QLA2344", "133MHz PCI-X to 2Gb FC, Quad Channel", /* 0x102 */
"QCP2342", "cPCI to 2Gb FC, Dual Channel", /* 0x103 */
"QSB2340", "SBUS to 2Gb FC, Single Channel", /* 0x104 */
"QSB2342", "SBUS to 2Gb FC, Dual Channel", /* 0x105 */
"QLA2310", "Sun 66MHz PCI-X to 2Gb FC, Single Channel", /* 0x106 */
"QLA2332", "Sun 66MHz PCI-X to 2Gb FC, Single Channel", /* 0x107 */
"QCP2332", "Sun cPCI to 2Gb FC, Dual Channel", /* 0x108 */
"QCP2340", "cPCI to 2Gb FC, Single Channel", /* 0x109 */
"QLA2342", "Sun 133MHz PCI-X to 2Gb FC, Dual Channel", /* 0x10a */
"QCP2342", "Sun - cPCI to 2Gb FC, Dual Channel", /* 0x10b */
"QLA2350", "133MHz PCI-X to 2Gb FC, Single Channel", /* 0x10c */
"QLA2352", "133MHz PCI-X to 2Gb FC, Dual Channel", /* 0x10d */
"QLA2352", "Sun 133MHz PCI-X to 2Gb FC, Dual Channel", /* 0x10e */
" ", " ", /* 0x10f */
" ", " ", /* 0x110 */
" ", " ", /* 0x111 */
" ", " ", /* 0x112 */
" ", " ", /* 0x113 */
" ", " ", /* 0x114 */
"QLA2360", "133MHz PCI-X to 2Gb FC, Single Channel", /* 0x115 */
"QLA2362", "133MHz PCI-X to 2Gb FC, Dual Channel", /* 0x116 */
"QLE2360", "PCI-Express to 2Gb FC, Single Channel", /* 0x117 */
"QLE2362", "PCI-Express to 2Gb FC, Dual Channel", /* 0x118 */
"QLA200", "133MHz PCI-X to 2Gb FC Optical", /* 0x119 */
" ", " ", /* 0x11a */
" ", " ", /* 0x11b */
"QLA200P", "133MHz PCI-X to 2Gb FC SFP", /* 0x11c */
" ", " ", /* 0x11d */
" ", " ", /* 0x11e */
" ", " ", /* 0x11f */
" ", " ", /* 0x120 */
" ", " ", /* 0x121 */
" ", " ", /* 0x122 */
" ", " ", /* 0x123 */
" ", " ", /* 0x124 */
" ", " ", /* 0x125 */
" ", " ", /* 0x126 */
" ", " ", /* 0x127 */
" ", " ", /* 0x128 */
" ", " ", /* 0x129 */
" ", " ", /* 0x12a */
" ", " ", /* 0x12b */
" ", " ", /* 0x12c */
" ", " ", /* 0x12d */
" ", " ", /* 0x12e */
"QLA210", "133MHz PCI-X to 2Gb FC, Single Channel", /* 0x12f */
"EMC 250", "133MHz PCI-X to 2Gb FC, Single Channel", /* 0x130 */
"HP A7538A", "HP 1p2g PCI-X to 2Gb FC, Single Channel", /* 0x131 */
"QLA210", "Sun 133MHz PCI-X to 2Gb FC, Single Channel", /* 0x132 */
"QLA2460", "PCI-X 2.0 to 4Gb FC, Single Channel", /* 0x133 */
"QLA2462", "PCI-X 2.0 to 4Gb FC, Dual Channel", /* 0x134 */
"QMC2462", "IBM eServer BC 4Gb FC Expansion Card", /* 0x135 */
"QMC2462S", "IBM eServer BC 4Gb FC Expansion Card SFF", /* 0x136 */
"QLE2460", "PCI-Express to 4Gb FC, Single Channel", /* 0x137 */
"QLE2462", "PCI-Express to 4Gb FC, Dual Channel", /* 0x138 */
"QME2462", "Dell BS PCI-Express to 4Gb FC, Dual Channel", /* 0x139 */
" ", " ", /* 0x13a */
" ", " ", /* 0x13b */
" ", " ", /* 0x13c */
"QEM2462", "Sun Server I/O Module 4Gb FC, Dual Channel", /* 0x13d */
"QLE210", "PCI-Express to 2Gb FC, Single Channel", /* 0x13e */
"QLE220", "PCI-Express to 4Gb FC, Single Channel", /* 0x13f */
"QLA2460", "Sun PCI-X 2.0 to 4Gb FC, Single Channel", /* 0x140 */
"QLA2462", "Sun PCI-X 2.0 to 4Gb FC, Dual Channel", /* 0x141 */
"QLE2460", "Sun PCI-Express to 2Gb FC, Single Channel", /* 0x142 */
"QLE2462", "Sun PCI-Express to 4Gb FC, Single Channel", /* 0x143 */
"QEM2462" "Server I/O Module 4Gb FC, Dual Channel", /* 0x144 */
"QLE2440", "PCI-Express to 4Gb FC, Single Channel", /* 0x145 */
"QLE2464", "PCI-Express to 4Gb FC, Quad Channel", /* 0x146 */
"QLA2440", "PCI-X 2.0 to 4Gb FC, Single Channel", /* 0x147 */
" ", " ", /* 0x148 */
"QLA2340", "Sun 133MHz PCI-X to 2Gb FC, Single Channel", /* 0x149 */
};
+1059
View File
File diff suppressed because it is too large Load Diff
+316
View File
@@ -0,0 +1,316 @@
/*
* QLogic Fibre Channel HBA Driver
* Copyright (c) 2003-2005 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
#ifndef __QLA_GBL_H
#define __QLA_GBL_H
#include <linux/interrupt.h>
extern void qla2x00_remove_one(struct pci_dev *);
extern int qla2x00_probe_one(struct pci_dev *, struct qla_board_info *);
/*
* Global Function Prototypes in qla_init.c source file.
*/
extern int qla2x00_initialize_adapter(scsi_qla_host_t *);
extern int qla2100_pci_config(struct scsi_qla_host *);
extern int qla2300_pci_config(struct scsi_qla_host *);
extern int qla24xx_pci_config(scsi_qla_host_t *);
extern void qla2x00_reset_chip(struct scsi_qla_host *);
extern void qla24xx_reset_chip(struct scsi_qla_host *);
extern int qla2x00_chip_diag(struct scsi_qla_host *);
extern int qla24xx_chip_diag(struct scsi_qla_host *);
extern void qla2x00_config_rings(struct scsi_qla_host *);
extern void qla24xx_config_rings(struct scsi_qla_host *);
extern void qla2x00_reset_adapter(struct scsi_qla_host *);
extern void qla24xx_reset_adapter(struct scsi_qla_host *);
extern int qla2x00_nvram_config(struct scsi_qla_host *);
extern int qla24xx_nvram_config(struct scsi_qla_host *);
extern void qla2x00_update_fw_options(struct scsi_qla_host *);
extern void qla24xx_update_fw_options(scsi_qla_host_t *);
extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *);
extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *);
extern int qla24xx_load_risc_flash(scsi_qla_host_t *, uint32_t *);
extern fc_port_t *qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t);
extern int qla2x00_loop_resync(scsi_qla_host_t *);
extern int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *);
extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *);
extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *);
extern void qla2x00_restart_queues(scsi_qla_host_t *, uint8_t);
extern void qla2x00_rescan_fcports(scsi_qla_host_t *);
extern void qla2x00_update_fcports(scsi_qla_host_t *);
extern int qla2x00_abort_isp(scsi_qla_host_t *);
extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *);
extern void qla2x00_reg_remote_port(scsi_qla_host_t *, fc_port_t *);
/*
* Global Data in qla_os.c source file.
*/
extern char qla2x00_version_str[];
extern int ql2xlogintimeout;
extern int qlport_down_retry;
extern int ql2xplogiabsentdevice;
extern int ql2xloginretrycount;
extern int ql2xfdmienable;
extern int ql2xprocessrscn;
extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *);
extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *);
extern void qla2x00_cmd_timeout(srb_t *);
extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int, int);
extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *, int);
extern int qla2x00_down_timeout(struct semaphore *, unsigned long);
extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *);
extern int qla2x00_wait_for_hba_online(scsi_qla_host_t *);
extern void qla2xxx_wake_dpc(scsi_qla_host_t *);
/*
* Global Function Prototypes in qla_iocb.c source file.
*/
extern void qla2x00_isp_cmd(scsi_qla_host_t *);
extern uint16_t qla2x00_calc_iocbs_32(uint16_t);
extern uint16_t qla2x00_calc_iocbs_64(uint16_t);
extern void qla2x00_build_scsi_iocbs_32(srb_t *, cmd_entry_t *, uint16_t);
extern void qla2x00_build_scsi_iocbs_64(srb_t *, cmd_entry_t *, uint16_t);
extern int qla2x00_start_scsi(srb_t *sp);
extern int qla24xx_start_scsi(srb_t *sp);
int qla2x00_marker(scsi_qla_host_t *, uint16_t, uint16_t, uint8_t);
int __qla2x00_marker(scsi_qla_host_t *, uint16_t, uint16_t, uint8_t);
/*
* Global Function Prototypes in qla_mbx.c source file.
*/
extern int
qla2x00_load_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
extern int
qla2x00_execute_fw(scsi_qla_host_t *, uint32_t);
extern void
qla2x00_get_fw_version(scsi_qla_host_t *, uint16_t *,
uint16_t *, uint16_t *, uint16_t *, uint32_t *);
extern int
qla2x00_get_fw_options(scsi_qla_host_t *, uint16_t *);
extern int
qla2x00_set_fw_options(scsi_qla_host_t *, uint16_t *);
extern int
qla2x00_mbx_reg_test(scsi_qla_host_t *);
extern int
qla2x00_verify_checksum(scsi_qla_host_t *, uint32_t);
extern int
qla2x00_issue_iocb(scsi_qla_host_t *, void *, dma_addr_t, size_t);
extern int
qla2x00_abort_command(scsi_qla_host_t *, srb_t *);
#if USE_ABORT_TGT
extern int
qla2x00_abort_target(fc_port_t *);
#endif
extern int
qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *,
uint8_t *, uint16_t *);
extern int
qla2x00_get_retry_cnt(scsi_qla_host_t *, uint8_t *, uint8_t *, uint16_t *);
extern int
qla2x00_init_firmware(scsi_qla_host_t *, uint16_t);
extern int
qla2x00_get_port_database(scsi_qla_host_t *, fc_port_t *, uint8_t);
extern int
qla2x00_get_firmware_state(scsi_qla_host_t *, uint16_t *);
extern int
qla2x00_get_port_name(scsi_qla_host_t *, uint16_t, uint8_t *, uint8_t);
extern int
qla2x00_lip_reset(scsi_qla_host_t *);
extern int
qla2x00_send_sns(scsi_qla_host_t *, dma_addr_t, uint16_t, size_t);
extern int
qla2x00_login_fabric(scsi_qla_host_t *, uint16_t, uint8_t, uint8_t, uint8_t,
uint16_t *, uint8_t);
extern int
qla24xx_login_fabric(scsi_qla_host_t *, uint16_t, uint8_t, uint8_t, uint8_t,
uint16_t *, uint8_t);
extern int
qla2x00_login_local_device(scsi_qla_host_t *, fc_port_t *, uint16_t *,
uint8_t);
extern int
qla2x00_fabric_logout(scsi_qla_host_t *, uint16_t, uint8_t, uint8_t, uint8_t);
extern int
qla24xx_fabric_logout(scsi_qla_host_t *, uint16_t, uint8_t, uint8_t, uint8_t);
extern int
qla2x00_full_login_lip(scsi_qla_host_t *ha);
extern int
qla2x00_get_id_list(scsi_qla_host_t *, void *, dma_addr_t, uint16_t *);
extern int
qla2x00_get_resource_cnts(scsi_qla_host_t *, uint16_t *, uint16_t *, uint16_t *,
uint16_t *);
extern int
qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map);
extern int
qla2x00_get_link_status(scsi_qla_host_t *, uint16_t, link_stat_t *,
uint16_t *);
extern int
qla24xx_get_isp_stats(scsi_qla_host_t *, uint32_t *, uint32_t, uint16_t *);
extern int qla24xx_abort_command(scsi_qla_host_t *, srb_t *);
extern int qla24xx_abort_target(fc_port_t *);
extern int qla2x00_system_error(scsi_qla_host_t *);
extern int
qla2x00_get_serdes_params(scsi_qla_host_t *, uint16_t *, uint16_t *,
uint16_t *);
extern int
qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t);
extern int
qla2x00_stop_firmware(scsi_qla_host_t *);
/*
* Global Function Prototypes in qla_isr.c source file.
*/
extern irqreturn_t qla2100_intr_handler(int, void *, struct pt_regs *);
extern irqreturn_t qla2300_intr_handler(int, void *, struct pt_regs *);
extern irqreturn_t qla24xx_intr_handler(int, void *, struct pt_regs *);
extern void qla2x00_process_response_queue(struct scsi_qla_host *);
extern void qla24xx_process_response_queue(struct scsi_qla_host *);
/*
* Global Function Prototypes in qla_sup.c source file.
*/
extern void qla2x00_lock_nvram_access(scsi_qla_host_t *);
extern void qla2x00_unlock_nvram_access(scsi_qla_host_t *);
extern void qla2x00_release_nvram_protection(scsi_qla_host_t *);
extern uint16_t qla2x00_get_nvram_word(scsi_qla_host_t *, uint32_t);
extern void qla2x00_write_nvram_word(scsi_qla_host_t *, uint32_t, uint16_t);
extern uint32_t *qla24xx_read_flash_data(scsi_qla_host_t *, uint32_t *,
uint32_t, uint32_t);
extern uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
uint32_t);
extern uint8_t *qla24xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
uint32_t);
extern int qla2x00_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
uint32_t);
extern int qla24xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
uint32_t);
extern int qla2x00_beacon_on(struct scsi_qla_host *);
extern int qla2x00_beacon_off(struct scsi_qla_host *);
extern void qla2x00_beacon_blink(struct scsi_qla_host *);
extern int qla24xx_beacon_on(struct scsi_qla_host *);
extern int qla24xx_beacon_off(struct scsi_qla_host *);
extern void qla24xx_beacon_blink(struct scsi_qla_host *);
extern uint8_t *qla2x00_read_optrom_data(struct scsi_qla_host *, uint8_t *,
uint32_t, uint32_t);
extern int qla2x00_write_optrom_data(struct scsi_qla_host *, uint8_t *,
uint32_t, uint32_t);
extern uint8_t *qla24xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
uint32_t, uint32_t);
extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *,
uint32_t, uint32_t);
/*
* Global Function Prototypes in qla_dbg.c source file.
*/
extern void qla2100_fw_dump(scsi_qla_host_t *, int);
extern void qla2300_fw_dump(scsi_qla_host_t *, int);
extern void qla24xx_fw_dump(scsi_qla_host_t *, int);
extern void qla2100_ascii_fw_dump(scsi_qla_host_t *);
extern void qla2300_ascii_fw_dump(scsi_qla_host_t *);
extern void qla24xx_ascii_fw_dump(scsi_qla_host_t *);
extern void qla2x00_dump_regs(scsi_qla_host_t *);
extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
extern void qla2x00_print_scsi_cmd(struct scsi_cmnd *);
extern void qla2x00_dump_pkt(void *);
/*
* Global Function Prototypes in qla_gs.c source file.
*/
extern void *qla2x00_prep_ms_iocb(scsi_qla_host_t *, uint32_t, uint32_t);
extern void *qla24xx_prep_ms_iocb(scsi_qla_host_t *, uint32_t, uint32_t);
extern int qla2x00_ga_nxt(scsi_qla_host_t *, fc_port_t *);
extern int qla2x00_gid_pt(scsi_qla_host_t *, sw_info_t *);
extern int qla2x00_gpn_id(scsi_qla_host_t *, sw_info_t *);
extern int qla2x00_gnn_id(scsi_qla_host_t *, sw_info_t *);
extern int qla2x00_rft_id(scsi_qla_host_t *);
extern int qla2x00_rff_id(scsi_qla_host_t *);
extern int qla2x00_rnn_id(scsi_qla_host_t *);
extern int qla2x00_rsnn_nn(scsi_qla_host_t *);
extern void *qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t);
extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t);
extern int qla2x00_fdmi_register(scsi_qla_host_t *);
/*
* Global Function Prototypes in qla_rscn.c source file.
*/
extern fc_port_t *qla2x00_alloc_rscn_fcport(scsi_qla_host_t *, gfp_t);
extern int qla2x00_handle_port_rscn(scsi_qla_host_t *, uint32_t, fc_port_t *,
int);
extern void qla2x00_process_iodesc(scsi_qla_host_t *, struct mbx_entry *);
extern void qla2x00_cancel_io_descriptors(scsi_qla_host_t *);
/*
* Global Function Prototypes in qla_xioctl.c source file.
*/
#define qla2x00_enqueue_aen(ha, cmd, mode) do { } while (0)
#define qla2x00_alloc_ioctl_mem(ha) (0)
#define qla2x00_free_ioctl_mem(ha) do { } while (0)
/*
* Global Function Prototypes in qla_attr.c source file.
*/
struct class_device_attribute;
extern struct class_device_attribute *qla2x00_host_attrs[];
struct fc_function_template;
extern struct fc_function_template qla2xxx_transport_functions;
extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);
extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
extern void qla2x00_init_host_attr(scsi_qla_host_t *);
extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);
extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
#endif /* _QLA_GBL_H */
+1649
View File
File diff suppressed because it is too large Load Diff
+4142
View File
File diff suppressed because it is too large Load Diff
+171
View File
@@ -0,0 +1,171 @@
/*
* QLogic Fibre Channel HBA Driver
* Copyright (c) 2003-2005 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
static __inline__ uint16_t qla2x00_debounce_register(volatile uint16_t __iomem *);
/*
* qla2x00_debounce_register
* Debounce register.
*
* Input:
* port = register address.
*
* Returns:
* register value.
*/
static __inline__ uint16_t
qla2x00_debounce_register(volatile uint16_t __iomem *addr)
{
volatile uint16_t first;
volatile uint16_t second;
do {
first = RD_REG_WORD(addr);
barrier();
cpu_relax();
second = RD_REG_WORD(addr);
} while (first != second);
return (first);
}
static __inline__ int qla2x00_normalize_dma_addr(
dma_addr_t *e_addr, uint32_t *e_len,
dma_addr_t *ne_addr, uint32_t *ne_len);
/**
* qla2x00_normalize_dma_addr() - Normalize an DMA address.
* @e_addr: Raw DMA address
* @e_len: Raw DMA length
* @ne_addr: Normalized second DMA address
* @ne_len: Normalized second DMA length
*
* If the address does not span a 4GB page boundary, the contents of @ne_addr
* and @ne_len are undefined. @e_len is updated to reflect a normalization.
*
* Example:
*
* ffffabc0ffffeeee (e_addr) start of DMA address
* 0000000020000000 (e_len) length of DMA transfer
* ffffabc11fffeeed end of DMA transfer
*
* Is the 4GB boundary crossed?
*
* ffffabc0ffffeeee (e_addr)
* ffffabc11fffeeed (e_addr + e_len - 1)
* 00000001e0000003 ((e_addr ^ (e_addr + e_len - 1))
* 0000000100000000 ((e_addr ^ (e_addr + e_len - 1)) & ~(0xffffffff)
*
* Compute start of second DMA segment:
*
* ffffabc0ffffeeee (e_addr)
* ffffabc1ffffeeee (0x100000000 + e_addr)
* ffffabc100000000 (0x100000000 + e_addr) & ~(0xffffffff)
* ffffabc100000000 (ne_addr)
*
* Compute length of second DMA segment:
*
* 00000000ffffeeee (e_addr & 0xffffffff)
* 0000000000001112 (0x100000000 - (e_addr & 0xffffffff))
* 000000001fffeeee (e_len - (0x100000000 - (e_addr & 0xffffffff))
* 000000001fffeeee (ne_len)
*
* Adjust length of first DMA segment
*
* 0000000020000000 (e_len)
* 0000000000001112 (e_len - ne_len)
* 0000000000001112 (e_len)
*
* Returns non-zero if the specified address was normalized, else zero.
*/
static __inline__ int
qla2x00_normalize_dma_addr(
dma_addr_t *e_addr, uint32_t *e_len,
dma_addr_t *ne_addr, uint32_t *ne_len)
{
int normalized;
normalized = 0;
if ((*e_addr ^ (*e_addr + *e_len - 1)) & ~(0xFFFFFFFFULL)) {
/* Compute normalized crossed address and len */
*ne_addr = (0x100000000ULL + *e_addr) & ~(0xFFFFFFFFULL);
*ne_len = *e_len - (0x100000000ULL - (*e_addr & 0xFFFFFFFFULL));
*e_len -= *ne_len;
normalized++;
}
return (normalized);
}
static __inline__ void qla2x00_poll(scsi_qla_host_t *);
static inline void
qla2x00_poll(scsi_qla_host_t *ha)
{
ha->isp_ops.intr_handler(0, ha, NULL);
}
static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *);
/*
* This routine will wait for fabric devices for
* the reset delay.
*/
static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *ha)
{
uint16_t fw_state;
qla2x00_get_firmware_state(ha, &fw_state);
}
/**
* qla2x00_issue_marker() - Issue a Marker IOCB if necessary.
* @ha: HA context
* @ha_locked: is function called with the hardware lock
*
* Returns non-zero if a failure occured, else zero.
*/
static inline int
qla2x00_issue_marker(scsi_qla_host_t *ha, int ha_locked)
{
/* Send marker if required */
if (ha->marker_needed != 0) {
if (ha_locked) {
if (__qla2x00_marker(ha, 0, 0, MK_SYNC_ALL) !=
QLA_SUCCESS)
return (QLA_FUNCTION_FAILED);
} else {
if (qla2x00_marker(ha, 0, 0, MK_SYNC_ALL) !=
QLA_SUCCESS)
return (QLA_FUNCTION_FAILED);
}
ha->marker_needed = 0;
}
return (QLA_SUCCESS);
}
static inline uint8_t *host_to_fcp_swap(uint8_t *, uint32_t);
static inline uint8_t *
host_to_fcp_swap(uint8_t *fcp, uint32_t bsize)
{
uint32_t *ifcp = (uint32_t *) fcp;
uint32_t *ofcp = (uint32_t *) fcp;
uint32_t iter = bsize >> 2;
for (; iter ; iter--)
*ofcp++ = swab32(*ifcp++);
return fcp;
}
static inline int qla2x00_is_reserved_id(scsi_qla_host_t *, uint16_t);
static inline int
qla2x00_is_reserved_id(scsi_qla_host_t *ha, uint16_t loop_id)
{
if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
return (loop_id > NPH_LAST_HANDLE);
return ((loop_id > ha->last_loop_id && loop_id < SNS_FIRST_LOOP_ID) ||
loop_id == MANAGEMENT_SERVER || loop_id == BROADCAST);
};
+875
View File
@@ -0,0 +1,875 @@
/*
* QLogic Fibre Channel HBA Driver
* Copyright (c) 2003-2005 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
#include "qla_def.h"
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_tcq.h>
static inline uint16_t qla2x00_get_cmd_direction(struct scsi_cmnd *cmd);
static inline cont_entry_t *qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *);
static inline cont_a64_entry_t *qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *);
request_t *qla2x00_req_pkt(scsi_qla_host_t *ha);
/**
* qla2x00_get_cmd_direction() - Determine control_flag data direction.
* @cmd: SCSI command
*
* Returns the proper CF_* direction based on CDB.
*/
static inline uint16_t
qla2x00_get_cmd_direction(struct scsi_cmnd *cmd)
{
uint16_t cflags;
cflags = 0;
/* Set transfer direction */
if (cmd->sc_data_direction == DMA_TO_DEVICE)
cflags = CF_WRITE;
else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
cflags = CF_READ;
return (cflags);
}
/**
* qla2x00_calc_iocbs_32() - Determine number of Command Type 2 and
* Continuation Type 0 IOCBs to allocate.
*
* @dsds: number of data segment decriptors needed
*
* Returns the number of IOCB entries needed to store @dsds.
*/
uint16_t
qla2x00_calc_iocbs_32(uint16_t dsds)
{
uint16_t iocbs;
iocbs = 1;
if (dsds > 3) {
iocbs += (dsds - 3) / 7;
if ((dsds - 3) % 7)
iocbs++;
}
return (iocbs);
}
/**
* qla2x00_calc_iocbs_64() - Determine number of Command Type 3 and
* Continuation Type 1 IOCBs to allocate.
*
* @dsds: number of data segment decriptors needed
*
* Returns the number of IOCB entries needed to store @dsds.
*/
uint16_t
qla2x00_calc_iocbs_64(uint16_t dsds)
{
uint16_t iocbs;
iocbs = 1;
if (dsds > 2) {
iocbs += (dsds - 2) / 5;
if ((dsds - 2) % 5)
iocbs++;
}
return (iocbs);
}
/**
* qla2x00_prep_cont_type0_iocb() - Initialize a Continuation Type 0 IOCB.
* @ha: HA context
*
* Returns a pointer to the Continuation Type 0 IOCB packet.
*/
static inline cont_entry_t *
qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *ha)
{
cont_entry_t *cont_pkt;
/* Adjust ring index. */
ha->req_ring_index++;
if (ha->req_ring_index == ha->request_q_length) {
ha->req_ring_index = 0;
ha->request_ring_ptr = ha->request_ring;
} else {
ha->request_ring_ptr++;
}
cont_pkt = (cont_entry_t *)ha->request_ring_ptr;
/* Load packet defaults. */
*((uint32_t *)(&cont_pkt->entry_type)) =
__constant_cpu_to_le32(CONTINUE_TYPE);
return (cont_pkt);
}
/**
* qla2x00_prep_cont_type1_iocb() - Initialize a Continuation Type 1 IOCB.
* @ha: HA context
*
* Returns a pointer to the continuation type 1 IOCB packet.
*/
static inline cont_a64_entry_t *
qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *ha)
{
cont_a64_entry_t *cont_pkt;
/* Adjust ring index. */
ha->req_ring_index++;
if (ha->req_ring_index == ha->request_q_length) {
ha->req_ring_index = 0;
ha->request_ring_ptr = ha->request_ring;
} else {
ha->request_ring_ptr++;
}
cont_pkt = (cont_a64_entry_t *)ha->request_ring_ptr;
/* Load packet defaults. */
*((uint32_t *)(&cont_pkt->entry_type)) =
__constant_cpu_to_le32(CONTINUE_A64_TYPE);
return (cont_pkt);
}
/**
* qla2x00_build_scsi_iocbs_32() - Build IOCB command utilizing 32bit
* capable IOCB types.
*
* @sp: SRB command to process
* @cmd_pkt: Command type 2 IOCB
* @tot_dsds: Total number of segments to transfer
*/
void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt,
uint16_t tot_dsds)
{
uint16_t avail_dsds;
uint32_t *cur_dsd;
scsi_qla_host_t *ha;
struct scsi_cmnd *cmd;
cmd = sp->cmd;
/* Update entry type to indicate Command Type 2 IOCB */
*((uint32_t *)(&cmd_pkt->entry_type)) =
__constant_cpu_to_le32(COMMAND_TYPE);
/* No data transfer */
if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) {
cmd_pkt->byte_count = __constant_cpu_to_le32(0);
return;
}
ha = sp->ha;
cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(cmd));
/* Three DSDs are available in the Command Type 2 IOCB */
avail_dsds = 3;
cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address;
/* Load data segments */
if (cmd->use_sg != 0) {
struct scatterlist *cur_seg;
struct scatterlist *end_seg;
cur_seg = (struct scatterlist *)cmd->request_buffer;
end_seg = cur_seg + tot_dsds;
while (cur_seg < end_seg) {
cont_entry_t *cont_pkt;
/* Allocate additional continuation packets? */
if (avail_dsds == 0) {
/*
* Seven DSDs are available in the Continuation
* Type 0 IOCB.
*/
cont_pkt = qla2x00_prep_cont_type0_iocb(ha);
cur_dsd = (uint32_t *)&cont_pkt->dseg_0_address;
avail_dsds = 7;
}
*cur_dsd++ = cpu_to_le32(sg_dma_address(cur_seg));
*cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg));
avail_dsds--;
cur_seg++;
}
} else {
*cur_dsd++ = cpu_to_le32(sp->dma_handle);
*cur_dsd++ = cpu_to_le32(cmd->request_bufflen);
}
}
/**
* qla2x00_build_scsi_iocbs_64() - Build IOCB command utilizing 64bit
* capable IOCB types.
*
* @sp: SRB command to process
* @cmd_pkt: Command type 3 IOCB
* @tot_dsds: Total number of segments to transfer
*/
void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt,
uint16_t tot_dsds)
{
uint16_t avail_dsds;
uint32_t *cur_dsd;
scsi_qla_host_t *ha;
struct scsi_cmnd *cmd;
cmd = sp->cmd;
/* Update entry type to indicate Command Type 3 IOCB */
*((uint32_t *)(&cmd_pkt->entry_type)) =
__constant_cpu_to_le32(COMMAND_A64_TYPE);
/* No data transfer */
if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) {
cmd_pkt->byte_count = __constant_cpu_to_le32(0);
return;
}
ha = sp->ha;
cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(cmd));
/* Two DSDs are available in the Command Type 3 IOCB */
avail_dsds = 2;
cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address;
/* Load data segments */
if (cmd->use_sg != 0) {
struct scatterlist *cur_seg;
struct scatterlist *end_seg;
cur_seg = (struct scatterlist *)cmd->request_buffer;
end_seg = cur_seg + tot_dsds;
while (cur_seg < end_seg) {
dma_addr_t sle_dma;
cont_a64_entry_t *cont_pkt;
/* Allocate additional continuation packets? */
if (avail_dsds == 0) {
/*
* Five DSDs are available in the Continuation
* Type 1 IOCB.
*/
cont_pkt = qla2x00_prep_cont_type1_iocb(ha);
cur_dsd = (uint32_t *)cont_pkt->dseg_0_address;
avail_dsds = 5;
}
sle_dma = sg_dma_address(cur_seg);
*cur_dsd++ = cpu_to_le32(LSD(sle_dma));
*cur_dsd++ = cpu_to_le32(MSD(sle_dma));
*cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg));
avail_dsds--;
cur_seg++;
}
} else {
*cur_dsd++ = cpu_to_le32(LSD(sp->dma_handle));
*cur_dsd++ = cpu_to_le32(MSD(sp->dma_handle));
*cur_dsd++ = cpu_to_le32(cmd->request_bufflen);
}
}
/**
* qla2x00_start_scsi() - Send a SCSI command to the ISP
* @sp: command to send to the ISP
*
* Returns non-zero if a failure occured, else zero.
*/
int
qla2x00_start_scsi(srb_t *sp)
{
int ret;
unsigned long flags;
scsi_qla_host_t *ha;
struct scsi_cmnd *cmd;
uint32_t *clr_ptr;
uint32_t index;
uint32_t handle;
cmd_entry_t *cmd_pkt;
struct scatterlist *sg;
uint16_t cnt;
uint16_t req_cnt;
uint16_t tot_dsds;
struct device_reg_2xxx __iomem *reg;
/* Setup device pointers. */
ret = 0;
ha = sp->ha;
reg = &ha->iobase->isp;
cmd = sp->cmd;
/* So we know we haven't pci_map'ed anything yet */
tot_dsds = 0;
/* Send marker if required */
if (ha->marker_needed != 0) {
if (qla2x00_marker(ha, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) {
return (QLA_FUNCTION_FAILED);
}
ha->marker_needed = 0;
}
/* Acquire ring specific lock */
spin_lock_irqsave(&ha->hardware_lock, flags);
/* Check for room in outstanding command list. */
handle = ha->current_outstanding_cmd;
for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) {
handle++;
if (handle == MAX_OUTSTANDING_COMMANDS)
handle = 1;
if (ha->outstanding_cmds[handle] == 0)
break;
}
if (index == MAX_OUTSTANDING_COMMANDS)
goto queuing_error;
/* Map the sg table so we have an accurate count of sg entries needed */
if (cmd->use_sg) {
sg = (struct scatterlist *) cmd->request_buffer;
tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
cmd->sc_data_direction);
if (tot_dsds == 0)
goto queuing_error;
} else if (cmd->request_bufflen) {
dma_addr_t req_dma;
req_dma = pci_map_single(ha->pdev, cmd->request_buffer,
cmd->request_bufflen, cmd->sc_data_direction);
if (dma_mapping_error(req_dma))
goto queuing_error;
sp->dma_handle = req_dma;
tot_dsds = 1;
}
/* Calculate the number of request entries needed. */
req_cnt = ha->isp_ops.calc_req_entries(tot_dsds);
if (ha->req_q_cnt < (req_cnt + 2)) {
cnt = RD_REG_WORD_RELAXED(ISP_REQ_Q_OUT(ha, reg));
if (ha->req_ring_index < cnt)
ha->req_q_cnt = cnt - ha->req_ring_index;
else
ha->req_q_cnt = ha->request_q_length -
(ha->req_ring_index - cnt);
}
if (ha->req_q_cnt < (req_cnt + 2))
goto queuing_error;
/* Build command packet */
ha->current_outstanding_cmd = handle;
ha->outstanding_cmds[handle] = sp;
sp->ha = ha;
sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
ha->req_q_cnt -= req_cnt;
cmd_pkt = (cmd_entry_t *)ha->request_ring_ptr;
cmd_pkt->handle = handle;
/* Zero out remaining portion of packet. */
clr_ptr = (uint32_t *)cmd_pkt + 2;
memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
/* Set target ID and LUN number*/
SET_TARGET_ID(ha, cmd_pkt->target, sp->fcport->loop_id);
cmd_pkt->lun = cpu_to_le16(sp->cmd->device->lun);
/* Update tagged queuing modifier */
cmd_pkt->control_flags = __constant_cpu_to_le16(CF_SIMPLE_TAG);
/* Load SCSI command packet. */
memcpy(cmd_pkt->scsi_cdb, cmd->cmnd, cmd->cmd_len);
cmd_pkt->byte_count = cpu_to_le32((uint32_t)cmd->request_bufflen);
/* Build IOCB segments */
ha->isp_ops.build_iocbs(sp, cmd_pkt, tot_dsds);
/* Set total data segment count. */
cmd_pkt->entry_count = (uint8_t)req_cnt;
wmb();
DEBUG5(printk("%s(): IOCB data:\n", __func__));
DEBUG5(qla2x00_dump_buffer(
(uint8_t *)ha->request_ring_ptr, REQUEST_ENTRY_SIZE));
/* Adjust ring index. */
ha->req_ring_index++;
if (ha->req_ring_index == ha->request_q_length) {
ha->req_ring_index = 0;
ha->request_ring_ptr = ha->request_ring;
} else
ha->request_ring_ptr++;
sp->flags |= SRB_DMA_VALID;
sp->state = SRB_ACTIVE_STATE;
/* Set chip new ring index. */
WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), ha->req_ring_index);
RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, reg)); /* PCI Posting. */
/* Manage unprocessed RIO/ZIO commands in response queue. */
if (ha->flags.process_response_queue &&
ha->response_ring_ptr->signature != RESPONSE_PROCESSED)
qla2x00_process_response_queue(ha);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return (QLA_SUCCESS);
queuing_error:
if (cmd->use_sg && tot_dsds) {
sg = (struct scatterlist *) cmd->request_buffer;
pci_unmap_sg(ha->pdev, sg, cmd->use_sg,
cmd->sc_data_direction);
} else if (tot_dsds) {
pci_unmap_single(ha->pdev, sp->dma_handle,
cmd->request_bufflen, cmd->sc_data_direction);
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return (QLA_FUNCTION_FAILED);
}
/**
* qla2x00_marker() - Send a marker IOCB to the firmware.
* @ha: HA context
* @loop_id: loop ID
* @lun: LUN
* @type: marker modifier
*
* Can be called from both normal and interrupt context.
*
* Returns non-zero if a failure occured, else zero.
*/
int
__qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
uint8_t type)
{
mrk_entry_t *mrk;
struct mrk_entry_24xx *mrk24;
mrk24 = NULL;
mrk = (mrk_entry_t *)qla2x00_req_pkt(ha);
if (mrk == NULL) {
DEBUG2_3(printk("%s(%ld): failed to allocate Marker IOCB.\n",
__func__, ha->host_no));
return (QLA_FUNCTION_FAILED);
}
mrk->entry_type = MARKER_TYPE;
mrk->modifier = type;
if (type != MK_SYNC_ALL) {
if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
mrk24 = (struct mrk_entry_24xx *) mrk;
mrk24->nport_handle = cpu_to_le16(loop_id);
mrk24->lun[1] = LSB(lun);
mrk24->lun[2] = MSB(lun);
} else {
SET_TARGET_ID(ha, mrk->target, loop_id);
mrk->lun = cpu_to_le16(lun);
}
}
wmb();
qla2x00_isp_cmd(ha);
return (QLA_SUCCESS);
}
int
qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
uint8_t type)
{
int ret;
unsigned long flags = 0;
spin_lock_irqsave(&ha->hardware_lock, flags);
ret = __qla2x00_marker(ha, loop_id, lun, type);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return (ret);
}
/**
* qla2x00_req_pkt() - Retrieve a request packet from the request ring.
* @ha: HA context
*
* Note: The caller must hold the hardware lock before calling this routine.
*
* Returns NULL if function failed, else, a pointer to the request packet.
*/
request_t *
qla2x00_req_pkt(scsi_qla_host_t *ha)
{
device_reg_t __iomem *reg = ha->iobase;
request_t *pkt = NULL;
uint16_t cnt;
uint32_t *dword_ptr;
uint32_t timer;
uint16_t req_cnt = 1;
/* Wait 1 second for slot. */
for (timer = HZ; timer; timer--) {
if ((req_cnt + 2) >= ha->req_q_cnt) {
/* Calculate number of free request entries. */
if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
cnt = (uint16_t)RD_REG_DWORD(
&reg->isp24.req_q_out);
else
cnt = qla2x00_debounce_register(
ISP_REQ_Q_OUT(ha, &reg->isp));
if (ha->req_ring_index < cnt)
ha->req_q_cnt = cnt - ha->req_ring_index;
else
ha->req_q_cnt = ha->request_q_length -
(ha->req_ring_index - cnt);
}
/* If room for request in request ring. */
if ((req_cnt + 2) < ha->req_q_cnt) {
ha->req_q_cnt--;
pkt = ha->request_ring_ptr;
/* Zero out packet. */
dword_ptr = (uint32_t *)pkt;
for (cnt = 0; cnt < REQUEST_ENTRY_SIZE / 4; cnt++)
*dword_ptr++ = 0;
/* Set system defined field. */
pkt->sys_define = (uint8_t)ha->req_ring_index;
/* Set entry count. */
pkt->entry_count = 1;
break;
}
/* Release ring specific lock */
spin_unlock(&ha->hardware_lock);
udelay(2); /* 2 us */
/* Check for pending interrupts. */
/* During init we issue marker directly */
if (!ha->marker_needed)
qla2x00_poll(ha);
spin_lock_irq(&ha->hardware_lock);
}
if (!pkt) {
DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
}
return (pkt);
}
/**
* qla2x00_isp_cmd() - Modify the request ring pointer.
* @ha: HA context
*
* Note: The caller must hold the hardware lock before calling this routine.
*/
void
qla2x00_isp_cmd(scsi_qla_host_t *ha)
{
device_reg_t __iomem *reg = ha->iobase;
DEBUG5(printk("%s(): IOCB data:\n", __func__));
DEBUG5(qla2x00_dump_buffer(
(uint8_t *)ha->request_ring_ptr, REQUEST_ENTRY_SIZE));
/* Adjust ring index. */
ha->req_ring_index++;
if (ha->req_ring_index == ha->request_q_length) {
ha->req_ring_index = 0;
ha->request_ring_ptr = ha->request_ring;
} else
ha->request_ring_ptr++;
/* Set chip new ring index. */
if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
WRT_REG_DWORD(&reg->isp24.req_q_in, ha->req_ring_index);
RD_REG_DWORD_RELAXED(&reg->isp24.req_q_in);
} else {
WRT_REG_WORD(ISP_REQ_Q_IN(ha, &reg->isp), ha->req_ring_index);
RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, &reg->isp));
}
}
/**
* qla24xx_calc_iocbs() - Determine number of Command Type 3 and
* Continuation Type 1 IOCBs to allocate.
*
* @dsds: number of data segment decriptors needed
*
* Returns the number of IOCB entries needed to store @dsds.
*/
static inline uint16_t
qla24xx_calc_iocbs(uint16_t dsds)
{
uint16_t iocbs;
iocbs = 1;
if (dsds > 1) {
iocbs += (dsds - 1) / 5;
if ((dsds - 1) % 5)
iocbs++;
}
return iocbs;
}
/**
* qla24xx_build_scsi_iocbs() - Build IOCB command utilizing Command Type 7
* IOCB types.
*
* @sp: SRB command to process
* @cmd_pkt: Command type 3 IOCB
* @tot_dsds: Total number of segments to transfer
*/
static inline void
qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
uint16_t tot_dsds)
{
uint16_t avail_dsds;
uint32_t *cur_dsd;
scsi_qla_host_t *ha;
struct scsi_cmnd *cmd;
cmd = sp->cmd;
/* Update entry type to indicate Command Type 3 IOCB */
*((uint32_t *)(&cmd_pkt->entry_type)) =
__constant_cpu_to_le32(COMMAND_TYPE_7);
/* No data transfer */
if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) {
cmd_pkt->byte_count = __constant_cpu_to_le32(0);
return;
}
ha = sp->ha;
/* Set transfer direction */
if (cmd->sc_data_direction == DMA_TO_DEVICE)
cmd_pkt->task_mgmt_flags =
__constant_cpu_to_le16(TMF_WRITE_DATA);
else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
cmd_pkt->task_mgmt_flags =
__constant_cpu_to_le16(TMF_READ_DATA);
/* One DSD is available in the Command Type 3 IOCB */
avail_dsds = 1;
cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address;
/* Load data segments */
if (cmd->use_sg != 0) {
struct scatterlist *cur_seg;
struct scatterlist *end_seg;
cur_seg = (struct scatterlist *)cmd->request_buffer;
end_seg = cur_seg + tot_dsds;
while (cur_seg < end_seg) {
dma_addr_t sle_dma;
cont_a64_entry_t *cont_pkt;
/* Allocate additional continuation packets? */
if (avail_dsds == 0) {
/*
* Five DSDs are available in the Continuation
* Type 1 IOCB.
*/
cont_pkt = qla2x00_prep_cont_type1_iocb(ha);
cur_dsd = (uint32_t *)cont_pkt->dseg_0_address;
avail_dsds = 5;
}
sle_dma = sg_dma_address(cur_seg);
*cur_dsd++ = cpu_to_le32(LSD(sle_dma));
*cur_dsd++ = cpu_to_le32(MSD(sle_dma));
*cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg));
avail_dsds--;
cur_seg++;
}
} else {
*cur_dsd++ = cpu_to_le32(LSD(sp->dma_handle));
*cur_dsd++ = cpu_to_le32(MSD(sp->dma_handle));
*cur_dsd++ = cpu_to_le32(cmd->request_bufflen);
}
}
/**
* qla24xx_start_scsi() - Send a SCSI command to the ISP
* @sp: command to send to the ISP
*
* Returns non-zero if a failure occured, else zero.
*/
int
qla24xx_start_scsi(srb_t *sp)
{
int ret;
unsigned long flags;
scsi_qla_host_t *ha;
struct scsi_cmnd *cmd;
uint32_t *clr_ptr;
uint32_t index;
uint32_t handle;
struct cmd_type_7 *cmd_pkt;
struct scatterlist *sg;
uint16_t cnt;
uint16_t req_cnt;
uint16_t tot_dsds;
struct device_reg_24xx __iomem *reg;
/* Setup device pointers. */
ret = 0;
ha = sp->ha;
reg = &ha->iobase->isp24;
cmd = sp->cmd;
/* So we know we haven't pci_map'ed anything yet */
tot_dsds = 0;
/* Send marker if required */
if (ha->marker_needed != 0) {
if (qla2x00_marker(ha, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) {
return QLA_FUNCTION_FAILED;
}
ha->marker_needed = 0;
}
/* Acquire ring specific lock */
spin_lock_irqsave(&ha->hardware_lock, flags);
/* Check for room in outstanding command list. */
handle = ha->current_outstanding_cmd;
for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) {
handle++;
if (handle == MAX_OUTSTANDING_COMMANDS)
handle = 1;
if (ha->outstanding_cmds[handle] == 0)
break;
}
if (index == MAX_OUTSTANDING_COMMANDS)
goto queuing_error;
/* Map the sg table so we have an accurate count of sg entries needed */
if (cmd->use_sg) {
sg = (struct scatterlist *) cmd->request_buffer;
tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
cmd->sc_data_direction);
if (tot_dsds == 0)
goto queuing_error;
} else if (cmd->request_bufflen) {
dma_addr_t req_dma;
req_dma = pci_map_single(ha->pdev, cmd->request_buffer,
cmd->request_bufflen, cmd->sc_data_direction);
if (dma_mapping_error(req_dma))
goto queuing_error;
sp->dma_handle = req_dma;
tot_dsds = 1;
}
req_cnt = qla24xx_calc_iocbs(tot_dsds);
if (ha->req_q_cnt < (req_cnt + 2)) {
cnt = (uint16_t)RD_REG_DWORD_RELAXED(&reg->req_q_out);
if (ha->req_ring_index < cnt)
ha->req_q_cnt = cnt - ha->req_ring_index;
else
ha->req_q_cnt = ha->request_q_length -
(ha->req_ring_index - cnt);
}
if (ha->req_q_cnt < (req_cnt + 2))
goto queuing_error;
/* Build command packet. */
ha->current_outstanding_cmd = handle;
ha->outstanding_cmds[handle] = sp;
sp->ha = ha;
sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
ha->req_q_cnt -= req_cnt;
cmd_pkt = (struct cmd_type_7 *)ha->request_ring_ptr;
cmd_pkt->handle = handle;
/* Zero out remaining portion of packet. */
/* tagged queuing modifier -- default is TSK_SIMPLE (0). */
clr_ptr = (uint32_t *)cmd_pkt + 2;
memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
/* Set NPORT-ID and LUN number*/
cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
/* Load SCSI command packet. */
memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len);
host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb));
cmd_pkt->byte_count = cpu_to_le32((uint32_t)cmd->request_bufflen);
/* Build IOCB segments */
qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds);
/* Set total data segment count. */
cmd_pkt->entry_count = (uint8_t)req_cnt;
wmb();
DEBUG5(printk("%s(): IOCB data:\n", __func__));
DEBUG5(qla2x00_dump_buffer(
(uint8_t *)ha->request_ring_ptr, REQUEST_ENTRY_SIZE));
/* Adjust ring index. */
ha->req_ring_index++;
if (ha->req_ring_index == ha->request_q_length) {
ha->req_ring_index = 0;
ha->request_ring_ptr = ha->request_ring;
} else
ha->request_ring_ptr++;
sp->flags |= SRB_DMA_VALID;
sp->state = SRB_ACTIVE_STATE;
/* Set chip new ring index. */
WRT_REG_DWORD(&reg->req_q_in, ha->req_ring_index);
RD_REG_DWORD_RELAXED(&reg->req_q_in); /* PCI Posting. */
/* Manage unprocessed RIO/ZIO commands in response queue. */
if (ha->flags.process_response_queue &&
ha->response_ring_ptr->signature != RESPONSE_PROCESSED)
qla24xx_process_response_queue(ha);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_SUCCESS;
queuing_error:
if (cmd->use_sg && tot_dsds) {
sg = (struct scatterlist *) cmd->request_buffer;
pci_unmap_sg(ha->pdev, sg, cmd->use_sg,
cmd->sc_data_direction);
} else if (tot_dsds) {
pci_unmap_single(ha->pdev, sp->dma_handle,
cmd->request_bufflen, cmd->sc_data_direction);
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_FUNCTION_FAILED;
}
+1696
View File
File diff suppressed because it is too large Load Diff
+2466
View File
File diff suppressed because it is too large Load Diff
+2809
View File
File diff suppressed because it is too large Load Diff
+1426
View File
File diff suppressed because it is too large Load Diff
+27
View File
@@ -0,0 +1,27 @@
/*
* QLogic Fibre Channel HBA Driver
* Copyright (c) 2003-2005 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
/*
* Compile time Options:
* 0 - Disable and 1 - Enable
*/
#define DEBUG_QLA2100 0 /* For Debug of qla2x00 */
#define USE_ABORT_TGT 1 /* Use Abort Target mbx cmd */
#define MAX_RETRIES_OF_ISP_ABORT 5
/* Max time to wait for the loop to be in LOOP_READY state */
#define MAX_LOOP_TIMEOUT (60 * 5)
#define EH_ACTIVE 1 /* Error handler active */
/*
* Some vendor subsystems do not recover properly after a device reset. Define
* the following to force a logout after a successful device reset.
*/
#undef LOGOUT_AFTER_DEVICE_RESET
#include "qla_version.h"
+1655
View File
File diff suppressed because it is too large Load Diff
+15
View File
@@ -0,0 +1,15 @@
/*
* QLogic Fibre Channel HBA Driver
* Copyright (c) 2003-2005 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
/*
* Driver version
*/
#define QLA2XXX_VERSION "8.01.04-k"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 1
#define QLA_DRIVER_PATCH_VER 4
#define QLA_DRIVER_BETA_VER 0
+340
View File
@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
+177
View File
@@ -0,0 +1,177 @@
Summary of changes between versions 0.9.4 and 0.9.5
---------------------------------------------------
- Fixed many found task management related problems, especially in the
RESETs area. DEBUG_TM compilation option added (see README).
- Timer-based retries for targets after SCST_TGT_RES_QUEUE_FULL status
implemented.
- Fixed broken CDROM FILEIO. Before that it always reported
"No medium found"
- Fixed READ(6)/WRITE(6) CDB decoding for block devices.
This bug prevented FreeBSD initiator from working.
- Implemented sgv_pool. It is mempool-like interface, which caches
built SG-vectors in order not to rebuild them again for every
subsequent command, so saves performance price of building
SG-vectors, including pages allocation, and of additional context
switches.
- For ABORTED commands xmit_response() now called. A target driver
should recognized such commands using new function
scst_cmd_aborted(). Also there are some other cleanups, improvements
and interfaces changes that affect target drivers and dev handlers.
You can find their full list by diff'ing scsi_tgt.h between versions
0.9.4 and 0.9.5.
- Function alloc_data_buf() added to struct scst_tgt_template as well
as data_buf_tgt_alloc added to struct scst_cmd to allow a target
driver implement own memory management handler (by Arne Redlich
<arne.redlich@xiranet.com>).
- Exported symbols are now not GPL'ed
- Various cleanups and bug fixes.
Summary of changes between versions 0.9.3 and 0.9.4
---------------------------------------------------
- Support for 2.4 kernels has been removed
- Added on_free_cmd() callback for dev handlers
- Fixed BUG() on task aborts.
- Fixed WCE (Write Cache Enabled) handling in FILEIO
(by Ming Zhang <mingz@ele.uri.edu>)
- Minor cleanups and bug fixes.
Summary of changes between versions 0.9.3-pre4 and 0.9.3
--------------------------------------------------------
- Fixed IO errors on initiators (return code 20008) under considerable
load, because of returned BUSY status. Now QUEUE FULL status returned
instead.
- Fixed "deadlock" on sessions creation.
- Fixed support for > 2TB storage device in FILEIO handler
(by Ming Zhang <mingz@ele.uri.edu>)
- NULLIO added to FILEIO handler (by Ming Zhang <mingz@ele.uri.edu>)
- Commands serialization now per-(session, device), i.e. tgt_dev.
- Minor cleanups and bug fixes
Summary of changes between versions 0.9.3-pre2 and 0.9.3-pre4
-------------------------------------------------------------
- Sessions registration and unregistrations reimplemented. The
interface with target drivers changed (made much more simple, but
incompatible).
- Some kmalloc()'s converted to SLAB caches (by Nathaniel Clark
<nate@misrule.us>)
- Too low timeouts for management operations in scst_disk were
increased
- Cleanups and bug fixes, including several race-based crashes
Summary of changes between versions 0.9.3-pre1 and 0.9.3-pre2
-------------------------------------------------------------
- Task management was considerably redone. Particularly, now the result
of ABORT TASK is returned to remote initiator immediately, except if
the result of the aborted command is already started to be sent.
- Per-session commands serialization implemented as part of "device
blocking" cleanup.
- UA generating after MODE SELECT and LOG SELECT implemented
- STRICT_SERIALIZING compile-time option added for those who need most
robust task management and willing to pay some performance cost for
that (see README)
- IRQ spinlocks were replaced by BH ones, where appropriate.
- Ability to change ISO image on the fly in CDROM FILEIO module added
- Cleanups and bug fixes
Summary of changes between versions 0.9.2 and 0.9.3-pre1
--------------------------------------------------------
- Sophisticated per-initiator access and devices visibility management added
(different initiators now could see different set of devices with
different permissions)
- FILEIO dev handler was reimplemented in most areas, including:
* Management interface via /proc added
* Various defects using devices/files larger 2Gb were fixed. Thanks
to Mark Buechler <mark.buechler@gmail.com>
* New CDROM FILEIO handler added.
* Now per-session threads created to improve concurrent performance.
* New flags added that allow using virtual devices as read only,
with write through caching or in O_DIRECT mode.
* Task management support added.
- RAID controller (type 0xC) dev handler added.
- SCSI processor (type 3) dev handler added.
- Sessions unregistration contexts cleanup.
- Dev handler's on_free_cmd() was dropped. Target driver's flag
"thread_per_session" was dropped as well.
- Internal locking partially redone.
- A lot of stability/bug fixes, cleanups and performance improvements.
Summary of changes between versions 0.9.1 and 0.9.2
---------------------------------------------------
- 2.6 support, developed and tested on 2.6.7.
- FILEIO/BLKDEV virtual disk device handler added. See main README for
details.
- /proc updates, "trace_log_level" entry added to change traced
events on the fly.
- Some internal interfaces changed, see the documentation.
- Device handlers' source code layout changed, all device handlers
live in one subdirectory now.
- Crash on memory allocation failure while building SG data vector
fixed.
- Other minor fixes
Summary of changes between versions 0.9.0a and 0.9.1
----------------------------------------------------
- scst_debug.* files are also installed together with scsi_tgt.h
(required by QLA2x00 target and could be useful for other target
drivers)
- CDB length for unknown commands (e.g. vendor ones) is now determined
from CDB
- Race with the commands serialization on one drive fixed
- Cleanup
+48
View File
@@ -0,0 +1,48 @@
#
# Common makefile for SCSI target mid-level and its drivers
#
# Copyright (C) 2004 Vladislav Bolkhovitin <vst@vlnb.net>
# and Leonid Stoljar
#
# 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, version 2
# of the License.
#
# 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.
#
#
# Decide to use which kernel src. If not specified, is current running kernel.
#export KDIR=/usr/src/linux-2.6
SCST_DIR=src
all:
cd $(SCST_DIR) && $(MAKE) $@
install:
cd $(SCST_DIR) && $(MAKE) $@
uninstall:
cd $(SCST_DIR) && $(MAKE) $@
clean:
cd $(SCST_DIR) && $(MAKE) $@
extraclean:
cd $(SCST_DIR) && $(MAKE) $@
help:
@echo " all (the default) : make all"
@echo " clean : clean files"
@echo " extraclean : clean + clean dependencies"
@echo " install : install"
@echo " uninstall : uninstall"
@echo " Notes :"
@echo " - install and uninstall must be made as root"
.PHONY: all install uninstall clean extraclean help
+408
View File
@@ -0,0 +1,408 @@
Generic SCSI target mid-level for Linux (SCST)
==============================================
Version 0.9.5, XX XXX 2006
--------------------------
SCST is designed to provide unified, consistent interface between SCSI
target drivers and Linux kernel and simplify target drivers development
as much as possible. Detail description of SCST's features and internals
could be found in "Generic SCSI Target Middle Level for Linux" document
SCST's Internet page http://scst.sourceforge.net.
SCST looks to be quite stable (for beta) and useful. It supports disks
(SCSI type 0), tapes (type 1), processor (type 3), CDROM's (type 5), MO
disks (type 7), medium changers (type 8) and RAID controller (type 0xC).
There are also FILEIO and "performance" device handlers. In addition,
starting from version 0.9.3 advanced per-initiator access and devices
visibility management is added, so different initiators could see
different set of devices with different access permissions. See below
for details.
This is more or less stable (but still beta) version.
Tested mostly on "vanilla" 2.6.17.8 kernel from kernel.org.
Device handlers
---------------
Device specific drivers (device handlers) are plugins for SCST, which
help SCST to analyze incoming requests and determine parameters,
specific to various types of devices. If an appropriate device handler
for a SCSI device type isn't loaded, SCST doesn't know how to handle
devices of this type, so they will be invisible for remote initiators
(more precisely, "LUN not supported" sense code will be returned).
In addition to device handlers for real devices, there are FILEIO and
"performance" ones.
FILEIO device handler works over files on file systems and makes from
them virtual remotely available SCSI disks or CDROM's. In addition, it
allows to work directly over a block device, e.g. local IDE or SCSI disk
or ever disk partition, where there is no file systems overhead. Using
block devices comparing to sending SCSI commands directly to SCSI
mid-level via scsi_do_req() has advantage that data are transfered via
system cache, so it is possible to fully benefit from caching and read
ahead performed by Linux's VM subsystem. The only disadvantage here that
there is superfluous data copying between the cache and SCST's buffers.
This issue is going to be addressed in the next release. Virtual CDROM's
are useful for remote installation. See below for details how to setup
and use FILEIO device handler.
"Performance" device handlers for disks, MO disks and tapes in their
exec() method skip (pretend to execute) all READ and WRITE operations
and thus provide a way for direct link performance measurements without
overhead of actual data transferring from/to underlying SCSI device.
Starting from 0.9.3 these handlers are incorporated inside of
corresponding device handler for real device and could be assigned on
run-time via "assign" command in "/proc/scsi_tgt/scsi_tgt" (see below).
NOTE: Since "perf" device handlers on READ operations don't touch the
==== commands' data buffer, it is returned to remote initiators as it
was allocated, without even being zeroed. Thus, "perf" device
handlers impose some security risk, so use them with caution.
Installation
------------
At first, make sure that the link "/lib/modules/`you_kernel_version`/build"
points to the source code for your currently running kernel.
Then, if you are going to work on 2.6 kernels, since in those kernels
scsi_do_req() works in LIFO order, instead of expected and required
FIFO, SCST needs a new function scsi_do_req_fifo() to be added in the
kernel. Patch 26_scst.patch (or 26_scst-2.6.14-.patch for early kernels)
from "kernel" directory does that. If it doesn't apply to your kernel
version, apply it manually, it only adds that function and nothing more.
You may not patch the kernel if STRICT_SERIALIZING is defined during the
compilation (see its description below).
To compile SCST go to 'src' directory and type 'make' on 2.6 kernels and
'make -f Makefile-24' on 2.4 ones. It will build SCST itself and its
device handlers. To install them type 'make install'. The driver modules
will be installed in
'/lib/modules/`you_kernel_version`/kernel/drivers/scsi/scsi_tgt' on 2.4
kernels and in '/lib/modules/`you_kernel_version`/extra' on 2.6 ones. In
addition, scsi_tgt.h, scst_debug.h and scst_debug.c will be copied to
'/usr/local/include/scst'. The first file contains all SCST's public
data definition, which are used by target drivers. The other ones
support debug messages logging.
Then you can load any module by typing 'modprobe drive_name'. The names are:
- scsi_tgt - SCST itself
- scst_disk - device handler for disks (type 0)
- scst_tape - device handler for tapes (type 1)
- scst_processor - device handler for processors (type 3)
- scst_cdrom - device handler for CDROMs (type 5)
- scst_modisk - device handler for MO disks (type 7)
- scst_changer - device handler for medium changers (type 8)
- scst_raid - device handler for storage array controller (e.g. raid) (type C)
- scst_fileio - device handler for FILE IO (disk or ISO CD image).
Then, to see your devices remotely, you need to add them to at least
"Default" security group (see below how). By default, no local devices
are seen remotely. There must be LUN 0 in each security group, i.e. LUs
numeration must not start from, e.g., 1.
Module "scst_target" supports parameter "scst_threads", which allows to
set count of SCST's threads (CPU count by default).
IMPORTANT: without loading appropriate device handler, corresponding devices
========= will be invisible for remote initiators, which could lead to holes
in the LUN addressing, so automatic device scanning by remote SCSI
mid-level could not notice the devices. Therefore you will have
to add them manually via
'echo "scsi add-single-device A 0 0 B" >/proc/scsi/scsi',
where A - is the host number, B - LUN.
IMPORTANT 1: In the current version simultaneous access to local SCSI
=========== devices via standard high-level SCSI drivers (sd, st, sg,
etc.) and SCST's target drivers is unsupported. Especially
it is important for execution via sg and st commands that
change the state of devices and their parameters, because
that could lead to data corruption. If any such command
is done, at least related device handler driver(s) must be
restarted. For block devices READ/WRITE commands using direct
disk handler look to be safe.
To uninstall, type 'make uninstall'. It is not implemented for 2.6
kernels.
If you install QLA2x00 target driver's source code in this directory,
then you can build, install or uninstall it by typing 'make qla', 'make
qla_install' or 'make qla_uninstall' correspondingly. Or 'make qla26',
'make qla26_install' or 'make qla26_uninstall' for new 2.6 driver. For
more details about QLA2x00 target drivers see their README files.
Compilation options
-------------------
There are the following compilation options, that could be commented
in/out in Makefile:
- DEBUG - turns on some debugging code, including some logging. Makes
the driver considerably bigger and slower, producing large amount of
log data.
- TRACING - turns on ability to log events. Makes the driver considerably
bigger and lead to some performance loss.
- EXTRACHECKS - adds extra validity checks in the various places.
- DEBUG_TM - turns on task management functions debugging, when on
LUN 0 in the "Default" group some of the commands will be delayed for
about 60 sec., so making the remote initiator send TM functions, eg
ABORT TASK and TARGET RESET. Also set TM_DBG_GO_OFFLINE symbol in the
Makefile to 1 if you want that the device eventually become
completely unresponsive, or to 0 otherwise to circle around ABORTs
and RESETs code. Needs DEBUG turned on.
- STRICT_SERIALIZING - makes SCST send all commands to underlying SCSI
device synchronously, one after one. This makes task management more
reliable, with cost of some performance penalty. This is mostly
actual for stateful SCSI devices like tapes, where the result of
command's execution depends from device's settings set by previous
commands. Disk and RAID devices are stateless in the most cases. The
current SCSI core in Linux doesn't allow to abort all commands
reliably if they sent asynchronously to a stateful device. Turned off
by default, turn it on if you use stateful device(s) and need as much
error recovery reliability as possible. As a side effect, no kernel
patching is necessary.
- SCST_HIGHMEM - if defined on HIGHMEM systems with 2.6 kernels, it
allows SCST to use HIGHMEM. This is very experimental feature and it
is unclear, if it brings something valuable, except some performance
hit, so in the current version it is disabled. Note, that
SCST_HIGHMEM isn't required for HIGHMEM systems and SCST will work
fine on them with SCST_HIGHMEM off. Untested.
- SCST_STRICT_SECURITY - if defined, makes SCST zero allocated data
buffers. Undefining it (default) considerably improves performance
and eases CPU load, but could create a security hole (information
leakage), so enable it, if you have strict security requirements.
SCST "/proc" commands
---------------------
For communications with user space programs SCST provides proc-based
interface in "/proc/scsi_tgt" directory. It contains the following
entries:
- "help" file, which provides online help for SCST commands
- "scsi_tgt" file, which on read provides information of serving by SCST
devices and their dev handlers. On write it supports the following
command:
* "assign H:C:I:L HANDLER_NAME" assigns dev handler "HANDLER_NAME"
on device with host:channel:id:lun
- "sessions" file, which lists currently connected initiators (open sessions)
- "threads" file, which allows to read and set number of SCST's threads
- "version" file, which shows version of SCST
- "trace_level" file, which allows to read and set trace (logging) level
for SCST. See "help" file for list of trace levels.
Each dev handler has own subdirectory. Most dev handler have only two
files in this subdirectory: "trace_level" and "type". The first one is
similar to main SCST "trace_level" file, the latter one shows SCSI type
number of this handler as well as some text description.
For example, "echo "assign 1:0:1:0 dev_disk" >/proc/scsi_tgt/scsi_tgt"
will assign device handler "dev_disk" to real device sitting on host 1,
channel 0, ID 1, LUN 0.
Access and devices visibility management
----------------------------------------
Access and devices visibility management allows for an initiator or
group of initiators to have different limited set of LUs/LUNs (security
group) each with appropriate access permissions. Initiator is
represented as a SCST session. Session is binded to security group on
its registration time by character "name" parameter of the registration
function, which provided by target driver, based on its internal
authentication. For example, for FC "name" could be WWN or just loop
ID. For iSCSI this could be iSCSI login credentials or iSCSI initiator
name. Each security group has set of names assigned to it by system
administrator. Session is binded to security group with provided name.
If no such groups found, the session binded to "Default" group.
In /proc/scsi_tgt each group represented as "groups/GROUP_NAME/"
subdirectory. In it there are files "devices" and "users". File
"devices" lists all devices and their LUNs in the group, file "users"
lists all names that should be binded to this group.
To configure access and devices visibility management SCST provides the
following files and directories under /proc/scsi_tgt:
- "add_group GROUP" to /proc/scsi_tgt/scsi_tgt adds group "GROUP"
- "del_group GROUP" to /proc/scsi_tgt/scsi_tgt deletes group "GROUP"
- "add H:C:I:L lun [RO]" to /proc/scsi_tgt/groups/GROUP/devices adds
device with host:channel:id:lun as LUN "lun" in group "GROUP". Optionally,
the device could be marked as read only.
- "del H:C:I:L" to /proc/scsi_tgt/groups/GROUP/devices deletes device with
host:channel:id:lun from group "GROUP"
- "add V_NAME lun [RO]" to /proc/scsi_tgt/groups/GROUP/devices adds device with
virtual name "V_NAME" as LUN "lun" in group "GROUP". Optionally, the device
could be marked as read only.
- "del V_NAME" to /proc/scsi_tgt/groups/GROUP/devices deletes device with
virtual name "V_NAME" from group "GROUP"
- "clear" to /proc/scsi_tgt/groups/GROUP/devices clears the list of devices
for group "GROUP"
- "add NAME" to /proc/scsi_tgt/groups/GROUP/names adds name "NAME" to group
"GROUP"
- "del NAME" to /proc/scsi_tgt/groups/GROUP/names deletes name "NAME" from group
"GROUP"
- "clear" to /proc/scsi_tgt/groups/GROUP/names clears the list of names
for group "GROUP"
Examples:
- "echo "add 1:0:1:0 0" >/proc/scsi_tgt/groups/Default/devices" will
add real device sitting on host 1, channel 0, ID 1, LUN 0 to "Default"
group with LUN 0.
- "echo "add disk1 1" >/proc/scsi_tgt/groups/Default/devices" will
add virtual FILEIO device with name "disk1" to "Default" group
with LUN 1.
FILEIO device handler
---------------------
After loading FILEIO device handler creates in "/proc/scsi_tgt/"
subdirectories "disk_fileio" and "cdrom_fileio". They have similar layout:
- "trace_level" and "type" files as described for other dev handlers
- "help" file, which provides online help for FILEIO commands
- "disk_fileio"/"cdrom_fileio" files, which on read provides
information of currently open device files. On write it supports the
following command:
* "open NAME PATH [FLAGS]" - opens file "PATH" as device "NAME" with
flags "FLAGS. Possible flags:
- WRITE_THROUGH - write back caching disabled
- READ_ONLY - read only
- O_DIRECT - both read and write caching disabled (doesn't work
currently).
- NULLIO - in this mode no real IO will be done, but success will be
returned. Intended to be used for performance measurements at the same
way as "*_perf" handlers.
* "close NAME" - closes device "NAME".
For example, "echo "open disk1 /vdisks/disk1" >/proc/scsi_tgt/disk_fileio/disk_fileio"
will open file /vdisks/disk1 as virtual FILEIO disk with name "disk1".
IMPORTANT: by default for performance reasons FILEIO devices use write back
========= caching policy, so if you care about the consistence of file systems,
laying over them, and your data you must supply your target
server with some king of UPS or disable write back caching
via WRITE_THROUGH flag. The FS joutnaling over write back
caching enabled devices doesn't protect from power failures
on the target side, therefore even after successful journal
rollback you very much risk to loose your data.
Performance
-----------
Before doing any performance measurements note that:
I. Maximum performance is possible only with real SCSI devices or
performance handlers. FILEIO handler isn't optimized for performance
yet, although, if you have enough CPU power, it could provide very
acceptable results, when aggregate throughput is close to aggregate
throuput locally on the target on the same disks.
II. In order to get the maximum performance you should:
1. For SCST:
- Disable in Makefile STRICT_SERIALIZING, EXTRACHECKS, TRACING, DEBUG,
SCST_STRICT_SECURITY, SCST_HIGHMEM
2. For Qlogic target driver:
- Disable in Makefile EXTRACHECKS, TRACING, DEBUG_TGT, DEBUG_WORK_IN_THREAD
3. For device handlers, including FILEIO:
- Disable in Makefile TRACING, DEBUG
IMPORTANT: Some of those options enabled by default, i.e. SCST is optimized
========= currently rather for development, not for performance.
4. For kernel:
- Don't enable debug/hacking features, i.e. use them as they are by
default.
- The default kernel read-ahead and queuing settings are optimized
for locally attached disks, therefore they are not optimal if they
attached remotly (our case), which sometimes could lead to unexpectedly
low throughput. You should increase read-ahead size
(/sys/block/device/queue/read_ahead_kb) for at least 256Kb or even
more on all initiators and the target. Also experiment with other
parameters in /sys/block/device directory, they also affect the
performance. If you find the best values, please share them with us.
5. For hardware.
- Make sure that your target hardware (e.g. target FC card) and underlaying
SCSI hardware (e.g. SCSI card to which your disks connected) stay on
different PCI buses. They will have to work in parallel, so it
will be better if they don't race for the bus. The problem is not
only in the bandwidth, which they have to share, but also in the
interaction between the cards during that competition. We have told
that in some cases it could lead to 5-10 times less performance, than
expected.
Just for reference: we had with 0.9.2 and "old" Qlogic driver on 2.4.2x
kernel, where we did carefull performance study, aggregate throuhput
about 390 Mb/sec from 2 qla2300 cards sitting on different 64-bit PCI
buses and working simultaneously for two different initiators with
several simultaneously working load programs on each. From one card -
about 190 Mb/sec. We used tape_perf handler, so there was no influence
from underlying SCSI hardware, i.e. we measured only SCST/FC overhead.
The target computer configuration was not very modern for the moment:
something like 2x1GHz Intel P3 Xeon CPUs. You can estimate the
memory/PCI speed from that. CPU load was ~5%, there were ~30K IRQ/sec
and no additional SCST related context switches. Version 0.9.3 at the
same setup will usually have 1 CS/cmd for buffer allocation, so the will
be about 5-10K CS/sec. This will be fixed in the next version, when
sgv_pool is integrated.
Credits
-------
Thanks to:
* Mark Buechler <mark.buechler@gmail.com> for a lot of useful
suggestions, bug reports and help in debugging.
* Ming Zhang <mingz@ele.uri.edu> for fixes and comments.
* Nathaniel Clark <nate@misrule.us> for fixes and comments.
* Calvin Morrow <calvin.morrow@comcast.net> for testing and usful
suggestions.
Vladislav Bolkhovitin <vst@vlnb.net>, http://scst.sourceforge.net
+55
View File
@@ -0,0 +1,55 @@
To be done
----------
- Kernel build integration (patch).
- Reimplement FILEIO handler with usage of async. read/write operations
(in order to avoid unnecessary context switches) and direct access to
the page cache (in order to avoid data copy between it and internal
buffers). Requires modifications of the kernel.
- O_DIRECT mode doesn't work (oops'es somewhere in the kernel)
- Close integration with Linux initiator SCSI mil-level, including
queue types (simple, ordered, etc.) and local initiators (sd, st, sg,
etc.) support. Requires modifications of the kernel.
- Improve task management and Unit Attention conditions handling
using ACA in order to make them always reliable. Honoring NACA, QErr,
TST, UA_INTLCK_CTRL bits. Requires deep modifications of the kernel.
- Move linear searches to hash-table based.
- Create dev handler for block devices, which would insert commands as
block requests in the device's block queue, so they would processed
by IO-scheduler then.
- Redone some semaphores with completion interface.
- HIGHMEM cleanup. Looks like HIGHMEM usage doesn't worth the effort and
performance hit, at least until FILEIO handler doesn't use the page
cache directly, so disable it for now, although the code looks ready.
To enable it, set SCST_HIGHMEM in 1 in scst_priv.h. HIGHMEM is not
supported on 2.4 and is not going to be.
- More intelligent IO-throttling.
- Small ToDo's spread all over the code.
- Investigate possible missed emulated UA cases.
- More target drivers errors handling (timeouts for commands, sent
to target drivers, e.g. via xmit_response(), etc.) with some kind
of error recovery.
- Additional ability for target drivers to ask for command's retry also
after xmit_response() and rdy_to_xfer() returned (for example, if a
command was successfully sent to the target card, but later it was
returned by the card with BUSY completion status).
- Asynchronous Event Notification support.
- Support of SCSI 3 variable length CDBs, as well as OSD's extensions.
- Advanced SCSI commands support: COPY, EXTENDED COPY, PERSISTENT
RESERVE IN/OUT, third party RESERVE, etc.
File diff suppressed because it is too large Load Diff
+105
View File
@@ -0,0 +1,105 @@
/*
* include/scst_debug.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* Contains helper functions for execution tracing and error reporting.
* Intended to be included in main .c file.
*
* 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, version 2
* of the License.
*
* 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.
*/
#if defined(DEBUG) || defined(TRACING)
unsigned long trace_flag;
#define TRACE_BUF_SIZE 512
static char trace_buf[TRACE_BUF_SIZE];
static spinlock_t trace_buf_lock = SPIN_LOCK_UNLOCKED;
int debug_print_prefix(const char *func, int line)
{
int i = 0;
unsigned long flags;
spin_lock_irqsave(&trace_buf_lock, flags);
if (trace_flag & TRACE_PID)
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE, "[%d]: ",
current->pid);
if (trace_flag & TRACE_FUNCTION)
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%s:", func);
if (trace_flag & TRACE_LINE)
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%i:", line);
if (i > 0)
PRINTN(LOG_FLAG, "%s", trace_buf);
spin_unlock_irqrestore(&trace_buf_lock, flags);
return i;
}
void debug_print_buffer(const void *data, int len)
{
int z, z1, i;
const unsigned char *buf = (const unsigned char *) data;
int f = 0;
unsigned long flags;
spin_lock_irqsave(&trace_buf_lock, flags);
PRINT(NO_FLAG, " (h)___0__1__2__3__4__5__6__7__8__9__A__B__C__D__E__F");
for (z = 0, z1 = 0, i = 0; z < len; z++) {
if (z % 16 == 0) {
if (z != 0) {
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i,
" ");
for (; (z1 < z) && (i < TRACE_BUF_SIZE - 1);
z1++) {
if ((buf[z1] >= 0x20) &&
(buf[z1] < 0x80))
trace_buf[i++] = buf[z1];
else
trace_buf[i++] = '.';
}
trace_buf[i] = '\0';
PRINT(NO_FLAG, "%s", trace_buf);
i = 0;
f = 1;
}
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i,
"%4x: ", z);
}
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%02x ",
buf[z]);
}
i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, " ");
for (; (z1 < z) && (i < TRACE_BUF_SIZE - 1); z1++) {
if ((buf[z1] > 0x20) && (buf[z1] < 0x80))
trace_buf[i++] = buf[z1];
else
trace_buf[i++] = '.';
}
trace_buf[i] = '\0';
if (f) {
PRINT(LOG_FLAG, "%s", trace_buf)
} else {
PRINT(NO_FLAG, "%s", trace_buf);
}
spin_unlock_irqrestore(&trace_buf_lock, flags);
return;
}
#endif /* DEBUG || TRACING */
+322
View File
@@ -0,0 +1,322 @@
/*
* include/scst_debug.h
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* Contains macroses for execution tracing and error reporting
*
* 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, version 2
* of the License.
*
* 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.
*/
#ifndef __SCST_DEBUG_H
#define __SCST_DEBUG_H
#include <linux/config.h> /* for CONFIG_SCSI_TARGET_EXTRACHEKS
CONFIG_SCSI_TARGET_TRACING
CONFIG_SCSI_TARGET_DEBUG */
#if !defined(EXTRACHECKS) && defined(CONFIG_SCSI_TARGET_EXTRACHECKS)
#define EXTRACHECKS
#endif
#if !defined(TRACING) && defined(CONFIG_SCSI_TARGET_TRACING)
#define TRACING
#endif
#if !defined(DEBUG) && defined(CONFIG_SCSI_TARGET_DEBUG)
#define DEBUG
#endif
#ifdef DEBUG
//# define LOG_FLAG KERN_DEBUG
# define LOG_FLAG KERN_INFO
# define INFO_FLAG KERN_INFO
# define ERROR_FLAG KERN_INFO
#else
# define LOG_FLAG KERN_INFO
# define INFO_FLAG KERN_INFO
# define ERROR_FLAG KERN_ERR
#endif
#define NO_FLAG ""
#define TRACE_NULL 0x00000000
#define TRACE_DEBUG 0x00000001
#define TRACE_FUNCTION 0x00000002
#define TRACE_LINE 0x00000004
#define TRACE_PID 0x00000008
#define TRACE_ENTRYEXIT 0x00000010
#define TRACE_BUFF 0x00000020
#define TRACE_MEMORY 0x00000040
#define TRACE_SG 0x00000080
#define TRACE_OUT_OF_MEM 0x00000100
#define TRACE_MINOR 0x00000200 /* less important events */
#define TRACE_MGMT 0x00000400
#define TRACE_MGMT_DEBUG 0x00000800
#define TRACE_SCSI 0x00001000
#define TRACE_SPECIAL 0x00002000 /* filtering debug, etc */
#define TRACE_ALL 0xffffffff
/* Flags 0xXXXX0000 are local for users */
#define PRINT(log_flag, format, args...) printk(log_flag format "\n", ## args);
#define PRINTN(log_flag, format, args...) printk(log_flag format, ## args);
#if defined(DEBUG) || defined(TRACING)
extern unsigned long trace_flag;
extern int debug_print_prefix(const char *func, int line);
extern void debug_print_buffer(const void *data, int len);
#define TRACE(trace, format, args...) \
do { \
if (trace_flag & (trace)) \
{ \
char *__tflag = LOG_FLAG; \
if (debug_print_prefix(__FUNCTION__, __LINE__) > 0) \
{ \
__tflag = NO_FLAG; \
} \
PRINT(NO_FLAG, "%s" format, __tflag, args); \
} \
} while(0)
#define TRACE_LOG_FLAG(log_flag, trace, format, args...) \
do { \
char *__tflag = log_flag; \
if (trace_flag & (trace)) \
{ \
if (debug_print_prefix(__FUNCTION__, __LINE__) > 0) \
{ \
__tflag = NO_FLAG; \
} \
} \
PRINT(NO_FLAG, "%s" format, __tflag, args); \
} while(0)
#define TRACE_BUFFER(message, buff, len) \
do { \
if (trace_flag & TRACE_BUFF) \
{ \
char *__tflag = LOG_FLAG; \
if (debug_print_prefix(__FUNCTION__, __LINE__) > 0) \
{ \
__tflag = NO_FLAG; \
} \
PRINT(NO_FLAG, "%s%s:", __tflag, message); \
debug_print_buffer(buff, len); \
} \
} while(0)
#define TRACE_BUFF_FLAG(flag, message, buff, len) \
do { \
if (trace_flag & (flag)) \
{ \
char *__tflag = LOG_FLAG; \
if (debug_print_prefix(__FUNCTION__, __LINE__) > 0) \
{ \
__tflag = NO_FLAG; \
} \
PRINT(NO_FLAG, "%s%s:", __tflag, message); \
debug_print_buffer(buff, len); \
} \
} while(0)
#else /* DEBUG || TRACING */
#define TRACE(trace, args...) {}
#define TRACE_BUFFER(message, buff, len) {}
#define TRACE_BUFF_FLAG(flag, message, buff, len) {}
#endif /* DEBUG || TRACING */
#ifdef DEBUG
#define TRACE_MEM(format, args...) \
do { \
if (trace_flag & TRACE_MEMORY) \
{ \
char *__tflag = LOG_FLAG; \
if (debug_print_prefix(__FUNCTION__, __LINE__) > 0) \
{ \
__tflag = NO_FLAG; \
} \
PRINT(NO_FLAG, "%s" format, __tflag, args); \
} \
} while(0)
#define TRACE_DBG(format, args...) \
do { \
if (trace_flag & TRACE_DEBUG) \
{ \
char *__tflag = LOG_FLAG; \
if (debug_print_prefix(__FUNCTION__, __LINE__) > 0) \
{ \
__tflag = NO_FLAG; \
} \
PRINT(NO_FLAG, "%s" format, __tflag, args); \
} \
} while(0)
#define TRACE_MGMT_DBG(format, args...) \
do { \
if (trace_flag & TRACE_MGMT_DEBUG) \
{ \
char *__tflag = LOG_FLAG; \
if (debug_print_prefix(__FUNCTION__, __LINE__) > 0) \
{ \
__tflag = NO_FLAG; \
} \
PRINT(NO_FLAG, "%s" format, __tflag, args); \
} \
} while(0)
#define PRINT_ERROR_PR(format, args...) \
do { \
if (ERROR_FLAG != LOG_FLAG) \
{ \
TRACE_LOG_FLAG(LOG_FLAG, trace_flag, "%s: ***ERROR*** " format, \
LOG_PREFIX, args); \
} \
TRACE_LOG_FLAG(ERROR_FLAG, trace_flag, "%s: ***ERROR*** " format, \
LOG_PREFIX, args); \
} while(0)
#define PRINT_INFO_PR(format, args...) \
do { \
if (INFO_FLAG != LOG_FLAG) \
{ \
TRACE_LOG_FLAG(LOG_FLAG, trace_flag, "%s: " \
format, LOG_PREFIX, args); \
} \
TRACE_LOG_FLAG(INFO_FLAG, trace_flag, "%s: " \
format, LOG_PREFIX, args); \
} while(0)
#define PRINT_ERROR(format, args...) \
do { \
if (ERROR_FLAG != LOG_FLAG) \
{ \
TRACE_LOG_FLAG(LOG_FLAG, trace_flag, "***ERROR*** " format, args); \
} \
TRACE_LOG_FLAG(ERROR_FLAG, trace_flag, "***ERROR*** " format, args); \
} while(0)
#define PRINT_INFO(format, args...) \
do { \
if (INFO_FLAG != LOG_FLAG) \
{ \
TRACE_LOG_FLAG(LOG_FLAG, trace_flag, format, args); \
} \
TRACE_LOG_FLAG(INFO_FLAG, trace_flag, format, args); \
} while(0)
#define TRACE_ENTRY() \
do { \
if (trace_flag & TRACE_ENTRYEXIT) \
{ \
if (trace_flag & TRACE_PID) \
{ \
PRINT(LOG_FLAG, "[%d]: ENTRY %s", current->pid, \
__FUNCTION__); \
} \
else \
{ \
PRINT(LOG_FLAG, "ENTRY %s", __FUNCTION__); \
} \
} \
} while(0)
#define TRACE_EXIT() \
do { \
if (trace_flag & TRACE_ENTRYEXIT) \
{ \
if (trace_flag & TRACE_PID) \
{ \
PRINT(LOG_FLAG, "[%d]: EXIT %s", current->pid, \
__FUNCTION__); \
} \
else \
{ \
PRINT(LOG_FLAG, "EXIT %s", __FUNCTION__); \
} \
} \
} while(0)
#define TRACE_EXIT_RES(res) \
do { \
if (trace_flag & TRACE_ENTRYEXIT) \
{ \
if (trace_flag & TRACE_PID) \
{ \
PRINT(LOG_FLAG, "[%d]: EXIT %s: %ld", current->pid, \
__FUNCTION__, (long)(res)); \
} \
else \
{ \
PRINT(LOG_FLAG, "EXIT %s: %ld", __FUNCTION__, (long)(res)); \
} \
} \
} while(0)
#define TRACE_EXIT_HRES(res) \
do { \
if (trace_flag & TRACE_ENTRYEXIT) \
{ \
if (trace_flag & TRACE_PID) \
{ \
PRINT(LOG_FLAG, "[%d]: EXIT %s: 0x%lx", current->pid, \
__FUNCTION__, (long)(res)); \
} \
else \
{ \
PRINT(LOG_FLAG, "EXIT %s: %lx", __FUNCTION__, (long)(res)); \
} \
} \
} while(0)
#else /* DEBUG */
#define TRACE_MEM(format, args...) {}
#define TRACE_DBG(format, args...) {}
#define TRACE_MGMT_DBG(format, args...) {}
#define TRACE_ENTRY() {}
#define TRACE_EXIT() {}
#define TRACE_EXIT_RES(res) {}
#define TRACE_EXIT_HRES(res) {}
#define PRINT_INFO_PR(format, args...) \
do { \
PRINT(INFO_FLAG, "%s: " format, LOG_PREFIX, args); \
} while(0)
#define PRINT_ERROR_PR(format, args...) \
do { \
PRINT(ERROR_FLAG, "%s: ***ERROR*** " \
format, LOG_PREFIX, args); \
} while(0)
#define PRINT_INFO(format, args...) \
do { \
PRINT(INFO_FLAG, format, args); \
} while(0)
#define PRINT_ERROR(format, args...) \
do { \
PRINT(ERROR_FLAG, "***ERROR*** " \
format, args); \
} while(0)
#endif /* DEBUG */
#endif /* __SCST_DEBUG_H */
+77
View File
@@ -0,0 +1,77 @@
--- linux-2.6.12-rc6/drivers/scsi/scsi_lib.c_scst 2005-06-15 16:15:01.000000000 +0400
+++ linux-2.6.12-rc6/drivers/scsi/scsi_lib.c 2005-06-23 20:28:20.802971272 +0400
@@ -235,6 +235,61 @@ void scsi_do_req(struct scsi_request *sr
}
EXPORT_SYMBOL(scsi_do_req);
+/*
+ * Function: scsi_do_req_fifo
+ *
+ * Purpose: Queue a SCSI request
+ *
+ * Arguments: sreq - command descriptor.
+ * cmnd - actual SCSI command to be performed.
+ * buffer - data buffer.
+ * bufflen - size of data buffer.
+ * done - completion function to be run.
+ * timeout - how long to let it run before timeout.
+ * retries - number of retries we allow.
+ *
+ * Lock status: No locks held upon entry.
+ *
+ * Returns: Nothing.
+ *
+ * Notes: This function is used for queueing requests in FIFO order.
+ * It is a copy of scsi_do_req() with only changed the last
+ * parameter of scsi_insert_special_req(). Not sure, if it
+ * breaks quiesce, but, anyway, I don't see another way to
+ * queue requests in FIFO order, which is necessary for SCST.
+ */
+void scsi_do_req_fifo(struct scsi_request *sreq, const void *cmnd,
+ void *buffer, unsigned bufflen,
+ void (*done)(struct scsi_cmnd *),
+ int timeout, int retries)
+{
+ /*
+ * If the upper level driver is reusing these things, then
+ * we should release the low-level block now. Another one will
+ * be allocated later when this request is getting queued.
+ */
+ __scsi_release_request(sreq);
+
+ /*
+ * Our own function scsi_done (which marks the host as not busy,
+ * disables the timeout counter, etc) will be called by us or by the
+ * scsi_hosts[host].queuecommand() function needs to also call
+ * the completion function for the high level driver.
+ */
+ memcpy(sreq->sr_cmnd, cmnd, sizeof(sreq->sr_cmnd));
+ sreq->sr_bufflen = bufflen;
+ sreq->sr_buffer = buffer;
+ sreq->sr_allowed = retries;
+ sreq->sr_done = done;
+ sreq->sr_timeout_per_command = timeout;
+
+ if (sreq->sr_cmd_len == 0)
+ sreq->sr_cmd_len = COMMAND_SIZE(sreq->sr_cmnd[0]);
+
+ scsi_insert_special_req(sreq, 0);
+}
+EXPORT_SYMBOL(scsi_do_req_fifo);
+
static void scsi_wait_done(struct scsi_cmnd *cmd)
{
struct request *req = cmd->request;
--- linux-2.6.12-rc6/include/scsi/scsi_request.h_scst 2005-06-23 20:08:59.475519880 +0400
+++ linux-2.6.12-rc6/include/scsi/scsi_request.h 2005-06-23 20:08:26.881474928 +0400
@@ -54,6 +54,10 @@ extern void scsi_do_req(struct scsi_requ
void *buffer, unsigned bufflen,
void (*done) (struct scsi_cmnd *),
int timeout, int retries);
+extern void scsi_do_req_fifo(struct scsi_request *, const void *cmnd,
+ void *buffer, unsigned bufflen,
+ void (*done) (struct scsi_cmnd *),
+ int timeout, int retries);
struct scsi_mode_data {
__u32 length;
+75
View File
@@ -0,0 +1,75 @@
--- linux-2.6.15.6/drivers/scsi/scsi_lib.c_scst 2006-03-05 22:07:54.000000000 +0300
+++ linux-2.6.15.6/drivers/scsi/scsi_lib.c 2006-03-27 17:56:59.000000000 +0400
@@ -254,6 +254,61 @@
}
EXPORT_SYMBOL(scsi_do_req);
+/*
+ * Function: scsi_do_req_fifo
+ *
+ * Purpose: Queue a SCSI request
+ *
+ * Arguments: sreq - command descriptor.
+ * cmnd - actual SCSI command to be performed.
+ * buffer - data buffer.
+ * bufflen - size of data buffer.
+ * done - completion function to be run.
+ * timeout - how long to let it run before timeout.
+ * retries - number of retries we allow.
+ *
+ * Lock status: No locks held upon entry.
+ *
+ * Returns: Nothing.
+ *
+ * Notes: This function is used for queueing requests in FIFO order.
+ * It is a copy of scsi_do_req() with only changed the last
+ * parameter of scsi_insert_special_req(). Not sure, if it
+ * breaks quiesce, but, anyway, I don't see another way to
+ * queue requests in FIFO order, which is necessary for SCST.
+ */
+void scsi_do_req_fifo(struct scsi_request *sreq, const void *cmnd,
+ void *buffer, unsigned bufflen,
+ void (*done)(struct scsi_cmnd *),
+ int timeout, int retries)
+{
+ /*
+ * If the upper level driver is reusing these things, then
+ * we should release the low-level block now. Another one will
+ * be allocated later when this request is getting queued.
+ */
+ __scsi_release_request(sreq);
+
+ /*
+ * Our own function scsi_done (which marks the host as not busy,
+ * disables the timeout counter, etc) will be called by us or by the
+ * scsi_hosts[host].queuecommand() function needs to also call
+ * the completion function for the high level driver.
+ */
+ memcpy(sreq->sr_cmnd, cmnd, sizeof(sreq->sr_cmnd));
+ sreq->sr_bufflen = bufflen;
+ sreq->sr_buffer = buffer;
+ sreq->sr_allowed = retries;
+ sreq->sr_done = done;
+ sreq->sr_timeout_per_command = timeout;
+
+ if (sreq->sr_cmd_len == 0)
+ sreq->sr_cmd_len = COMMAND_SIZE(sreq->sr_cmnd[0]);
+
+ scsi_insert_special_req(sreq, 0);
+}
+EXPORT_SYMBOL(scsi_do_req_fifo);
+
/**
* scsi_execute - insert request and wait for the result
* @sdev: scsi device
--- linux-2.6.15.6/include/scsi/scsi_request.h_scst 2006-03-27 17:54:21.000000000 +0400
+++ linux-2.6.15.6/include/scsi/scsi_request.h 2006-03-27 17:56:00.000000000 +0400
@@ -51,4 +51,8 @@
void *buffer, unsigned bufflen,
void (*done) (struct scsi_cmnd *),
int timeout, int retries);
+extern void scsi_do_req_fifo(struct scsi_request *, const void *cmnd,
+ void *buffer, unsigned bufflen,
+ void (*done) (struct scsi_cmnd *),
+ int timeout, int retries);
#endif /* _SCSI_SCSI_REQUEST_H */
+77
View File
@@ -0,0 +1,77 @@
--- linux-2.6.16/drivers/scsi/scsi_lib.c.orig 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16/drivers/scsi/scsi_lib.c 2006-04-07 10:04:42.077637750 -0400
@@ -227,6 +227,63 @@ void scsi_do_req(struct scsi_request *sr
}
EXPORT_SYMBOL(scsi_do_req);
+/*
+ * Function: scsi_do_req_fifo
+ *
+ * Purpose: Queue a SCSI request
+ *
+ * Arguments: sreq - command descriptor.
+ * cmnd - actual SCSI command to be performed.
+ * buffer - data buffer.
+ * bufflen - size of data buffer.
+ * done - completion function to be run.
+ * timeout - how long to let it run before timeout.
+ * retries - number of retries we allow.
+ *
+ * Lock status: No locks held upon entry.
+ *
+ * Returns: Nothing.
+ *
+ * Notes: This function is used for queueing requests in FIFO order.
+ * It is a copy of scsi_do_req() with only changed the last
+ * parameter of scsi_insert_special_req(). Not sure, if it
+ * breaks quiesce, but, anyway, I don't see another way to
+ * queue requests in FIFO order, which is necessary for SCST.
+ */
+void scsi_do_req_fifo(struct scsi_request *sreq, const void *cmnd,
+ void *buffer, unsigned bufflen,
+ void (*done)(struct scsi_cmnd *),
+ int timeout, int retries)
+{
+ /*
+ * If the upper level driver is reusing these things, then
+ * we should release the low-level block now. Another one will
+ * be allocated later when this request is getting queued.
+ */
+ __scsi_release_request(sreq);
+
+ /*
+ * Our own function scsi_done (which marks the host as not busy,
+ * disables the timeout counter, etc) will be called by us or by the
+ * scsi_hosts[host].queuecommand() function needs to also call
+ * the completion function for the high level driver.
+ */
+ memcpy(sreq->sr_cmnd, cmnd, sizeof(sreq->sr_cmnd));
+ sreq->sr_bufflen = bufflen;
+ sreq->sr_buffer = buffer;
+ sreq->sr_allowed = retries;
+ sreq->sr_done = done;
+ sreq->sr_timeout_per_command = timeout;
+
+ if (sreq->sr_cmd_len == 0)
+ sreq->sr_cmd_len = COMMAND_SIZE(sreq->sr_cmnd[0]);
+
+ sreq->sr_request->flags &= ~REQ_DONTPREP;
+ blk_insert_request(sreq->sr_device->request_queue, sreq->sr_request,
+ 1, sreq);
+}
+EXPORT_SYMBOL(scsi_do_req_fifo);
+
/**
* scsi_execute - insert request and wait for the result
* @sdev: scsi device
--- linux-2.6.16/include/scsi/scsi_request.h.orig 2006-04-07 10:06:02.506664250 -0400
+++ linux-2.6.16/include/scsi/scsi_request.h 2006-04-07 10:06:19.039697500 -0400
@@ -51,4 +51,8 @@ extern void scsi_do_req(struct scsi_requ
void *buffer, unsigned bufflen,
void (*done) (struct scsi_cmnd *),
int timeout, int retries);
+extern void scsi_do_req_fifo(struct scsi_request *, const void *cmnd,
+ void *buffer, unsigned bufflen,
+ void (*done) (struct scsi_cmnd *),
+ int timeout, int retries);
#endif /* _SCSI_SCSI_REQUEST_H */
@@ -0,0 +1,11 @@
--- Kconfig 2004-08-18 13:14:50.328907320 +0400
+++ Kconfig.scsi 2004-08-13 18:01:13.000000000 +0400
@@ -1261,6 +1261,8 @@ config SCSI_QLOGICPTI
source "drivers/scsi/qla2xxx/Kconfig"
+source "drivers/scsi/scsi_tgt/Kconfig"
+
config SCSI_SEAGATE
tristate "Seagate ST-02 and Future Domain TMC-8xx SCSI support"
depends on X86 && ISA && SCSI && BROKEN
+79
View File
@@ -0,0 +1,79 @@
config SCSI_TARGET
tristate "SCSI target middle level support"
default SCSI
depends on SCSI && PROC_FS
---help---
SCSI TARGET is designed to provide unified, consistent interface
between SCSI target drivers and Linux kernel and simplify target
drivers development as much as possible.
config SCSI_TARGET_DISK
tristate "SCSI target disk support"
default SCSI_TARGET
depends on SCSI && PROC_FS && SCSI_TARGET
---help---
SCSI TARGET handler for disk device.
config SCSI_TARGET_TAPE
tristate "SCSI target tape support"
default SCSI_TARGET
depends on SCSI && PROC_FS && SCSI_TARGET
---help---
SCSI TARGET handler for tape device.
config SCSI_TARGET_CDROM
tristate "SCSI target cdrom support"
default SCSI_TARGET
depends on SCSI && PROC_FS && SCSI_TARGET
---help---
SCSI TARGET handler for cdrom device.
config SCSI_TARGET_MODISK
tristate "SCSI target MO disk support"
default SCSI_TARGET
depends on SCSI && PROC_FS && SCSI_TARGET
---help---
SCSI TARGET handler for MO disk device.
config SCSI_TARGET_CHANGER
tristate "SCSI target changer support"
default SCSI_TARGET
depends on SCSI && PROC_FS && SCSI_TARGET
---help---
SCSI TARGET handler for changer device.
config SCSI_TARGET_PROCESSOR
tristate "SCSI target processor support"
default SCSI_TARGET
depends on SCSI && PROC_FS && SCSI_TARGET
---help---
SCSI TARGET handler for processor device.
config SCSI_TARGET_RAID
tristate "SCSI target storage array controller (raid) support"
default SCSI_TARGET
depends on SCSI && PROC_FS && SCSI_TARGET
---help---
SCSI TARGET handler for raid storage array controller (raid) device.
config SCSI_TARGET_FILEIO
tristate "SCSI target virtual disk and/or cdrom support"
default SCSI_TARGET
depends on SCSI && PROC_FS && SCSI_TARGET
---help---
SCSI TARGET handler for virtual disk and/or cdrom device.
config SCSI_TARGET_EXTRACHECKS
bool "Extrachecks support"
---help---
SCSI TARGET extrachecks.
config SCSI_TARGET_TRACING
bool "Tracing support"
---help---
SCSI TARGET tracing.
config SCSI_TARGET_DEBUG
bool "Debug support"
---help---
SCSI TARGET debugging.
@@ -0,0 +1,10 @@
--- Makefile 2004-08-18 13:20:55.434402848 +0400
+++ Makefile.scsi 2004-08-13 18:01:13.000000000 +0400
@@ -81,6 +81,7 @@ obj-$(CONFIG_SCSI_QLOGIC_ISP) += qlogici
obj-$(CONFIG_SCSI_QLOGIC_FC) += qlogicfc.o
obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o
obj-$(CONFIG_SCSI_QLA2XXX) += qla2xxx/
+obj-$(CONFIG_SCSI_TARGET) += scsi_tgt/
obj-$(CONFIG_SCSI_PAS16) += pas16.o
obj-$(CONFIG_SCSI_SEAGATE) += seagate.o
obj-$(CONFIG_SCSI_FD_8xx) += seagate.o
+17
View File
@@ -0,0 +1,17 @@
EXTRA_CFLAGS += -Iinclude/scsi
scsi_tgt-y += scst.o
scsi_tgt-y += scst_targ.o
scsi_tgt-y += scst_lib.o
scsi_tgt-y += scst_proc.o
obj-$(CONFIG_SCSI_TARGET) += scsi_tgt.o
obj-$(CONFIG_SCSI_TARGET_DISK) += scst_disk.o
obj-$(CONFIG_SCSI_TARGET_TAPE) += scst_tape.o
obj-$(CONFIG_SCSI_TARGET_CDROM) += scst_cdrom.o
obj-$(CONFIG_SCSI_TARGET_MODISK) += scst_modisk.o
obj-$(CONFIG_SCSI_TARGET_CHANGER) += scst_changer.o
obj-$(CONFIG_SCSI_TARGET_RAID) += scst_raid.o
obj-$(CONFIG_SCSI_TARGET_PROCESSOR) += scst_processor.o
obj-$(CONFIG_SCSI_TARGET_FILEIO) += scst_fileio.o
+107
View File
@@ -0,0 +1,107 @@
#
# SCSI target mid-level makefile
#
# Copyright (C) 2004 Vladislav Bolkhovitin <vst@vlnb.net>
# and Leonid Stoljar
#
# 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, version 2
# of the License.
#
# 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.
#
#
# Main targets:
# all (the default) : make all
# clean : clean files
# extraclean : clean + clean dependencies
# install : install
# uninstall : uninstall
#
# Notes :
# - install and uninstall must be made as root
#
DEV_HANDLERS_DIR = dev_handlers
ifneq ($(KERNELRELEASE),)
obj-m := scsi_tgt.o
scsi_tgt-objs := scst.o scst_targ.o scst_lib.o scst_mem.o scst_proc.o
obj-$(BUILD_DEV) += $(DEV_HANDLERS_DIR)/
else
ifeq ($(KVER),)
ifeq ($(KDIR),)
KDIR := /lib/modules/$(shell uname -r)/build
endif
else
KDIR := /lib/modules/$(KVER)/build
endif
all:
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_DEV=m
scst:
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_DEV=n
install: all
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_DEV=m \
modules_install
install -d $(INSTALL_DIR_H)
install -m 644 ../include/scsi_tgt.h $(INSTALL_DIR_H)
install -m 644 ../include/scst_debug.h $(INSTALL_DIR_H)
install -m 644 ../include/scst_debug.c $(INSTALL_DIR_H)
-depmod -a
uninstall:
cd $(DEV_HANDLERS_DIR) && $(MAKE) $@
rm -f $(INSTALL_DIR)/scsi_tgt.ko
-rmdir $(INSTALL_DIR) 2>/dev/null
-/sbin/depmod -a
rm -rf $(INSTALL_DIR_H)
endif
INSTALL_DIR := /lib/modules/$(shell uname -r)/extra
INSTALL_DIR_H := /usr/local/include/scst
INC_DIR := $(SUBDIRS)/../include
EXTRA_CFLAGS += -I$(INC_DIR)
#EXTRA_CFLAGS += -DSTRICT_SERIALIZING
EXTRA_CFLAGS += -DEXTRACHECKS
#EXTRA_CFLAGS += -fno-inline
#EXTRA_CFLAGS += -DTRACING
EXTRA_CFLAGS += -DDEBUG
#EXTRA_CFLAGS += -DDEBUG_TM -DTM_DBG_GO_OFFLINE=0
#EXTRA_CFLAGS += -DDEBUG_RETRY
#EXTRA_CFLAGS += -DDEBUG_OOM
# If defined, makes SCST zero allocated data buffers.
# Undefining it considerably improves performance and eases CPU load,
# but could create a security hole (information leakage), so
# enable it if you have strict security requirements.
#EXTRA_CFLAGS += -DSCST_STRICT_SECURITY
# If defined, allows SCST to use HIGHMEM. It's unclear, if it brings
# something valuable, except performance hit in some cases,
# so let it be off. Untested.
#EXTRA_CFLAGS += -DSCST_HIGHMEM
clean:
rm -f *.o *.ko .*.cmd *.mod.c .*.d .depend Modules.symvers
rm -rf .tmp_versions
cd $(DEV_HANDLERS_DIR) && $(MAKE) $@
extraclean: clean
.PHONY: all install uninstall clean extraclean
+64
View File
@@ -0,0 +1,64 @@
#
# SCSI target mid-level dev handler's makefile
#
# Copyright (C) 2004 Vladislav Bolkhovitin <vst@vlnb.net>
# and Leonid Stoljar
#
# 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, version 2
# of the License.
#
# 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.
#
#
# Main targets:
# all (the default) : make all
# clean : clean files
# extraclean : clean + clean dependencies
# install : install
# uninstall : uninstall
#
# Notes :
# - install and uninstall must be made as root
#
ifneq ($(KERNELRELEASE),)
obj-m := scst_cdrom.o scst_changer.o scst_disk.o scst_modisk.o scst_tape.o \
scst_fileio.o scst_raid.o scst_processor.o
else
ifeq ($(KDIR),)
KDIR := /lib/modules/$(shell uname -r)/build
endif
all:
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)
install: all
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) \
modules_install
-depmod -a
uninstall:
rm -f $(INSTALL_DIR)/scst_*.ko
endif
INSTALL_DIR := /lib/modules/$(shell uname -r)/extra
EXTRA_CFLAGS += -I$(SUBDIRS) -I$(SUBDIRS)/../include
#EXTRA_CFLAGS += -I$(SUBDIRS) -I$(SUBDIRS)/../../include -I$(SUBDIRS)/..
#EXTRA_CFLAGS += -DTRACING
EXTRA_CFLAGS += -DDEBUG
clean:
rm -f *.o *.ko .*.cmd *.mod.c .*.d .depend Modules.symvers
rm -rf .tmp_versions
extraclean: clean
.PHONY: all install uninstall clean extraclean
+408
View File
@@ -0,0 +1,408 @@
/*
* scst_cdrom.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* SCSI CDROM (type 5) dev handler
*
* 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, version 2
* of the License.
*
* 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.
*/
#include <linux/cdrom.h>
#define LOG_PREFIX "dev_cdrom"
#include "scst_debug.h"
#include "scsi_tgt.h"
#include "scst_dev_handler.h"
#include "scst_debug.c"
#define CDROM_NAME "dev_cdrom"
#define CDROM_TYPE { \
name: CDROM_NAME, \
type: TYPE_ROM, \
parse_atomic: 1, \
dev_done_atomic: 1, \
attach: cdrom_attach, \
detach: cdrom_detach, \
parse: cdrom_parse, \
dev_done: cdrom_done, \
}
#define CDROM_RETRIES 2
#define CDROM_SMALL_TIMEOUT (3 * HZ)
#define CDROM_REG_TIMEOUT (900 * HZ)
#define CDROM_LONG_TIMEOUT (14000 * HZ)
#define READ_CAP_LEN 8
/* Flags */
#define BYTCHK 0x02
struct cdrom_params
{
int sector_size;
};
int cdrom_attach(struct scst_device *);
void cdrom_detach(struct scst_device *);
int cdrom_parse(struct scst_cmd *, const struct scst_info_cdb *);
int cdrom_done(struct scst_cmd *);
#if defined(DEBUG) || defined(TRACING)
unsigned long trace_flag = SCST_DEFAULT_DEV_LOG_FLAGS;
#endif
static struct scst_dev_type cdrom_devtype = CDROM_TYPE;
/**************************************************************
* Function: cdrom_attach
*
* Argument:
*
* Returns : 1 if attached, error code otherwise
*
* Description:
*************************************************************/
int cdrom_attach(struct scst_device *dev)
{
int res = 0;
uint8_t cmd[10];
const int buffer_size = 512;
uint8_t *buffer = NULL;
int retries;
unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
enum dma_data_direction data_dir;
unsigned char *sbuff;
struct cdrom_params *cdrom;
TRACE_ENTRY();
if (dev->scsi_dev == NULL ||
dev->scsi_dev->type != dev->handler->type) {
PRINT_ERROR_PR("%s", "SCSI device not define or illegal type");
res = -ENODEV;
goto out;
}
cdrom = kzalloc(sizeof(*cdrom), GFP_KERNEL);
TRACE_MEM("kzalloc(GFP_KERNEL) for struct cdrom_params (%zu): %p",
sizeof(*cdrom), cdrom);
if (cdrom == NULL) {
TRACE(TRACE_OUT_OF_MEM, "%s",
"Unable to allocate struct cdrom_params");
res = -ENOMEM;
goto out;
}
buffer = kzalloc(buffer_size, GFP_KERNEL);
TRACE_MEM("kzalloc(GFP_KERNEL) for %d: %p", buffer_size, buffer);
if (!buffer) {
TRACE(TRACE_OUT_OF_MEM, "%s", "Memory allocation failure");
res = -ENOMEM;
goto out_free_cdrom;
}
/* Clear any existing UA's and get cdrom capacity (cdrom block size) */
memset(cmd, 0, sizeof(cmd));
cmd[0] = READ_CAPACITY;
cmd[1] = (dev->scsi_dev->scsi_level <= SCSI_2) ?
((dev->scsi_dev->lun << 5) & 0xe0) : 0;
retries = SCST_DEV_UA_RETRIES;
while (1) {
memset(buffer, 0, buffer_size);
data_dir = SCST_DATA_READ;
sbuff = sense_buffer;
TRACE_DBG("%s", "Doing READ_CAPACITY");
res = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer,
buffer_size, sbuff,
CDROM_REG_TIMEOUT, CDROM_RETRIES, 0);
TRACE_DBG("READ_CAPACITY done: %x", res);
if (!res || (sbuff[12] != 0x28 && sbuff[12] != 0x29))
{
break;
}
if (!--retries) {
PRINT_ERROR_PR("UA not clear after %d retries",
SCST_DEV_UA_RETRIES);
cdrom->sector_size = 2048;
// res = -ENODEV;
goto out_free_buf;
}
}
if (res == 0) {
cdrom->sector_size = ((buffer[4] << 24) | (buffer[5] << 16) |
(buffer[6] << 8) | (buffer[7] << 0));
TRACE_DBG("Sector size is %i scsi_level %d(SCSI_2 %d)",
cdrom->sector_size, dev->scsi_dev->scsi_level, SCSI_2);
if (!cdrom->sector_size) {
cdrom->sector_size = 2048;
}
} else {
TRACE_BUFFER("Sense set", sbuff, SCSI_SENSE_BUFFERSIZE);
cdrom->sector_size = 2048;
// res = -ENODEV;
goto out_free_buf;
}
out_free_buf:
TRACE_MEM("kfree for buffer: %p", buffer);
kfree(buffer);
out_free_cdrom:
if (res == 0)
dev->tgt_dev_specific = cdrom;
else {
TRACE_MEM("kfree for cdrom: %p", cdrom);
kfree(cdrom);
}
out:
TRACE_EXIT();
return res;
}
/************************************************************
* Function: cdrom_detach
*
* Argument:
*
* Returns : None
*
* Description: Called to detach this device type driver
************************************************************/
void cdrom_detach(struct scst_device *dev)
{
struct cdrom_params *cdrom =
(struct cdrom_params *)dev->tgt_dev_specific;
TRACE_ENTRY();
TRACE_MEM("kfree for cdrom: %p", cdrom);
kfree(cdrom);
dev->tgt_dev_specific = NULL;
TRACE_EXIT();
return;
}
/********************************************************************
* Function: cdrom_parse
*
* Argument:
*
* Returns : The state of the command
*
* Description: This does the parsing of the command
*
* Note: Not all states are allowed on return
********************************************************************/
int cdrom_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb)
{
int res = SCST_CMD_STATE_DEFAULT;
struct cdrom_params *cdrom;
int fixed;
TRACE_ENTRY();
/*
* SCST sets good defaults for cmd->data_direction and cmd->bufflen
* based on info_cdb, therefore change them only if necessary
*/
if (info_cdb->flags & SCST_SMALL_TIMEOUT) {
cmd->timeout = CDROM_SMALL_TIMEOUT;
} else if (info_cdb->flags & SCST_LONG_TIMEOUT) {
cmd->timeout = CDROM_LONG_TIMEOUT;
} else {
cmd->timeout = CDROM_REG_TIMEOUT;
}
TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d lun %d(%d)",
info_cdb->op_name,
info_cdb->direction,
info_cdb->flags,
info_cdb->transfer_len, cmd->lun, (cmd->cdb[1] >> 5) & 7);
cmd->cdb[1] &= 0x1f;
fixed = info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED;
switch (cmd->cdb[0]) {
case READ_CAPACITY:
cmd->bufflen = READ_CAP_LEN;
cmd->data_direction = SCST_DATA_READ;
break;
case GPCMD_SET_STREAMING:
cmd->bufflen = (((*(cmd->cdb + 9)) & 0xff) << 8) +
((*(cmd->cdb + 10)) & 0xff);
cmd->bufflen &= 0xffff;
break;
case GPCMD_READ_CD:
cmd->bufflen = cmd->bufflen >> 8;
break;
#if 0
case SYNCHRONIZE_CACHE:
cmd->underflow = 0;
break;
#endif
case VERIFY_6:
case VERIFY:
case VERIFY_12:
case VERIFY_16:
if ((cmd->cdb[1] & BYTCHK) == 0) {
cmd->bufflen = 0;
cmd->data_direction = SCST_DATA_NONE;
fixed = 0;
}
break;
default:
/* It's all good */
break;
}
if (fixed) {
/*
* No need for locks here, since *_detach() can not be
* called, when there are existing commands.
*/
cdrom = (struct cdrom_params *)cmd->dev->tgt_dev_specific;
cmd->bufflen = info_cdb->transfer_len * cdrom->sector_size;
}
TRACE_DBG("res %d bufflen %zd direct %d",
res, cmd->bufflen, cmd->data_direction);
TRACE_EXIT();
return res;
}
/********************************************************************
* Function: cdrom_done
*
* Argument:
*
* Returns :
*
* Description: This is the completion routine for the command,
* it is used to extract any necessary information
* about a command.
********************************************************************/
int cdrom_done(struct scst_cmd *cmd)
{
int opcode = cmd->cdb[0];
int masked_status = cmd->masked_status;
struct cdrom_params *cdrom;
int res = SCST_CMD_STATE_DEFAULT;
TRACE_ENTRY();
if (unlikely(cmd->sg == NULL))
goto out;
/*
* SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len
* based on cmd->masked_status and cmd->data_direction, therefore change
* them only if necessary
*/
if ((masked_status == GOOD) || (masked_status == CONDITION_GOOD)) {
switch (opcode) {
case READ_CAPACITY:
{
/* Always keep track of cdrom capacity */
int buffer_size;
/*
* To force the compiler not to optimize it out to keep
* cdrom->sector_size access atomic
*/
volatile int sector_size;
uint8_t *buffer;
buffer_size = scst_get_buf_first(cmd, &buffer);
if (unlikely(buffer_size <= 0)) {
PRINT_ERROR_PR("%s: Unable to get the buffer",
__FUNCTION__);
scst_set_busy(cmd);
goto out;
}
/*
* No need for locks here, since *_detach() can not be
* called, when there are existing commands.
*/
cdrom =
(struct cdrom_params *)cmd->dev->tgt_dev_specific;
sector_size =
((buffer[4] << 24) | (buffer[5] << 16) |
(buffer[6] << 8) | (buffer[7] << 0));
if (!sector_size)
sector_size = 2048;
cdrom->sector_size = sector_size;
TRACE_DBG("Sector size is %i", cdrom->sector_size);
scst_put_buf(cmd, buffer);
break;
}
default:
/* It's all good */
break;
}
}
TRACE_DBG("cmd->tgt_resp_flags=%x, cmd->resp_data_len=%d, "
"res=%d", cmd->tgt_resp_flags, cmd->resp_data_len, res);
out:
TRACE_EXIT();
return res;
}
static int __init cdrom_init(void)
{
int res = 0;
TRACE_ENTRY();
cdrom_devtype.module = THIS_MODULE;
if (scst_register_dev_driver(&cdrom_devtype) < 0) {
res = -ENODEV;
goto out;
}
res = scst_dev_handler_build_std_proc(&cdrom_devtype);
if (res != 0)
goto out_err;
out:
TRACE_EXIT();
return res;
out_err:
scst_unregister_dev_driver(&cdrom_devtype);
goto out;
}
static void __exit cdrom_exit(void)
{
TRACE_ENTRY();
scst_dev_handler_destroy_std_proc(&cdrom_devtype);
scst_unregister_dev_driver(&cdrom_devtype);
TRACE_EXIT();
return;
}
module_init(cdrom_init);
module_exit(cdrom_exit);
MODULE_LICENSE("GPL");
+244
View File
@@ -0,0 +1,244 @@
/*
* scst_changer.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* SCSI medium changer (type 8) dev handler
*
* 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, version 2
* of the License.
*
* 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.
*/
#define LOG_PREFIX "dev_changer"
#include "scst_debug.h"
#include "scsi_tgt.h"
#include "scst_dev_handler.h"
#include "scst_debug.c"
#define CHANGER_NAME "dev_changer"
#define CHANGER_TYPE { \
name: CHANGER_NAME, \
type: TYPE_MEDIUM_CHANGER,\
parse_atomic: 1, \
/* dev_done_atomic: 1,*/ \
attach: changer_attach, \
/* detach: changer_detach,*/ \
parse: changer_parse, \
/* dev_done: changer_done*/ \
}
#define CHANGER_RETRIES 2
#define CHANGER_TIMEOUT (3 * HZ)
#define CHANGER_LONG_TIMEOUT (14000 * HZ)
#define READ_CAP_LEN 8
int changer_attach(struct scst_device *);
void changer_detach(struct scst_device *);
int changer_parse(struct scst_cmd *, const struct scst_info_cdb *);
int changer_done(struct scst_cmd *);
#if defined(DEBUG) || defined(TRACING)
unsigned long trace_flag = SCST_DEFAULT_DEV_LOG_FLAGS;
#endif
static struct scst_dev_type changer_devtype = CHANGER_TYPE;
/**************************************************************
* Function: changer_attach
*
* Argument:
*
* Returns : 1 if attached, error code otherwise
*
* Description:
*************************************************************/
int changer_attach(struct scst_device *dev)
{
int res = 0;
int retries;
TRACE_ENTRY();
if (dev->scsi_dev == NULL ||
dev->scsi_dev->type != dev->handler->type) {
PRINT_ERROR_PR("%s", "SCSI device not define or illegal type");
res = -ENODEV;
goto out;
}
/*
* If the device is offline, don't try to read capacity or any
* of the other stuff
*/
if (dev->scsi_dev->sdev_state == SDEV_OFFLINE)
{
TRACE_DBG("%s", "Device is offline");
res = -ENODEV;
goto out;
}
retries = SCST_DEV_UA_RETRIES;
do {
TRACE_DBG("%s", "Doing TEST_UNIT_READY");
res = scsi_test_unit_ready(dev->scsi_dev, CHANGER_TIMEOUT,
CHANGER_RETRIES);
TRACE_DBG("TEST_UNIT_READY done: %x", res);
} while ((--retries > 0) && res);
if (res)
res = -ENODEV;
out:
TRACE_EXIT_HRES(res);
return res;
}
/************************************************************
* Function: changer_detach
*
* Argument:
*
* Returns : None
*
* Description: Called to detach this device type driver
************************************************************/
void changer_detach(struct scst_device *dev)
{
TRACE_ENTRY();
TRACE_EXIT();
return;
}
/********************************************************************
* Function: changer_parse
*
* Argument:
*
* Returns : The state of the command
*
* Description: This does the parsing of the command
*
* Note: Not all states are allowed on return
********************************************************************/
int changer_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb)
{
int res = SCST_CMD_STATE_DEFAULT;
TRACE_ENTRY();
/*
* SCST sets good defaults for cmd->data_direction and cmd->bufflen
* based on info_cdb, therefore change them only if necessary
*/
if (info_cdb->flags & SCST_LONG_TIMEOUT) {
cmd->timeout = CHANGER_LONG_TIMEOUT;
} else {
cmd->timeout = CHANGER_TIMEOUT;
}
TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d",
info_cdb->op_name,
info_cdb->direction, info_cdb->flags, info_cdb->transfer_len);
#if 0
switch (cmd->cdb[0]) {
default:
/* It's all good */
break;
}
#endif
TRACE_DBG("res %d bufflen %zd direct %d",
res, cmd->bufflen, cmd->data_direction);
TRACE_EXIT();
return res;
}
/********************************************************************
* Function: changer_done
*
* Argument:
*
* Returns :
*
* Description: This is the completion routine for the command,
* it is used to extract any necessary information
* about a command.
********************************************************************/
int changer_done(struct scst_cmd *cmd)
{
int res = SCST_CMD_STATE_DEFAULT;
TRACE_ENTRY();
if (unlikely(cmd->sg == NULL))
goto out;
/*
* SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len
* based on cmd->masked_status and cmd->data_direction, therefore change
* them only if necessary
*/
#if 0
switch (cmd->cdb[0]) {
default:
/* It's all good */
break;
}
#endif
out:
TRACE_EXIT();
return res;
}
static int __init changer_init(void)
{
int res = 0;
TRACE_ENTRY();
changer_devtype.module = THIS_MODULE;
if (scst_register_dev_driver(&changer_devtype) < 0) {
res = -ENODEV;
goto out;
}
res = scst_dev_handler_build_std_proc(&changer_devtype);
if (res != 0)
goto out_err;
out:
TRACE_EXIT_RES(res);
return res;
out_err:
scst_unregister_dev_driver(&changer_devtype);
goto out;
}
static void __exit changer_exit(void)
{
TRACE_ENTRY();
scst_dev_handler_destroy_std_proc(&changer_devtype);
scst_unregister_dev_driver(&changer_devtype);
TRACE_EXIT();
return;
}
module_init(changer_init);
module_exit(changer_exit);
MODULE_LICENSE("GPL");
+94
View File
@@ -0,0 +1,94 @@
#include <scsi/scsi_eh.h>
#define SCST_DEV_UA_RETRIES 5
#if defined(DEBUG) || defined(TRACING)
#define DEV_HANDLER_LOG_ENTRY_NAME "trace_level"
#include <linux/module.h>
#include <linux/proc_fs.h>
#ifdef DEBUG
#define SCST_DEFAULT_DEV_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_PID | \
TRACE_FUNCTION | TRACE_MGMT | TRACE_MINOR | TRACE_MGMT_DEBUG)
#else
#define SCST_DEFAULT_DEV_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MINOR)
#endif
static int scst_dev_handler_proc_log_entry_read(char *buffer, char **start,
off_t offset, int length, int *eof, void *data)
{
int res = 0;
TRACE_ENTRY();
res = scst_proc_log_entry_read(buffer, start, offset, length, eof,
data, trace_flag, NULL);
TRACE_EXIT_RES(res);
return res;
}
static int scst_dev_handler_proc_log_entry_write(struct file *file,
const char *buf, unsigned long length, void *data)
{
int res = 0;
TRACE_ENTRY();
res = scst_proc_log_entry_write(file, buf, length, data,
&trace_flag, SCST_DEFAULT_DEV_LOG_FLAGS, NULL);
TRACE_EXIT_RES(res);
return res;
}
#endif /* defined(DEBUG) || defined(TRACING) */
static int scst_dev_handler_build_std_proc(struct scst_dev_type *dev_type)
{
int res = 0;
#if defined(DEBUG) || defined(TRACING)
struct proc_dir_entry *p, *root;
TRACE_ENTRY();
root = scst_proc_get_dev_type_root(dev_type);
if (root) {
/* create the proc file entry for the device */
p = create_proc_read_entry(DEV_HANDLER_LOG_ENTRY_NAME,
S_IFREG | S_IRUGO | S_IWUSR, root,
scst_dev_handler_proc_log_entry_read,
(void *)dev_type->name);
if (p == NULL) {
PRINT_ERROR_PR("Not enough memory to register dev "
"handler %s entry %s in /proc",
dev_type->name, DEV_HANDLER_LOG_ENTRY_NAME);
res = -ENOMEM;
goto out;
}
p->write_proc = scst_dev_handler_proc_log_entry_write;
}
out:
TRACE_EXIT_RES(res);
#endif
return res;
}
static void scst_dev_handler_destroy_std_proc(struct scst_dev_type *dev_type)
{
#if defined(DEBUG) || defined(TRACING)
struct proc_dir_entry *root;
TRACE_ENTRY();
root = scst_proc_get_dev_type_root(dev_type);
if (root) {
remove_proc_entry(DEV_HANDLER_LOG_ENTRY_NAME, root);
}
TRACE_EXIT();
#endif
}
+471
View File
@@ -0,0 +1,471 @@
/*
* scst_disk.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* SCSI disk (type 0) dev handler
* &
* SCSI disk (type 0) "performance" device handler (skip all READ and WRITE
* operations).
*
* 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, version 2
* of the License.
*
* 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.
*/
#include <linux/module.h>
#include <linux/init.h>
#define LOG_PREFIX "dev_disk"
#include "scst_debug.h"
#include "scsi_tgt.h"
#include "scst_dev_handler.h"
#include "scst_debug.c"
# define DISK_NAME "dev_disk"
# define DISK_PERF_NAME "dev_disk_perf"
#define DISK_TYPE { \
name: DISK_NAME, \
type: TYPE_DISK, \
parse_atomic: 1, \
dev_done_atomic: 1, \
exec_atomic: 1, \
attach: disk_attach, \
detach: disk_detach, \
parse: disk_parse, \
dev_done: disk_done, \
}
#define DISK_PERF_TYPE { \
name: DISK_PERF_NAME, \
type: TYPE_DISK, \
parse_atomic: 1, \
dev_done_atomic: 1, \
exec_atomic: 1, \
attach: disk_attach, \
detach: disk_detach, \
parse: disk_parse, \
dev_done: disk_done, \
exec: disk_exec, \
}
#define DISK_RETRIES 2
#define DISK_SMALL_TIMEOUT (3 * HZ)
#define DISK_REG_TIMEOUT (60 * HZ)
#define DISK_LONG_TIMEOUT (3600 * HZ)
#define READ_CAP_LEN 8
/* Flags */
#define BYTCHK 0x02
struct disk_params
{
int sector_size;
};
int disk_attach(struct scst_device *dev);
void disk_detach(struct scst_device *dev);
int disk_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cmd);
int disk_done(struct scst_cmd *cmd);
int disk_exec(struct scst_cmd *cmd);
#if defined(DEBUG) || defined(TRACING)
unsigned long trace_flag = SCST_DEFAULT_DEV_LOG_FLAGS;
#endif
static struct scst_dev_type disk_devtype = DISK_TYPE;
static struct scst_dev_type disk_devtype_perf = DISK_PERF_TYPE;
static int __init init_scst_disk_driver(void)
{
int res = 0;
TRACE_ENTRY();
disk_devtype.module = THIS_MODULE;
if (scst_register_dev_driver(&disk_devtype) < 0) {
res = -ENODEV;
goto out;
}
res = scst_dev_handler_build_std_proc(&disk_devtype);
if (res != 0)
goto out_unreg1;
disk_devtype_perf.module = THIS_MODULE;
if (scst_register_dev_driver(&disk_devtype_perf) < 0) {
res = -ENODEV;
goto out_unreg1_err1;
}
res = scst_dev_handler_build_std_proc(&disk_devtype_perf);
if (res != 0)
goto out_unreg2;
out:
TRACE_EXIT_RES(res);
return res;
out_unreg2:
scst_dev_handler_destroy_std_proc(&disk_devtype_perf);
out_unreg1_err1:
scst_dev_handler_destroy_std_proc(&disk_devtype);
out_unreg1:
scst_unregister_dev_driver(&disk_devtype);
goto out;
}
static void __exit exit_scst_disk_driver(void)
{
TRACE_ENTRY();
scst_dev_handler_destroy_std_proc(&disk_devtype_perf);
scst_unregister_dev_driver(&disk_devtype_perf);
scst_dev_handler_destroy_std_proc(&disk_devtype);
scst_unregister_dev_driver(&disk_devtype);
TRACE_EXIT();
return;
}
module_init(init_scst_disk_driver);
module_exit(exit_scst_disk_driver);
/**************************************************************
* Function: disk_attach
*
* Argument:
*
* Returns : 1 if attached, error code otherwise
*
* Description:
*************************************************************/
int disk_attach(struct scst_device *dev)
{
int res = 0;
uint8_t cmd[10];
const int buffer_size = 512;
uint8_t *buffer = NULL;
int retries;
unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
enum dma_data_direction data_dir;
unsigned char *sbuff;
struct disk_params *disk;
TRACE_ENTRY();
if (dev->scsi_dev == NULL ||
dev->scsi_dev->type != dev->handler->type) {
PRINT_ERROR_PR("%s", "SCSI device not define or illegal type");
res = -ENODEV;
goto out;
}
disk = kzalloc(sizeof(*disk), GFP_KERNEL);
TRACE_MEM("kzalloc(GFP_KERNEL) for struct disk_params (%zu): %p",
sizeof(*disk), disk);
if (disk == NULL) {
TRACE(TRACE_OUT_OF_MEM, "%s",
"Unable to allocate struct disk_params");
res = -ENOMEM;
goto out;
}
buffer = kzalloc(buffer_size, GFP_KERNEL);
TRACE_MEM("kzalloc(GFP_KERNEL) for %d: %p", buffer_size, buffer);
if (!buffer) {
TRACE(TRACE_OUT_OF_MEM, "%s", "Memory allocation failure");
res = -ENOMEM;
goto out_free_disk;
}
/* Clear any existing UA's and get disk capacity (disk block size) */
memset(cmd, 0, sizeof(cmd));
cmd[0] = READ_CAPACITY;
cmd[1] = (dev->scsi_dev->scsi_level <= SCSI_2) ?
((dev->scsi_dev->lun << 5) & 0xe0) : 0;
retries = SCST_DEV_UA_RETRIES;
while (1) {
memset(buffer, 0, buffer_size);
data_dir = SCST_DATA_READ;
sbuff = sense_buffer;
TRACE_DBG("%s", "Doing READ_CAPACITY");
res = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer,
buffer_size, sbuff,
DISK_REG_TIMEOUT, DISK_RETRIES, 0);
TRACE_DBG("READ_CAPACITY done: %x", res);
if (!res || (sbuff[12] != 0x28 && sbuff[12] != 0x29))
{
break;
}
if (!--retries) {
PRINT_ERROR_PR("UA not clear after %d retries",
SCST_DEV_UA_RETRIES);
res = -ENODEV;
goto out_free_buf;
}
}
if (res == 0) {
disk->sector_size = ((buffer[4] << 24) | (buffer[5] << 16) |
(buffer[6] << 8) | (buffer[7] << 0));
TRACE_DBG("Sector size is %i", disk->sector_size);
if (!disk->sector_size) {
disk->sector_size = 512;
}
} else {
TRACE_BUFFER("Sense set", sbuff, SCSI_SENSE_BUFFERSIZE);
res = -ENODEV;
goto out_free_buf;
}
out_free_buf:
TRACE_MEM("kfree for buffer: %p", buffer);
kfree(buffer);
out_free_disk:
if (res == 0)
dev->tgt_dev_specific = disk;
else {
TRACE_MEM("kfree for disk: %p", disk);
kfree(disk);
}
out:
TRACE_EXIT_RES(res);
return res;
}
/************************************************************
* Function: disk_detach
*
* Argument:
*
* Returns : None
*
* Description: Called to detach this device type driver
************************************************************/
void disk_detach(struct scst_device *dev)
{
struct disk_params *disk = (struct disk_params *)dev->tgt_dev_specific;
TRACE_ENTRY();
TRACE_MEM("kfree for disk: %p", disk);
kfree(disk);
dev->tgt_dev_specific = NULL;
TRACE_EXIT();
return;
}
/********************************************************************
* Function: disk_parse
*
* Argument:
*
* Returns : The state of the command
*
* Description: This does the parsing of the command
*
* Note: Not all states are allowed on return
********************************************************************/
int disk_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb)
{
int res = SCST_CMD_STATE_DEFAULT;
struct disk_params *disk;
int fixed;
TRACE_ENTRY();
/*
* SCST sets good defaults for cmd->data_direction and cmd->bufflen
* based on info_cdb, therefore change them only if necessary
*/
if (info_cdb->flags & SCST_SMALL_TIMEOUT) {
cmd->timeout = DISK_SMALL_TIMEOUT;
} else if (info_cdb->flags & SCST_LONG_TIMEOUT) {
cmd->timeout = DISK_LONG_TIMEOUT;
} else {
cmd->timeout = DISK_REG_TIMEOUT;
}
TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d",
info_cdb->op_name,
info_cdb->direction, info_cdb->flags, info_cdb->transfer_len);
fixed = info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED;
switch (cmd->cdb[0]) {
case READ_CAPACITY:
cmd->bufflen = READ_CAP_LEN;
cmd->data_direction = SCST_DATA_READ;
break;
#if 0
case SYNCHRONIZE_CACHE:
cmd->underflow = 0;
break;
#endif
case VERIFY_6:
case VERIFY:
case VERIFY_12:
case VERIFY_16:
if ((cmd->cdb[1] & BYTCHK) == 0) {
cmd->bufflen = 0;
cmd->data_direction = SCST_DATA_NONE;
fixed = 0;
}
break;
default:
/* It's all good */
break;
}
if (fixed) {
/*
* No need for locks here, since *_detach() can not be
* called, when there are existing commands.
*/
disk = (struct disk_params *)cmd->dev->tgt_dev_specific;
cmd->bufflen = info_cdb->transfer_len * disk->sector_size;
}
TRACE_DBG("res %d bufflen %zd direct %d",
res, cmd->bufflen, cmd->data_direction);
TRACE_EXIT_RES(res);
return res;
}
/********************************************************************
* Function: disk_done
*
* Argument:
*
* Returns :
*
* Description: This is the completion routine for the command,
* it is used to extract any necessary information
* about a command.
********************************************************************/
int disk_done(struct scst_cmd *cmd)
{
int opcode = cmd->cdb[0];
int masked_status = cmd->masked_status;
struct disk_params *disk;
int res = SCST_CMD_STATE_DEFAULT;
TRACE_ENTRY();
if (unlikely(cmd->sg == NULL))
goto out;
/*
* SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len
* based on cmd->masked_status and cmd->data_direction, therefore change
* them only if necessary
*/
if ((masked_status == GOOD) || (masked_status == CONDITION_GOOD)) {
switch (opcode) {
case READ_CAPACITY:
{
/* Always keep track of disk capacity */
int buffer_size;
/*
* To force the compiler not to optimize it out to keep
* disk->sector_size access atomic
*/
volatile int sector_size;
uint8_t *buffer;
buffer_size = scst_get_buf_first(cmd, &buffer);
if (unlikely(buffer_size <= 0)) {
PRINT_ERROR_PR("%s: Unable to get the buffer",
__FUNCTION__);
scst_set_busy(cmd);
goto out;
}
/*
* No need for locks here, since *_detach() can not be
* called, when there are existing commands.
*/
disk = (struct disk_params *)cmd->dev->tgt_dev_specific;
sector_size =
((buffer[4] << 24) | (buffer[5] << 16) |
(buffer[6] << 8) | (buffer[7] << 0));
if (!sector_size)
sector_size = 512;
disk->sector_size = sector_size;
TRACE_DBG("Sector size is %i", disk->sector_size);
scst_put_buf(cmd, buffer);
break;
}
default:
/* It's all good */
break;
}
}
TRACE_DBG("cmd->tgt_resp_flags=%x, cmd->resp_data_len=%d, "
"res=%d", cmd->tgt_resp_flags, cmd->resp_data_len, res);
out:
TRACE_EXIT_RES(res);
return res;
}
/********************************************************************
* Function: disk_exec
*
* Argument:
*
* Returns :
*
* Description: Make SCST do nothing for data READs and WRITES.
* Intended for raw line performance testing
********************************************************************/
int disk_exec(struct scst_cmd *cmd)
{
int res = SCST_EXEC_NOT_COMPLETED;
int opcode = cmd->cdb[0];
TRACE_ENTRY();
switch (opcode) {
case WRITE_6:
case WRITE_10:
case WRITE_12:
case WRITE_16:
case READ_6:
case READ_10:
case READ_12:
case READ_16:
res = SCST_EXEC_COMPLETED;
cmd->status = 0;
cmd->masked_status = 0;
cmd->msg_status = 0;
cmd->host_status = DID_OK;
cmd->driver_status = 0;
cmd->completed = 1;
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT);
break;
}
TRACE_EXIT_RES(res);
return res;
}
MODULE_LICENSE("GPL");
File diff suppressed because it is too large Load Diff
+499
View File
@@ -0,0 +1,499 @@
/*
* scst_modisk.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* SCSI MO disk (type 7) dev handler
* &
* SCSI MO disk (type 7) "performance" device handler (skip all READ and WRITE
* operations).
*
* 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, version 2
* of the License.
*
* 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.
*/
#include <linux/module.h>
#include <linux/init.h>
#define LOG_PREFIX "dev_modisk"
#include "scst_debug.h"
#include "scsi_tgt.h"
#include "scst_dev_handler.h"
#include "scst_debug.c"
# define MODISK_NAME "dev_modisk"
# define MODISK_PERF_NAME "dev_modisk_perf"
#define MODISK_TYPE { \
name: MODISK_NAME, \
type: TYPE_MOD, \
parse_atomic: 1, \
dev_done_atomic: 1, \
exec_atomic: 1, \
attach: modisk_attach, \
detach: modisk_detach, \
parse: modisk_parse, \
dev_done: modisk_done, \
}
#define MODISK_PERF_TYPE { \
name: MODISK_PERF_NAME, \
type: TYPE_MOD, \
parse_atomic: 1, \
dev_done_atomic: 1, \
exec_atomic: 1, \
attach: modisk_attach, \
detach: modisk_detach, \
parse: modisk_parse, \
dev_done: modisk_done, \
exec: modisk_exec, \
}
#define MODISK_RETRIES 2
#define MODISK_SMALL_TIMEOUT (3 * HZ)
#define MODISK_REG_TIMEOUT (900 * HZ)
#define MODISK_LONG_TIMEOUT (14000 * HZ)
#define READ_CAP_LEN 8
#define MODISK_SECTOR_SIZE 1024
/* Flags */
#define BYTCHK 0x02
struct modisk_params
{
int sector_size;
};
int modisk_attach(struct scst_device *);
void modisk_detach(struct scst_device *);
int modisk_parse(struct scst_cmd *, const struct scst_info_cdb *);
int modisk_done(struct scst_cmd *);
int modisk_exec(struct scst_cmd *);
#if defined(DEBUG) || defined(TRACING)
unsigned long trace_flag = SCST_DEFAULT_DEV_LOG_FLAGS;
#endif
static struct scst_dev_type modisk_devtype = MODISK_TYPE;
static struct scst_dev_type modisk_devtype_perf = MODISK_PERF_TYPE;
static int __init init_scst_modisk_driver(void)
{
int res = 0;
TRACE_ENTRY();
modisk_devtype.module = THIS_MODULE;
if (scst_register_dev_driver(&modisk_devtype) < 0) {
res = -ENODEV;
goto out;
}
res = scst_dev_handler_build_std_proc(&modisk_devtype);
if (res != 0)
goto out_unreg1;
modisk_devtype_perf.module = THIS_MODULE;
if (scst_register_dev_driver(&modisk_devtype_perf) < 0) {
res = -ENODEV;
goto out_unreg1_err1;
}
res = scst_dev_handler_build_std_proc(&modisk_devtype_perf);
if (res != 0)
goto out_unreg2;
out:
TRACE_EXIT_RES(res);
return res;
out_unreg2:
scst_dev_handler_destroy_std_proc(&modisk_devtype_perf);
out_unreg1_err1:
scst_dev_handler_destroy_std_proc(&modisk_devtype);
out_unreg1:
scst_unregister_dev_driver(&modisk_devtype);
goto out;
}
static void __exit exit_scst_modisk_driver(void)
{
TRACE_ENTRY();
scst_dev_handler_destroy_std_proc(&modisk_devtype_perf);
scst_unregister_dev_driver(&modisk_devtype_perf);
scst_dev_handler_destroy_std_proc(&modisk_devtype);
scst_unregister_dev_driver(&modisk_devtype);
TRACE_EXIT();
return;
}
module_init(init_scst_modisk_driver);
module_exit(exit_scst_modisk_driver);
/**************************************************************
* Function: modisk_attach
*
* Argument:
*
* Returns : 1 if attached, error code otherwise
*
* Description:
*************************************************************/
int modisk_attach(struct scst_device *dev)
{
int res = 0;
uint8_t cmd[10];
const int buffer_size = 512;
uint8_t *buffer = NULL;
int retries;
unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
enum dma_data_direction data_dir;
unsigned char *sbuff;
struct modisk_params *modisk;
TRACE_ENTRY();
if (dev->scsi_dev == NULL ||
dev->scsi_dev->type != dev->handler->type) {
PRINT_ERROR_PR("%s", "SCSI device not define or illegal type");
res = -ENODEV;
goto out;
}
modisk = kzalloc(sizeof(*modisk), GFP_KERNEL);
TRACE_MEM("kzalloc(GFP_KERNEL) for struct modisk_params (%zu): %p",
sizeof(*modisk), modisk);
if (modisk == NULL) {
TRACE(TRACE_OUT_OF_MEM, "%s",
"Unable to allocate struct modisk_params");
res = -ENOMEM;
goto out;
}
modisk->sector_size = MODISK_SECTOR_SIZE;
/*
* If the device is offline, don't try to read capacity or any
* of the other stuff
*/
if (dev->scsi_dev->sdev_state == SDEV_OFFLINE)
{
TRACE_DBG("%s", "Device is offline");
res = -ENODEV;
goto out_free_modisk;
}
buffer = kzalloc(buffer_size, GFP_KERNEL);
TRACE_MEM("kzalloc(GFP_KERNEL) for %d: %p", buffer_size, buffer);
if (!buffer) {
TRACE(TRACE_OUT_OF_MEM, "%s", "Memory allocation failure");
res = -ENOMEM;
goto out_free_modisk;
}
/* Clear any existing UA's and get modisk capacity (modisk block size) */
memset(cmd, 0, sizeof(cmd));
cmd[0] = READ_CAPACITY;
cmd[1] = (dev->scsi_dev->scsi_level <= SCSI_2) ?
((dev->scsi_dev->lun << 5) & 0xe0) : 0;
retries = SCST_DEV_UA_RETRIES;
while (1) {
memset(buffer, 0, buffer_size);
data_dir = SCST_DATA_READ;
sbuff = sense_buffer;
TRACE_DBG("%s", "Doing READ_CAPACITY");
res = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer,
buffer_size, sbuff,
MODISK_REG_TIMEOUT, MODISK_RETRIES, 0);
TRACE_DBG("READ_CAPACITY done: %x", res);
if (!res || (sbuff[2] != UNIT_ATTENTION))
{
break;
}
if (!--retries) {
PRINT_ERROR_PR("UA not clear after %d retries",
SCST_DEV_UA_RETRIES);
goto out_free_buf;
}
}
if (res == 0) {
modisk->sector_size = ((buffer[4] << 24) | (buffer[5] << 16) |
(buffer[6] << 8) | (buffer[7] << 0));
TRACE_DBG("Sector size is %i scsi_level %d(SCSI_2 %d)",
modisk->sector_size, dev->scsi_dev->scsi_level, SCSI_2);
if (!modisk->sector_size) {
modisk->sector_size = MODISK_SECTOR_SIZE;
}
} else {
TRACE_BUFFER("Sense set", sbuff, SCSI_SENSE_BUFFERSIZE);
if (sbuff[2] != NOT_READY)
res = -ENODEV;
goto out_free_buf;
}
out_free_buf:
TRACE_MEM("kfree for buffer: %p", buffer);
kfree(buffer);
out_free_modisk:
if (res == 0)
dev->tgt_dev_specific = modisk;
else {
TRACE_MEM("kfree for modisk: %p", modisk);
kfree(modisk);
}
out:
TRACE_EXIT_RES(res);
return res;
}
/************************************************************
* Function: modisk_detach
*
* Argument:
*
* Returns : None
*
* Description: Called to detach this device type driver
************************************************************/
void modisk_detach(struct scst_device *dev)
{
struct modisk_params *modisk =
(struct modisk_params *)dev->tgt_dev_specific;
TRACE_ENTRY();
TRACE_MEM("kfree for modisk: %p", modisk);
kfree(modisk);
dev->tgt_dev_specific = NULL;
TRACE_EXIT();
return;
}
/********************************************************************
* Function: modisk_parse
*
* Argument:
*
* Returns : The state of the command
*
* Description: This does the parsing of the command
*
* Note: Not all states are allowed on return
********************************************************************/
int modisk_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb)
{
int res = SCST_CMD_STATE_DEFAULT;
struct modisk_params *modisk;
int fixed;
TRACE_ENTRY();
/*
* SCST sets good defaults for cmd->data_direction and cmd->bufflen
* based on info_cdb, therefore change them only if necessary
*/
if (info_cdb->flags & SCST_SMALL_TIMEOUT) {
cmd->timeout = MODISK_SMALL_TIMEOUT;
} else if (info_cdb->flags & SCST_LONG_TIMEOUT) {
cmd->timeout = MODISK_LONG_TIMEOUT;
} else {
cmd->timeout = MODISK_REG_TIMEOUT;
}
TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d lun %d(%d)",
info_cdb->op_name,
info_cdb->direction,
info_cdb->flags,
info_cdb->transfer_len, cmd->lun, (cmd->cdb[1] >> 5) & 7);
cmd->cdb[1] &= 0x1f;
fixed = info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED;
switch (cmd->cdb[0]) {
case READ_CAPACITY:
cmd->bufflen = READ_CAP_LEN;
cmd->data_direction = SCST_DATA_READ;
break;
case 0xB6 /* SET_STREAMING */ :
cmd->bufflen = (((*(cmd->cdb + 9)) & 0xff) << 8) +
((*(cmd->cdb + 10)) & 0xff);
cmd->bufflen &= 0xffff;
break;
case 0xBE /* READ_CD */ :
cmd->bufflen = cmd->bufflen >> 8;
break;
#if 0
case SYNCHRONIZE_CACHE:
cmd->underflow = 0;
break;
#endif
case VERIFY_6:
case VERIFY:
case VERIFY_12:
case VERIFY_16:
if ((cmd->cdb[1] & BYTCHK) == 0) {
cmd->bufflen = 0;
cmd->data_direction = SCST_DATA_NONE;
fixed = 0;
}
break;
default:
/* It's all good */
break;
}
if (fixed) {
/*
* No need for locks here, since *_detach() can not be
* called, when there are existing commands.
*/
modisk = (struct modisk_params *)cmd->dev->tgt_dev_specific;
cmd->bufflen = info_cdb->transfer_len * modisk->sector_size;
}
TRACE_DBG("res %d bufflen %zd direct %d",
res, cmd->bufflen, cmd->data_direction);
TRACE_EXIT_RES(res);
return res;
}
/********************************************************************
* Function: modisk_done
*
* Argument:
*
* Returns :
*
* Description: This is the completion routine for the command,
* it is used to extract any necessary information
* about a command.
********************************************************************/
int modisk_done(struct scst_cmd *cmd)
{
int opcode = cmd->cdb[0];
int masked_status = cmd->masked_status;
struct modisk_params *modisk;
int res = SCST_CMD_STATE_DEFAULT;
TRACE_ENTRY();
if (unlikely(cmd->sg == NULL))
goto out;
/*
* SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len
* based on cmd->masked_status and cmd->data_direction, therefore change
* them only if necessary
*/
if ((masked_status == GOOD) || (masked_status == CONDITION_GOOD)) {
switch (opcode) {
case READ_CAPACITY:
{
/* Always keep track of modisk capacity */
int buffer_size;
/*
* To force the compiler not to optimize it out to keep
* modisk->sector_size access atomic
*/
volatile int sector_size;
uint8_t *buffer;
buffer_size = scst_get_buf_first(cmd, &buffer);
if (unlikely(buffer_size <= 0)) {
PRINT_ERROR_PR("%s: Unable to get the buffer",
__FUNCTION__);
scst_set_busy(cmd);
goto out;
}
/*
* No need for locks here, since *_detach() can not be
* called, when there are existing commands.
*/
modisk =
(struct modisk_params *)cmd->dev->tgt_dev_specific;
sector_size =
((buffer[4] << 24) | (buffer[5] << 16) |
(buffer[6] << 8) | (buffer[7] << 0));
if (!sector_size)
sector_size = MODISK_SECTOR_SIZE;
modisk->sector_size = sector_size;
TRACE_DBG("Sector size is %i", modisk->sector_size);
scst_put_buf(cmd, buffer);
break;
}
default:
/* It's all good */
break;
}
}
TRACE_DBG("cmd->tgt_resp_flags=%x, cmd->resp_data_len=%d, "
"res=%d", cmd->tgt_resp_flags, cmd->resp_data_len, res);
out:
TRACE_EXIT_RES(res);
return res;
}
/********************************************************************
* Function: modisk_exec
*
* Argument:
*
* Returns :
*
* Description: Make SCST do nothing for data READs and WRITES.
* Intended for raw line performance testing
********************************************************************/
int modisk_exec(struct scst_cmd *cmd)
{
int res = SCST_EXEC_NOT_COMPLETED;
int opcode = cmd->cdb[0];
TRACE_ENTRY();
switch (opcode) {
case WRITE_6:
case WRITE_10:
case WRITE_12:
case WRITE_16:
case READ_6:
case READ_10:
case READ_12:
case READ_16:
res = SCST_EXEC_COMPLETED;
cmd->status = 0;
cmd->masked_status = 0;
cmd->msg_status = 0;
cmd->host_status = DID_OK;
cmd->driver_status = 0;
cmd->completed = 1;
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT);
break;
}
TRACE_EXIT_RES(res);
return res;
}
MODULE_LICENSE("GPL");
+244
View File
@@ -0,0 +1,244 @@
/*
* scst_processor.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* SCSI medium processor (type 3) dev handler
*
* 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, version 2
* of the License.
*
* 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.
*/
#define LOG_PREFIX "dev_processor"
#include "scst_debug.h"
#include "scsi_tgt.h"
#include "scst_dev_handler.h"
#include "scst_debug.c"
#define PROCESSOR_NAME "dev_processor"
#define PROCESSOR_TYPE { \
name: PROCESSOR_NAME, \
type: TYPE_PROCESSOR, \
parse_atomic: 1, \
/* dev_done_atomic: 1,*/ \
attach: processor_attach, \
/* detach: processor_detach,*/ \
parse: processor_parse, \
/* dev_done: processor_done*/ \
}
#define PROCESSOR_RETRIES 2
#define PROCESSOR_TIMEOUT (3 * HZ)
#define PROCESSOR_LONG_TIMEOUT (14000 * HZ)
#define READ_CAP_LEN 8
int processor_attach(struct scst_device *);
void processor_detach(struct scst_device *);
int processor_parse(struct scst_cmd *, const struct scst_info_cdb *);
int processor_done(struct scst_cmd *);
#if defined(DEBUG) || defined(TRACING)
unsigned long trace_flag = SCST_DEFAULT_DEV_LOG_FLAGS;
#endif
static struct scst_dev_type processor_devtype = PROCESSOR_TYPE;
/**************************************************************
* Function: processor_attach
*
* Argument:
*
* Returns : 1 if attached, error code otherwise
*
* Description:
*************************************************************/
int processor_attach(struct scst_device *dev)
{
int res = 0;
int retries;
TRACE_ENTRY();
if (dev->scsi_dev == NULL ||
dev->scsi_dev->type != dev->handler->type) {
PRINT_ERROR_PR("%s", "SCSI device not define or illegal type");
res = -ENODEV;
goto out;
}
/*
* If the device is offline, don't try to read capacity or any
* of the other stuff
*/
if (dev->scsi_dev->sdev_state == SDEV_OFFLINE)
{
TRACE_DBG("%s", "Device is offline");
res = -ENODEV;
goto out;
}
retries = SCST_DEV_UA_RETRIES;
do {
TRACE_DBG("%s", "Doing TEST_UNIT_READY");
res = scsi_test_unit_ready(dev->scsi_dev, PROCESSOR_TIMEOUT,
PROCESSOR_RETRIES);
TRACE_DBG("TEST_UNIT_READY done: %x", res);
} while ((--retries > 0) && res);
if (res)
res = -ENODEV;
out:
TRACE_EXIT();
return res;
}
/************************************************************
* Function: processor_detach
*
* Argument:
*
* Returns : None
*
* Description: Called to detach this device type driver
************************************************************/
void processor_detach(struct scst_device *dev)
{
TRACE_ENTRY();
TRACE_EXIT();
return;
}
/********************************************************************
* Function: processor_parse
*
* Argument:
*
* Returns : The state of the command
*
* Description: This does the parsing of the command
*
* Note: Not all states are allowed on return
********************************************************************/
int processor_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb)
{
int res = SCST_CMD_STATE_DEFAULT;
TRACE_ENTRY();
/*
* SCST sets good defaults for cmd->data_direction and cmd->bufflen
* based on info_cdb, therefore change them only if necessary
*/
if (info_cdb->flags & SCST_LONG_TIMEOUT) {
cmd->timeout = PROCESSOR_LONG_TIMEOUT;
} else {
cmd->timeout = PROCESSOR_TIMEOUT;
}
TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d",
info_cdb->op_name,
info_cdb->direction, info_cdb->flags, info_cdb->transfer_len);
#if 0
switch (cmd->cdb[0]) {
default:
/* It's all good */
break;
}
#endif
TRACE_DBG("res %d bufflen %zd direct %d",
res, cmd->bufflen, cmd->data_direction);
TRACE_EXIT();
return res;
}
/********************************************************************
* Function: processor_done
*
* Argument:
*
* Returns :
*
* Description: This is the completion routine for the command,
* it is used to extract any necessary information
* about a command.
********************************************************************/
int processor_done(struct scst_cmd *cmd)
{
int res = SCST_CMD_STATE_DEFAULT;
TRACE_ENTRY();
if (unlikely(cmd->sg == NULL))
goto out;
/*
* SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len
* based on cmd->masked_status and cmd->data_direction, therefore change
* them only if necessary
*/
#if 0
switch (cmd->cdb[0]) {
default:
/* It's all good */
break;
}
#endif
out:
TRACE_EXIT();
return res;
}
static int __init processor_init(void)
{
int res = 0;
TRACE_ENTRY();
processor_devtype.module = THIS_MODULE;
if (scst_register_dev_driver(&processor_devtype) < 0) {
res = -ENODEV;
goto out;
}
res = scst_dev_handler_build_std_proc(&processor_devtype);
if (res != 0)
goto out_err;
out:
TRACE_EXIT_RES(res);
return res;
out_err:
scst_unregister_dev_driver(&processor_devtype);
goto out;
}
static void __exit processor_exit(void)
{
TRACE_ENTRY();
scst_dev_handler_destroy_std_proc(&processor_devtype);
scst_unregister_dev_driver(&processor_devtype);
TRACE_EXIT();
return;
}
module_init(processor_init);
module_exit(processor_exit);
MODULE_LICENSE("GPL");
+244
View File
@@ -0,0 +1,244 @@
/*
* scst_raid.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* SCSI raid(controller) (type 0xC) dev handler
*
* 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, version 2
* of the License.
*
* 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.
*/
#define LOG_PREFIX "dev_raid"
#include "scst_debug.h"
#include "scsi_tgt.h"
#include "scst_dev_handler.h"
#include "scst_debug.c"
#define RAID_NAME "dev_raid"
#define RAID_TYPE { \
name: RAID_NAME, \
type: TYPE_RAID, \
parse_atomic: 1, \
/* dev_done_atomic: 1,*/ \
attach: raid_attach, \
/* detach: raid_detach,*/ \
parse: raid_parse, \
/* dev_done: raid_done*/ \
}
#define RAID_RETRIES 2
#define RAID_TIMEOUT (3 * HZ)
#define RAID_LONG_TIMEOUT (14000 * HZ)
#define READ_CAP_LEN 8
int raid_attach(struct scst_device *);
void raid_detach(struct scst_device *);
int raid_parse(struct scst_cmd *, const struct scst_info_cdb *);
int raid_done(struct scst_cmd *);
#if defined(DEBUG) || defined(TRACING)
unsigned long trace_flag = SCST_DEFAULT_DEV_LOG_FLAGS;
#endif
static struct scst_dev_type raid_devtype = RAID_TYPE;
/**************************************************************
* Function: raid_attach
*
* Argument:
*
* Returns : 1 if attached, error code otherwise
*
* Description:
*************************************************************/
int raid_attach(struct scst_device *dev)
{
int res = 0;
int retries;
TRACE_ENTRY();
if (dev->scsi_dev == NULL ||
dev->scsi_dev->type != dev->handler->type) {
PRINT_ERROR_PR("%s", "SCSI device not define or illegal type");
res = -ENODEV;
goto out;
}
/*
* If the device is offline, don't try to read capacity or any
* of the other stuff
*/
if (dev->scsi_dev->sdev_state == SDEV_OFFLINE)
{
TRACE_DBG("%s", "Device is offline");
res = -ENODEV;
goto out;
}
retries = SCST_DEV_UA_RETRIES;
do {
TRACE_DBG("%s", "Doing TEST_UNIT_READY");
res = scsi_test_unit_ready(dev->scsi_dev, RAID_TIMEOUT,
RAID_RETRIES);
TRACE_DBG("TEST_UNIT_READY done: %x", res);
} while ((--retries > 0) && res);
if (res)
res = -ENODEV;
out:
TRACE_EXIT();
return res;
}
/************************************************************
* Function: raid_detach
*
* Argument:
*
* Returns : None
*
* Description: Called to detach this device type driver
************************************************************/
void raid_detach(struct scst_device *dev)
{
TRACE_ENTRY();
TRACE_EXIT();
return;
}
/********************************************************************
* Function: raid_parse
*
* Argument:
*
* Returns : The state of the command
*
* Description: This does the parsing of the command
*
* Note: Not all states are allowed on return
********************************************************************/
int raid_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb)
{
int res = SCST_CMD_STATE_DEFAULT;
TRACE_ENTRY();
/*
* SCST sets good defaults for cmd->data_direction and cmd->bufflen
* based on info_cdb, therefore change them only if necessary
*/
if (info_cdb->flags & SCST_LONG_TIMEOUT) {
cmd->timeout = RAID_LONG_TIMEOUT;
} else {
cmd->timeout = RAID_TIMEOUT;
}
TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d",
info_cdb->op_name,
info_cdb->direction, info_cdb->flags, info_cdb->transfer_len);
#if 0
switch (cmd->cdb[0]) {
default:
/* It's all good */
break;
}
#endif
TRACE_DBG("res %d bufflen %zd direct %d",
res, cmd->bufflen, cmd->data_direction);
TRACE_EXIT();
return res;
}
/********************************************************************
* Function: raid_done
*
* Argument:
*
* Returns :
*
* Description: This is the completion routine for the command,
* it is used to extract any necessary information
* about a command.
********************************************************************/
int raid_done(struct scst_cmd *cmd)
{
int res = SCST_CMD_STATE_DEFAULT;
TRACE_ENTRY();
if (unlikely(cmd->sg == NULL))
goto out;
/*
* SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len
* based on cmd->masked_status and cmd->data_direction, therefore change
* them only if necessary
*/
#if 0
switch (cmd->cdb[0]) {
default:
/* It's all good */
break;
}
#endif
out:
TRACE_EXIT();
return res;
}
static int __init raid_init(void)
{
int res = 0;
TRACE_ENTRY();
raid_devtype.module = THIS_MODULE;
if (scst_register_dev_driver(&raid_devtype) < 0) {
res = -ENODEV;
goto out;
}
res = scst_dev_handler_build_std_proc(&raid_devtype);
if (res != 0)
goto out_err;
out:
TRACE_EXIT_RES(res);
return res;
out_err:
scst_unregister_dev_driver(&raid_devtype);
goto out;
}
static void __exit raid_exit(void)
{
TRACE_ENTRY();
scst_dev_handler_destroy_std_proc(&raid_devtype);
scst_unregister_dev_driver(&raid_devtype);
TRACE_EXIT();
return;
}
module_init(raid_init);
module_exit(raid_exit);
MODULE_LICENSE("GPL");
+531
View File
@@ -0,0 +1,531 @@
/*
* scst_tape.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* SCSI tape (type 1) dev handler
* &
* SCSI tape (type 1) "performance" device handler (skip all READ and WRITE
* operations).
*
* 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, version 2
* of the License.
*
* 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.
*/
#include <linux/module.h>
#include <linux/init.h>
#define LOG_PREFIX "dev_tape"
#include "scst_debug.h"
#include "scsi_tgt.h"
#include "scst_dev_handler.h"
#include "scst_debug.c"
# define TAPE_NAME "dev_tape"
# define TAPE_PERF_NAME "dev_tape_perf"
#define TAPE_TYPE { \
name: TAPE_NAME, \
type: TYPE_TAPE, \
parse_atomic: 1, \
dev_done_atomic: 1, \
exec_atomic: 1, \
attach: tape_attach, \
detach: tape_detach, \
parse: tape_parse, \
dev_done: tape_done, \
}
#define TAPE_PERF_TYPE { \
name: TAPE_PERF_NAME, \
type: TYPE_TAPE, \
parse_atomic: 1, \
dev_done_atomic: 1, \
exec_atomic: 1, \
attach: tape_attach, \
detach: tape_detach, \
parse: tape_parse, \
dev_done: tape_done, \
exec: tape_exec, \
}
#define TAPE_RETRIES 2
#define TAPE_SMALL_TIMEOUT (3 * HZ)
#define TAPE_REG_TIMEOUT (900 * HZ)
#define TAPE_LONG_TIMEOUT (14000 * HZ)
/* The fixed bit in READ/WRITE/VERIFY */
#define SILI_BIT 2
/* Bits in the READ POSITION command */
#define TCLP_BIT 4
#define LONG_BIT 2
#define BT_BIT 1
#define POSITION_LEN_SHORT 20
#define POSITION_LEN_LONG 32
struct tape_params
{
spinlock_t tp_lock;
uint8_t density;
uint8_t mode;
uint8_t speed;
uint8_t medium_type;
int block_size;
};
int tape_attach(struct scst_device *);
void tape_detach(struct scst_device *);
int tape_parse(struct scst_cmd *, const struct scst_info_cdb *);
int tape_done(struct scst_cmd *);
int tape_exec(struct scst_cmd *);
#if defined(DEBUG) || defined(TRACING)
unsigned long trace_flag = SCST_DEFAULT_DEV_LOG_FLAGS;
#endif
static struct scst_dev_type tape_devtype = TAPE_TYPE;
static struct scst_dev_type tape_devtype_perf = TAPE_PERF_TYPE;
static int __init init_scst_tape_driver(void)
{
int res = 0;
TRACE_ENTRY();
tape_devtype.module = THIS_MODULE;
if (scst_register_dev_driver(&tape_devtype) < 0) {
res = -ENODEV;
goto out;
}
res = scst_dev_handler_build_std_proc(&tape_devtype);
if (res != 0)
goto out_unreg1;
tape_devtype_perf.module = THIS_MODULE;
if (scst_register_dev_driver(&tape_devtype_perf) < 0) {
res = -ENODEV;
goto out_unreg1_err1;
}
res = scst_dev_handler_build_std_proc(&tape_devtype_perf);
if (res != 0)
goto out_unreg2;
out:
TRACE_EXIT_RES(res);
return res;
out_unreg2:
scst_dev_handler_destroy_std_proc(&tape_devtype_perf);
out_unreg1_err1:
scst_dev_handler_destroy_std_proc(&tape_devtype);
out_unreg1:
scst_unregister_dev_driver(&tape_devtype);
goto out;
}
static void __exit exit_scst_tape_driver(void)
{
TRACE_ENTRY();
scst_dev_handler_destroy_std_proc(&tape_devtype_perf);
scst_unregister_dev_driver(&tape_devtype_perf);
scst_dev_handler_destroy_std_proc(&tape_devtype);
scst_unregister_dev_driver(&tape_devtype);
TRACE_EXIT();
return;
}
module_init(init_scst_tape_driver);
module_exit(exit_scst_tape_driver);
/**************************************************************
* Function: tape_attach
*
* Argument:
*
* Returns : 1 if attached, error code otherwise
*
* Description:
*************************************************************/
int tape_attach(struct scst_device *dev)
{
int res = 0;
int retries;
struct scsi_mode_data data;
const int buffer_size = 512;
uint8_t *buffer = NULL;
struct tape_params *tape;
TRACE_ENTRY();
if (dev->scsi_dev == NULL ||
dev->scsi_dev->type != dev->handler->type) {
PRINT_ERROR_PR("%s", "SCSI device not define or illegal type");
res = -ENODEV;
goto out;
}
tape = kzalloc(sizeof(*tape), GFP_KERNEL);
TRACE_MEM("kzalloc(GFP_KERNEL) for struct tape_params (%zu): %p",
sizeof(*tape), tape);
if (tape == NULL) {
TRACE(TRACE_OUT_OF_MEM, "%s",
"Unable to allocate struct tape_params");
res = -ENOMEM;
goto out;
}
spin_lock_init(&tape->tp_lock);
buffer = kmalloc(buffer_size, GFP_KERNEL);
TRACE_MEM("kmalloc(GFP_KERNEL) for %d: %p", buffer_size, buffer);
if (!buffer) {
TRACE(TRACE_OUT_OF_MEM, "%s", "Memory allocation failure");
res = -ENOMEM;
goto out_free_req;
}
retries = SCST_DEV_UA_RETRIES;
do {
TRACE_DBG("%s", "Doing TEST_UNIT_READY");
res = scsi_test_unit_ready(dev->scsi_dev, TAPE_SMALL_TIMEOUT,
TAPE_RETRIES);
TRACE_DBG("TEST_UNIT_READY done: %x", res);
} while ((--retries > 0) && res);
if (res) {
res = -ENODEV;
goto out;
}
TRACE_DBG("%s", "Doing MODE_SENSE");
res = scsi_mode_sense(dev->scsi_dev,
((dev->scsi_dev->scsi_level <= SCSI_2) ?
((dev->scsi_dev->lun << 5) & 0xe0) : 0),
0 /* Mode Page 0 */,
buffer, buffer_size,
TAPE_SMALL_TIMEOUT, TAPE_RETRIES,
&data, NULL);
TRACE_DBG("MODE_SENSE done: %x", res);
if (res == 0) {
if (buffer[3] == 8) {
tape->block_size = ((buffer[9] << 16) |
(buffer[10] << 8) |
(buffer[11] << 0));
} else {
tape->block_size = 512;
}
tape->medium_type = buffer[1];
tape->mode = (buffer[2] & 0x70) >> 4;
tape->speed = buffer[2] & 0x0f;
tape->density = buffer[4];
TRACE_DBG("Tape: lun %d. bs %d. type 0x%02x mode 0x%02x "
"speed 0x%02x dens 0x%02x", dev->scsi_dev->lun,
tape->block_size, tape->medium_type,
tape->mode, tape->speed, tape->density);
} else {
res = -ENODEV;
goto out_free_buf;
}
out_free_buf:
TRACE_MEM("kfree for buffer: %p", buffer);
kfree(buffer);
out_free_req:
if (res == 0)
dev->tgt_dev_specific = tape;
else {
TRACE_MEM("kfree for tape: %p", tape);
kfree(tape);
}
out:
TRACE_EXIT_RES(res);
return res;
}
/************************************************************
* Function: tape_detach
*
* Argument:
*
* Returns : None
*
* Description: Called to detach this device type driver
************************************************************/
void tape_detach(struct scst_device *dev)
{
struct tape_params *tape = (struct tape_params *)dev->tgt_dev_specific;
TRACE_ENTRY();
TRACE_MEM("kfree for tape: %p", tape);
kfree(tape);
dev->tgt_dev_specific = NULL;
TRACE_EXIT();
return;
}
/********************************************************************
* Function: tape_parse
*
* Argument:
*
* Returns : The state of the command
*
* Description: This does the parsing of the command
*
* Note: Not all states are allowed on return
********************************************************************/
int tape_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb)
{
int res = SCST_CMD_STATE_DEFAULT;
struct tape_params *tape;
TRACE_ENTRY();
/*
* SCST sets good defaults for cmd->data_direction and cmd->bufflen
* based on info_cdb, therefore change them only if necessary
*/
if (info_cdb->flags & SCST_SMALL_TIMEOUT) {
cmd->timeout = TAPE_SMALL_TIMEOUT;
} else if (info_cdb->flags & SCST_LONG_TIMEOUT) {
cmd->timeout = TAPE_LONG_TIMEOUT;
} else {
cmd->timeout = TAPE_REG_TIMEOUT;
}
TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d",
info_cdb->op_name,
info_cdb->direction, info_cdb->flags, info_cdb->transfer_len);
if (cmd->cdb[0] == READ_POSITION) {
int tclp = cmd->cdb[1] & TCLP_BIT;
int long_bit = cmd->cdb[1] & LONG_BIT;
int bt = cmd->cdb[1] & BT_BIT;
if ((tclp == long_bit) && (!bt || !long_bit)) {
cmd->bufflen =
tclp ? POSITION_LEN_LONG : POSITION_LEN_SHORT;
cmd->data_direction = SCST_DATA_READ;
} else {
cmd->bufflen = 0;
cmd->data_direction = SCST_DATA_NONE;
}
}
if (info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED & cmd->cdb[1]) {
/*
* No need for locks here, since *_detach() can not be called,
* when there are existing commands.
*/
tape = (struct tape_params *)cmd->dev->tgt_dev_specific;
cmd->bufflen = info_cdb->transfer_len * tape->block_size;
}
TRACE_EXIT_RES(res);
return res;
}
/********************************************************************
* Function: tape_done
*
* Argument:
*
* Returns :
*
* Description: This is the completion routine for the command,
* it is used to extract any necessary information
* about a command.
********************************************************************/
int tape_done(struct scst_cmd *cmd)
{
int opcode = cmd->cdb[0];
int masked_status = cmd->masked_status;
struct tape_params *tape;
int res = SCST_CMD_STATE_DEFAULT;
TRACE_ENTRY();
if (unlikely(cmd->sg == NULL))
goto out;
/*
* SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len
* based on cmd->masked_status and cmd->data_direction, therefore change
* them only if necessary
*/
if ((masked_status == GOOD) || (masked_status == CONDITION_GOOD)) {
int buffer_size;
uint8_t *buffer = NULL;
switch (opcode) {
case MODE_SENSE:
case MODE_SELECT:
buffer_size = scst_get_buf_first(cmd, &buffer);
if (unlikely(buffer_size <= 0)) {
PRINT_ERROR_PR("%s: Unable to get the buffer",
__FUNCTION__);
scst_set_busy(cmd);
goto out;
}
break;
}
switch (opcode) {
case MODE_SENSE:
TRACE_DBG("%s", "MODE_SENSE");
if ((cmd->cdb[2] & 0xC0) == 0) {
/*
* No need for locks here, since *_detach()
* can not be called, when there are
* existing commands.
*/
tape = (struct tape_params *)cmd->dev->tgt_dev_specific;
spin_lock_bh(&tape->tp_lock);
if (buffer[3] == 8) {
tape->block_size = (buffer[9] << 16) |
(buffer[10] << 8) | buffer[11];
}
tape->medium_type = buffer[1];
tape->mode = (buffer[2] & 0x70) >> 4;
tape->speed = buffer[2] & 0x0f;
tape->density = buffer[4];
spin_unlock_bh(&tape->tp_lock);
}
break;
case MODE_SELECT:
TRACE_DBG("%s", "MODE_SELECT");
/*
* No need for locks here, since *_detach() can not be
* called, when there are existing commands.
*/
tape = (struct tape_params *)cmd->dev->tgt_dev_specific;
spin_lock_bh(&tape->tp_lock);
if (buffer[3] == 8) {
tape->block_size =
(buffer[9] << 16) | (buffer[10] << 8) |
(buffer[11]);
}
tape->medium_type = buffer[1];
tape->mode = (buffer[2] & 0x70) >> 4;
tape->speed = buffer[2] & 0x0f;
if (buffer[4] != 0x7f)
tape->density = buffer[4];
spin_unlock_bh(&tape->tp_lock);
break;
default:
/* It's all good */
break;
}
switch (opcode) {
case MODE_SENSE:
case MODE_SELECT:
scst_put_buf(cmd, buffer);
break;
}
}
else if ((masked_status == CHECK_CONDITION) &&
SCST_SENSE_VALID(cmd->sense_buffer))
{
TRACE_DBG("%s", "Extended sense");
if (opcode == READ_6 && !(cmd->cdb[1] & SILI_BIT) &&
(cmd->sense_buffer[2] & 0xe0)) { /* EOF, EOM, or ILI */
int TransferLength, Residue = 0;
if ((cmd->sense_buffer[2] & 0x0f) == BLANK_CHECK) {
cmd->sense_buffer[2] &= 0xcf; /* No need for EOM in this case */
}
TransferLength = ((cmd->cdb[2] << 16) |
(cmd->cdb[3] << 8) | cmd->cdb[4]);
/* Compute the residual count */
if ((cmd->sense_buffer[0] & 0x80) != 0) {
Residue = ((cmd->sense_buffer[3] << 24) |
(cmd->sense_buffer[4] << 16) |
(cmd->sense_buffer[5] << 8) |
cmd->sense_buffer[6]);
}
TRACE_DBG("Checking the sense key "
"sn[2]=%x cmd->cdb[0,1]=%x,%x TransLen/Resid %d/%d",
(int) cmd->sense_buffer[2],
cmd->cdb[0], cmd->cdb[1], TransferLength,
Residue);
if (TransferLength > Residue) {
int resp_data_len = TransferLength - Residue;
if (cmd->cdb[1] & SCST_TRANSFER_LEN_TYPE_FIXED) {
/*
* No need for locks here, since
* *_detach() can not be called, when
* there are existing commands.
*/
tape = (struct tape_params *)cmd->dev->tgt_dev_specific;
resp_data_len *= tape->block_size;
}
scst_set_resp_data_len(cmd, resp_data_len);
}
}
}
TRACE_DBG("cmd->tgt_resp_flags=%x, cmd->resp_data_len=%d, "
"res=%d", cmd->tgt_resp_flags, cmd->resp_data_len, res);
out:
TRACE_EXIT_RES(res);
return res;
}
/********************************************************************
* Function: tape_exec
*
* Argument:
*
* Returns :
*
* Description: Make SCST do nothing for data READs and WRITES.
* Intended for raw line performance testing
********************************************************************/
int tape_exec(struct scst_cmd *cmd)
{
int res = SCST_EXEC_NOT_COMPLETED;
int opcode = cmd->cdb[0];
TRACE_ENTRY();
switch (opcode) {
case WRITE_6:
case READ_6:
res = SCST_EXEC_COMPLETED;
cmd->status = 0;
cmd->masked_status = 0;
cmd->msg_status = 0;
cmd->host_status = DID_OK;
cmd->driver_status = 0;
cmd->completed = 1;
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT);
break;
}
TRACE_EXIT_RES(res);
return res;
}
MODULE_LICENSE("GPL");
+1228
View File
File diff suppressed because it is too large Load Diff
+506
View File
@@ -0,0 +1,506 @@
/*
* scst_cdbprobe.h
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* 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, version 2
* of the License.
*
* 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.
*/
/* Must be included in only one .c file in the project!! */
#ifndef __SCST_CDBPROBE_H
#define __SCST_CDBPROBE_H
#define SCST_BLOCK_LIMIT_LEN 6
/*
+=====================================-============-======-
| Command name | Operation | Type |
| | code | |
|-------------------------------------+------------+------+
+=========================================================+
|Key: M = command implementation is mandatory. |
| O = command implementation is optional. |
| V = Vendor-specific |
| R = Reserved |
| ' '= DON'T use for this device |
+=========================================================+
*/
#define SCST_CDB_MANDATORY 'M' /* mandatory */
#define SCST_CDB_OPTIONAL 'O' /* optional */
#define SCST_CDB_VENDOR 'V' /* vendor */
#define SCST_CDB_RESERVED 'R' /* reserved */
#define SCST_CDB_NOTSUPP ' ' /* don't use */
struct scst_sdbops
{
uint8_t ops; /* SCSI-2 op codes */
uint8_t devkey[16]; /* Key for every device type M,O,V,R
* type_disk devkey[0]
* type_tape devkey[1]
* type_printer devkey[2]
* type_proseccor devkey[3]
* type_worm devkey[4]
* type_cdrom devkey[5]
* type_scanner devkey[6]
* type_mod devkey[7]
* type_changer devkey[8]
* type_commdev devkey[9]
* type_reserv devkey[A]
* type_reserv devkey[B]
* type_raid devkey[C]
* type_enclosure devkey[D]
* type_reserv devkey[E]
* type_reserv devkey[F]
*/
const char *op_name; /* SCSI-2 op codes full name */
uint8_t direction; /* init --> target: SCST_DATA_WRITE
* target --> init: SCST_DATA_READ
*/
uint8_t size_field_len; /* how many bytes using for data */
uint8_t fixed; /* opcode -- have fixed variable bit ??? */
uint8_t flag1; /* Note 1 */
uint8_t flag2;
};
static int scst_scsi_op_list[256];
static const struct scst_sdbops scst_scsi_op_table[] = {
/*
* +-------------------> TYPE_IS_DISK (0)
* |
* |+------------------> TYPE_IS_TAPE (1)
* ||
* || +----------------> TYPE_IS_PROCESSOR (3)
* || |
* || | +--------------> TYPE_IS_CDROM (5)
* || | |
* || | | +------------> TYPE_IS_MOD (7)
* || | | |
* || | | |+-----------> TYPE_IS_CHANGER (8)
* || | | ||
* || | | || +-------> TYPE_IS_RAID (C)
* || | | || |
* || | | || |
* 0123456789ABCDEF ---> TYPE_IS_???? */
{0x00, "MMMMMMMMMMMMMMMM", "TEST UNIT READY",
SCST_DATA_NONE, 0, SCST_SMALL_TIMEOUT, 0, 0},
{0x01, " M ", "REWIND",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0},
{0x01, "O V OO OO ", "REZERO UNIT",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x02, "VVVVVV V ", "REQUEST BLOCK ADDR",
SCST_DATA_NONE, 0, SCST_SMALL_TIMEOUT, 0, 0},
{0x03, "MMMMMMMMMMMMMMMM", "REQUEST SENSE",
SCST_DATA_READ, 1, SCST_SMALL_TIMEOUT, 0, 0},
{0x04, "M O O ", "FORMAT UNIT",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0}, /*-*/
{0x04, " O ", "FORMAT",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x05, "VMVVVV V ", "READ BLOCK LIMITS",
SCST_DATA_READ, 1, SCST_SMALL_TIMEOUT, 0, 0},
{0x06, "VVVVVV V ", "",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x07, " O ", "INITIALIZE ELEMENT STATUS",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0},
{0x07, "OVV O OV ", "REASSIGN BLOCKS",
SCST_DATA_NONE, 0, 0, 0, 0}, /*-*/
{0x08, "O ", "READ(6)",
SCST_DATA_READ, 1, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0},
{0x08, " MV OO OV ", "READ(6)",
SCST_DATA_READ, 3, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0},
{0x08, " M ", "GET MESSAGE(6)",
SCST_DATA_READ, 3, 0, 0, 0},
{0x08, " O ", "RECEIVE",
SCST_DATA_READ, 3, 0, 0, 0},
{0x09, "VVVVVV V ", "",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x0A, "O ", "WRITE(6)",
SCST_DATA_WRITE, 1, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0},
{0x0A, " M O OV ", "WRITE(6)",
SCST_DATA_WRITE, 3, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0},
{0x0A, " M ", "PRINT",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x0A, " M ", "SEND MESSAGE(6)",
SCST_DATA_WRITE, 3, 0, 0, 0},
{0x0A, " M ", "SEND(6)",
SCST_DATA_WRITE, 3, 0, 0, 0},
{0x0B, "O OO OV ", "SEEK(6)",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x0B, " ", "TRACK SELECT",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x0B, " O ", "SLEW AND PRINT",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x0C, "VVVVVV V ", "SEEK BLOCK",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0},
{0x0D, "VVVVVV V ", "PARTITION",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0},
{0x0E, "VVVVVV V ", "",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x0F, "VOVVVV V ", "READ REVERSE",
SCST_DATA_READ, 3, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0},
{0x10, "VM V V ", "WRITE FILEMARKS",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x10, " O O ", "SYNCHRONIZE BUFFER",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x11, "VMVVVV ", "SPACE",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0},
{0x12, "MMMMMMMMMMMMMMMM", "INQUIRY",
SCST_DATA_READ, 1, SCST_SMALL_TIMEOUT, 0, 0},
{0x13, "VOVVVV ", "VERIFY(6)",
SCST_DATA_WRITE, 3, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0},
{0x14, "VOOVVV ", "RECOVER BUFFERED DATA",
SCST_DATA_READ, 3, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0},
{0x15, "OMOOOOOOOOOOOOOO", "MODE SELECT(6)",
SCST_DATA_WRITE, 1, 0, 0, 0}, /*N6! */
{0x16, "MMMMMMMMMMMMMMMM", "RESERVE",
SCST_DATA_NONE, 0, SCST_SMALL_TIMEOUT, 0, 0},
{0x17, "MMMMMMMMMMMMMMMM", "RELEASE",
SCST_DATA_NONE, 0, SCST_SMALL_TIMEOUT, 0, 0},
{0x18, "OOOOOOOO ", "COPY",
SCST_DATA_WRITE, 1, SCST_LONG_TIMEOUT, 0, 0}, /*N5! */
{0x19, "VMVVVV ", "ERASE",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0},
{0x1A, "OMOOOOOOOOOOOOOO", "MODE SENSE(6)",
SCST_DATA_READ, 1, SCST_SMALL_TIMEOUT, 0, 0},
{0x1B, " O ", "SCAN",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x1B, " O ", "LOAD UNLOAD",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0},
{0x1B, " O ", "STOP PRINT",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x1B, "O OO O O ", "STOP START UNIT",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0},
{0x1C, "OOOOOOOOOOOOOOOO", "RECEIVE DIAGNOSTIC RESULTS",
SCST_DATA_READ, 1, 0, 0, 0},
{0x1D, "MMMMMMMMMMMMMMMM", "SEND DIAGNOSTIC",
SCST_DATA_WRITE, 1, 0, 0, 0},
{0x1E, "OOOOOOOOOOOOOOOO", "PREVENT ALLOW MEDIUM REMOVAL",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0},
{0x1F, " O ", "PORT STATUS",
SCST_DATA_NONE, 0, 0, 0, 0},
/* 10-bytes length CDB */
{0x20, "V VV V ", "",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x21, "V VV V ", "",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x22, "V VV V ", "",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x23, "V VV V ", "READ FORMAT CAPACITY",
SCST_DATA_READ, 2, 0, 0, 0},
{0x24, "V VVM ", "SET WINDOW",
SCST_DATA_WRITE, 3, 0, 0, 0}, /*-*/
{0x25, "M MM M ", "READ CAPACITY",
SCST_DATA_READ, 0, 0, 0, 0},
{0x25, " O ", "GET WINDOW",
SCST_DATA_READ, 3, 0, 0, 0},
{0x26, "V VV ", "",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x27, "V VV ", "",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x28, "M MMMM ", "READ(10)",
SCST_DATA_READ, 2, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0},
{0x28, " O ", "GET MESSAGE(10)",
SCST_DATA_READ, 2, 0, 0, 0},
{0x29, "V VV O ", "READ GENERATION",
SCST_DATA_READ, 1, 0, 0, 0},
{0x2A, "O MO M ", "WRITE(10)",
SCST_DATA_WRITE, 2, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0},
{0x2A, " O ", "SEND MESSAGE(10)",
SCST_DATA_WRITE, 2, 0, 0, 0},
{0x2A, " O ", "SEND(10)",
SCST_DATA_WRITE, 2, 0, 0, 0},
{0x2B, " O ", "LOCATE",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0},
{0x2B, " O ", "POSITION TO ELEMENT",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0},
{0x2B, "O OO O ", "SEEK(10)",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x2C, "V O O ", "ERASE(10)",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0},
{0x2D, "V O O ", "READ UPDATED BLOCK",
SCST_DATA_READ, 1, 0, 0, 0}, /*N2! */
{0x2E, "O OO O ", "WRITE AND VERIFY(10)",
SCST_DATA_WRITE, 2, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0},
{0x2F, "O OO O ", "VERIFY(10)",
SCST_DATA_WRITE, 2, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0},
/*-*/
{0x30, "O OO O ", "SEARCH DATA HIGH(10)",
SCST_DATA_NONE, 0, SCST_UNKNOWN_LENGTH, 1, 0}, /*-*/
{0x31, " O ", "OBJECT POSITION",
SCST_DATA_NONE, 0, SCST_UNKNOWN_LENGTH, 1, 0}, /*N1! */
{0x31, "O OO O ", "SEARCH DATA EQUAL(10)",
SCST_DATA_NONE, 0, SCST_UNKNOWN_LENGTH, 1, 0}, /*-*/
{0x32, "O OO O ", "SEARCH DATA LOW(10)",
SCST_DATA_NONE, 0, SCST_UNKNOWN_LENGTH, 1, 0}, /*-*/
{0x33, "O OO O ", "SET LIMITS(10)",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x34, " O ", "READ POSITION",
SCST_DATA_READ, 1, SCST_SMALL_TIMEOUT, 0, 0}, /*N4! */
{0x34, " O ", "GET DATA BUFFER STATUS",
SCST_DATA_READ, 2, 0, 0, 0},
{0x34, "O OO O ", "PRE-FETCH",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x35, "O OO O ", "SYNCHRONIZE CACHE",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x36, "O OO O ", "LOCK UNLOCK CACHE",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x37, "O O ", "READ DEFECT DATA(10)",
SCST_DATA_READ, 1, 0, 0, 0},
{0x38, " O O ", "MEDIUM SCAN",
SCST_DATA_READ, 1, 0, 0, 0}, /*-*/
{0x39, "OOOOOOOO ", "COMPARE",
SCST_DATA_WRITE, 1, 0, 0, 0}, /*N3! */
{0x3A, "OOOOOOOO ", "COPY AND VERIFY",
SCST_DATA_WRITE, 1, 0, 0, 0}, /*N3!? */
{0x3B, "OOOOOOOOOOOOOOOO", "WRITE BUFFER",
SCST_DATA_WRITE, 3, SCST_SMALL_TIMEOUT, 0, 0},
{0x3C, "OOOOOOOOOOOOOOOO", "READ BUFFER",
SCST_DATA_READ, 3, SCST_SMALL_TIMEOUT, 0, 0},
{0x3D, " O O ", "UPDATE BLOCK",
SCST_DATA_WRITE, 1, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0}, /*N2! */
{0x3E, "O OO O ", "READ LONG",
SCST_DATA_READ, 1, 0, 0, 0}, /*N6! */
{0x3F, "O O O ", "WRITE LONG",
SCST_DATA_WRITE, 1, 0, 0, 0}, /*N6! */
{0x40, "OOOOOOOOOO ", "CHANGE DEFINITION",
SCST_DATA_WRITE, 1, SCST_SMALL_TIMEOUT, 0, 0},
{0x41, "O O ", "WRITE SAME",
SCST_DATA_WRITE, 0, SCST_UNKNOWN_LENGTH, 1, 0}, /*N2! */
{0x42, " O ", "READ SUB-CHANNEL",
SCST_DATA_READ, 2, 0, 0, 0},
{0x43, " O ", "READ TOC/PMA/ATIP",
SCST_DATA_READ, 2, 0, 0, 0},
{0x44, " O ", "READ HEADER",
SCST_DATA_READ, 2, 0, 0, 0},
{0x45, " O ", "PLAY AUDIO(10)",
SCST_DATA_READ, 2, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0}, /*N8! */
{0x46, " O ", "GET CONFIGURATION",
SCST_DATA_READ, 2, 0, 0, 0},
{0x47, " O ", "PLAY AUDIO MSF",
SCST_DATA_READ, 0, SCST_UNKNOWN_LENGTH, 1, 0}, /*? */
{0x48, " O ", "PLAY AUDIO TRACK INDEX",
SCST_DATA_READ, 0, SCST_UNKNOWN_LENGTH, 1, 0}, /*? */
{0x49, " O ", "PLAY TRACK RELATIVE(10)",
SCST_DATA_READ, 2, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0}, /*N8! */
{0x4A, " O ", "GET EVENT STATUS NOTIFICATION",
SCST_DATA_READ, 2, 0, 0, 0},
{0x4B, " O ", "PAUSE/RESUME",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x4C, "OOOOOOOOOOOOOOOO", "LOG SELECT",
SCST_DATA_WRITE, 2, SCST_SMALL_TIMEOUT, 0, 0}, /*N6! */
{0x4D, "OOOOOOOOOOOOOOOO", "LOG SENSE",
SCST_DATA_READ, 2, SCST_SMALL_TIMEOUT, 0, 0}, /*N6! */
{0x4E, " O ", "STOP PLAY/SCAN",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x4F, " ", "",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x50, " ", "XDWRITE",
SCST_DATA_NONE, 0, 0, 0, 0}, /*-*/
{0x51, " O ", "READ DISC INFORMATION",
SCST_DATA_READ, 2, 0, 0, 0},
{0x51, " ", "XPWRITE",
SCST_DATA_NONE, 0, 0, 0, 0}, /*-*/
{0x52, " O ", "READ TRACK INFORMATION",
SCST_DATA_READ, 2, 0, 0, 0},
{0x53, " O ", "RESERVE TRACK",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x54, " O ", "SEND OPC INFORMATION",
SCST_DATA_WRITE, 2, 0, 0, 0},
{0x55, "OOOOOOOOOOOOOOOO", "MODE SELECT(10)",
SCST_DATA_WRITE, 2, 0, 0, 0},
{0x56, "OOOOOOOOOOOOOOOO", "RESERVE(10)",
SCST_DATA_NONE, 0, SCST_SMALL_TIMEOUT, 0, 0},
{0x57, "OOOOOOOOOOOOOOOO", "RELEASE(10)",
SCST_DATA_NONE, 0, SCST_SMALL_TIMEOUT, 0, 0},
{0x58, " O ", "REPAIR TRACK",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x59, " ", "",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x5A, "OOOOOOOOOOOOOOOO", "MODE SENSE(10)",
SCST_DATA_READ, 2, SCST_SMALL_TIMEOUT, 0, 0},
{0x5B, " O ", "CLOSE TRACK/SESSION",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x5C, " O ", "READ BUFFER CAPACITY",
SCST_DATA_READ, 2, 0, 0, 0},
{0x5D, " O ", "SEND CUE SHEET",
SCST_DATA_WRITE, 3, 0, 0, 0},
{0x5E, " ", "PERSISTENT_RESERV_IN",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x5F, " ", "PERSISTENT_RESERV_OUT",
SCST_DATA_NONE, 0, 0, 0, 0},
/* 16-bytes length CDB */
{0x80, "O OO O ", "XDWRITE EXTENDED",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x80, " M ", "WRITE FILEMARKS",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x81, "O OO O ", "REBUILD",
SCST_DATA_WRITE, 4, 0, 0, 0},
{0x82, "O OO O ", "REGENERATE",
SCST_DATA_WRITE, 4, 0, 0, 0},
{0x83, "OOOOOOOOOOOOOOOO", "EXTENDED COPY",
SCST_DATA_WRITE, 4, 0, 0, 0},
{0x84, "OOOOOOOOOOOOOOOO", "RECEIVE COPY RESULT",
SCST_DATA_WRITE, 4, 0, 0, 0},
{0x86, "OOOOOOOOOO ", "ACCESS CONTROL IN",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x87, "OOOOOOOOOO ", "ACCESS CONTROL OUT",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x88, "M MMMM ", "READ(16)",
SCST_DATA_READ, 4, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0},
{0x8A, "O OO O ", "WRITE(16)",
SCST_DATA_WRITE, 4, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0},
{0x8C, "OOOOOOOOOO ", "READ ATTRIBUTE",
SCST_DATA_READ, 4, 0, 0, 0},
{0x8D, "OOOOOOOOOO ", "WRITE ATTRIBUTE",
SCST_DATA_WRITE, 4, 0, 0, 0},
{0x8E, "O OO O ", "WRITE AND VERIFY(16)",
SCST_DATA_WRITE, 4, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0},
/*-*/
{0x8F, "O OO O ", "VERIFY(16)",
SCST_DATA_WRITE, 4, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0}, /*? */
{0x90, "O OO O ", "PRE-FETCH(16)",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x91, "O OO O ", "SYNCHRONIZE CACHE(16)",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x91, " M ", "SPACE(16)",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0},
{0x92, "O OO O ", "LOCK UNLOCK CACHE(16)",
SCST_DATA_NONE, 0, 0, 0, 0},
{0x92, " O ", "LOCATE(16)",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0},
{0x93, "O O ", "WRITE SAME(16)",
SCST_DATA_WRITE, 4, SCST_UNKNOWN_LENGTH, 1, 0}, /*N2! */
{0x93, " M ", "ERASE(16)",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0},
/* 12-bytes length CDB */
{0xA0, "VVVVVVVVVV M ", "REPORT LUN",
SCST_DATA_READ, 4, SCST_SMALL_TIMEOUT, 0, 0}, /*N7! */
{0xA1, " O ", "BLANK",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0},
{0xA2, " ", "",
SCST_DATA_NONE, 0, 0, 0, 0},
{0xA3, " O ", "SEND KEY",
SCST_DATA_WRITE, 2, 0, 0, 0},
{0xA3, "OOOOO OOOO ", "REPORT DEVICE IDENTIDIER",
SCST_DATA_READ, 4, 0, 0, 0},
{0xA3, " M ", "MAINTENANCE(IN)",
SCST_DATA_READ, 4, 0, 0, 0},
{0xA4, " O ", "REPORT KEY",
SCST_DATA_READ, 2, 0, 0, 0},
{0xA4, " O ", "MAINTENANCE(OUT)",
SCST_DATA_WRITE, 4, 0, 0, 0},
{0xA5, " M ", "MOVE MEDIUM",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0},
{0xA5, " O ", "PLAY AUDIO(12)",
SCST_DATA_READ, 4, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0}, /*N8! */
{0xA6, " O O ", "EXCHANGE/LOAD/UNLOAD MEDIUM",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0},
{0xA7, " O ", "SET READ AHEAD",
SCST_DATA_NONE, 0, 0, 0, 0},
{0xA8, " O ", "GET MESSAGE(12)",
SCST_DATA_READ, 4, 0, 0, 0},
{0xA8, "O OO O ", "READ(12)",
SCST_DATA_READ, 4, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0},
{0xA9, " O ", "PLAY TRACK RELATIVE(12)",
SCST_DATA_READ, 4, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0}, /*N8*! */
{0xAA, "O OO O ", "WRITE(12)",
SCST_DATA_WRITE, 4, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0},
{0xAA, " O ", "SEND MESSAGE(12)",
SCST_DATA_WRITE, 4, 0, 0, 0},
{0xAB, " ", "",
SCST_DATA_NONE, 0, 0, 0, 0},
{0xAC, " O ", "ERASE(12)",
SCST_DATA_NONE, 0, 0, 0, 0},
{0xAC, " O ", "GET PERFORMANCE",
SCST_DATA_READ, 0, SCST_UNKNOWN_LENGTH, 1, 0},
{0xAD, " O ", "READ DVD STRUCTURE",
SCST_DATA_READ, 2, 0, 0, 0},
{0xAE, "O OO O ", "WRITE AND VERIFY(12)",
SCST_DATA_WRITE, 4, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0},
/*-*/
{0xAF, "O OO O ", "VERIFY(12)",
SCST_DATA_WRITE, 4, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0}, /*? */
{0xB0, " OO O ", "SEARCH DATA HIGH(12)",
SCST_DATA_WRITE, 1, 0, 0, 0}, /*N9! */
{0xB1, " OO O ", "SEARCH DATA EQUAL(12)",
SCST_DATA_WRITE, 1, 0, 0, 0}, /*N9! */
{0xB2, " OO O ", "SEARCH DATA LOW(12)",
SCST_DATA_WRITE, 1, 0, 0, 0}, /*N9! */
{0xB3, " OO O ", "SET LIMITS(12)",
SCST_DATA_NONE, 0, 0, 0, 0},
{0xB4, " ", "",
SCST_DATA_NONE, 0, 0, 0, 0},
{0xB5, " O ", "REQUEST VOLUME ELEMENT ADDRESS",
SCST_DATA_READ, 1, 0, 0, 0},
{0xB6, " O ", "SEND VOLUME TAG",
SCST_DATA_WRITE, 1, 0, 0, 0},
{0xB6, " O ", "SET STREAMING",
SCST_DATA_WRITE, 0, 0, 0, 0},
{0xB7, " O ", "READ DEFECT DATA(12)",
SCST_DATA_READ, 1, 0, 0, 0},
{0xB8, " O ", "READ ELEMENT STATUS",
SCST_DATA_READ, 3, 0, 0, 0}, /*N10 */
{0xB9, " O ", "READ CD MSF",
SCST_DATA_READ, 0, SCST_UNKNOWN_LENGTH, 1, 0},
{0xBA, " O ", "SCAN",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0},
{0xBA, " O ", "REDUNDANCY GROUP(IN)",
SCST_DATA_READ, 4, 0, 0, 0},
{0xBB, " O ", "SET SPEED",
SCST_DATA_NONE, 0, 0, 0, 0},
{0xBB, " O ", "REDUNDANCY GROUP(OUT)",
SCST_DATA_WRITE, 4, 0, 0, 0},
{0xBC, " O ", "SPARE(IN)",
SCST_DATA_READ, 4, 0, 0, 0},
{0xBD, " O ", "MECHANISM STATUS",
SCST_DATA_READ, 2, 0, 0, 0},
{0xBD, " O ", "SPARE(OUT)",
SCST_DATA_WRITE, 4, 0, 0, 0},
{0xBE, " O ", "READ CD",
SCST_DATA_READ, 4, SCST_TRANSFER_LEN_TYPE_FIXED, 0, 0},
{0xBE, " O ", "VOLUME SET(IN)",
SCST_DATA_READ, 4, 0, 0, 0},
{0xBF, " O ", "SEND DVD STRUCTUE",
SCST_DATA_WRITE, 2, 0, 0, 0},
{0xBF, " O ", "VOLUME SET(OUT)",
SCST_DATA_WRITE, 4, 0, 0, 0},
{0xE7, " V ", "INIT ELEMENT STATUS WRANGE",
SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0}
};
/* Notes:
N1. - Unknown data len
N2. - Read/Write 1 block data
N3. - SCSI-2 1 byte len, SCSI-3 may be upto 3 bytes AND other location
N4. - Answer 20-bytes block.
N5. - CDB get param list len
N6. - len is bytes only
N7. - SCSI-3 Report Lun?
N8. - fixed length audio mode blocks for CD/DVD use MODE SENSE
N9. - 14-BYTES header + (n * patterns) full length variable
N10. - SCSI-2 use 1byte, mt.c (SCSI-3)? use 3 bytes
Unknown op's:
#define SCSIOP_XDWRITE_EXTENDED 0x80
#define SCSIOP_REBUILD 0x81
#define SCSIOP_EA 0xea
#define WRITE_LONG_2 0xea
*/
#define SCST_CDB_TBL_SIZE ((sizeof(scst_scsi_op_table)/sizeof(struct scst_sdbops)))
#endif /* __SCST_CDBPROBE_H */
+2351
View File
File diff suppressed because it is too large Load Diff
+565
View File
@@ -0,0 +1,565 @@
/*
* scst_sgv_pool.c
*
* Copyright (C) 2006 Vladislav Bolkhovitin <vst@vlnb.net>
*
* 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, version 2
* of the License.
*
* 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.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/unistd.h>
#include <asm/string.h>
#ifdef SCST_HIGHMEM
#include <linux/highmem.h>
#endif
#include "scsi_tgt.h"
#include "scst_debug.h"
#include "scst_priv.h"
#include "scst_mem.h"
/*
* This implementation of sgv_pool is not the best, because the SLABs could get
* fragmented and too much undesirable memory could be kept, plus
* under memory pressure the cached objects could be purged too quickly.
* From other side it's simple, works well, and doesn't require any modifications
* of the existing SLAB code.
*/
atomic_t sgv_big_total_alloc;
static int scst_check_clustering(struct scatterlist *sg, int cur, int hint)
{
int res = -1;
int i = hint;
unsigned long pfn_cur = page_to_pfn(sg[cur].page);
int len_cur = sg[cur].length;
unsigned long pfn_cur_next = pfn_cur + (len_cur >> PAGE_SHIFT);
int full_page_cur = (len_cur & (PAGE_SIZE - 1)) == 0;
unsigned long pfn, pfn_next, full_page;
#ifdef SCST_HIGHMEM
if (page >= highmem_start_page) {
TRACE_MEM("%s", "HIGHMEM page allocated, no clustering")
goto out;
}
#endif
#if 0
TRACE_MEM("pfn_cur %ld, pfn_cur_next %ld, len_cur %d, full_page_cur %d",
pfn_cur, pfn_cur_next, len_cur, full_page_cur);
#endif
/* check the hint first */
if (i >= 0) {
pfn = page_to_pfn(sg[i].page);
pfn_next = pfn + (sg[i].length >> PAGE_SHIFT);
full_page = (sg[i].length & (PAGE_SIZE - 1)) == 0;
if ((pfn == pfn_cur_next) && full_page_cur)
goto out_head;
if ((pfn_next == pfn_cur) && full_page)
goto out_tail;
}
/* ToDo: implement more intelligent search */
for (i = cur - 1; i >= 0; i--) {
pfn = page_to_pfn(sg[i].page);
pfn_next = pfn + (sg[i].length >> PAGE_SHIFT);
full_page = (sg[i].length & (PAGE_SIZE - 1)) == 0;
if ((pfn == pfn_cur_next) && full_page_cur)
goto out_head;
if ((pfn_next == pfn_cur) && full_page)
goto out_tail;
}
out:
return res;
out_tail:
TRACE_MEM("SG segment %d will be tail merged with segment %d", cur, i);
sg[i].length += len_cur;
memset(&sg[cur], 0, sizeof(sg[cur]));
res = i;
goto out;
out_head:
TRACE_MEM("SG segment %d will be head merged with segment %d", cur, i);
sg[i].page = sg[cur].page;
sg[i].length += len_cur;
memset(&sg[cur], 0, sizeof(sg[cur]));
res = i;
goto out;
}
static void sgv_free_sg(struct sgv_pool_obj *obj)
{
int i;
TRACE_MEM("obj=%p, sg_count=%d", obj, obj->sg_count);
for (i = 0; i < obj->sg_count; i++) {
struct page *p = obj->entries[i].page;
int len = obj->entries[i].length;
int pages =
(len >> PAGE_SHIFT) + ((len & ~PAGE_MASK) != 0);
TRACE_MEM("page %lx, len %d, pages %d",
(unsigned long)p, len, pages);
while (pages > 0) {
int order = 0;
/*
* __free_pages() doesn't like freeing pages with not that order with
* which they were allocated, so disable this small optimization.
*/
#if 0
if (len > 0) {
while(((1 << order) << PAGE_SHIFT) < len)
order++;
len = 0;
}
#endif
TRACE_MEM("free_pages(): order %d, page %lx",
order, (unsigned long)p);
__free_pages(p, order);
pages -= 1 << order;
p += 1 << order;
}
}
obj->sg_count = 0;
}
static int sgv_alloc_sg(struct sgv_pool_obj *obj, int pages,
unsigned long mask, int clustered)
{
int res = 0;
int pg, i, j;
int merged = -1;
TRACE_MEM("pages=%d, clustered=%d", pages, clustered);
#if 0
mask |= __GFP_COLD;
#endif
#ifdef SCST_STRICT_SECURITY
mask |= __GFP_ZERO;
#endif
obj->sg_count = 0;
for (pg = 0; pg < pages; pg++) {
#ifdef DEBUG_OOM
if (((scst_random() % 100) == 55))
obj->entries[obj->sg_count].page = NULL;
else
#endif
obj->entries[obj->sg_count].page = alloc_pages(mask, 0);
if (obj->entries[obj->sg_count].page == NULL) {
TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of "
"sgv_pool_obj page failed");
res = -ENOMEM;
goto out_free;
}
obj->entries[obj->sg_count].length = PAGE_SIZE;
if (clustered) {
merged = scst_check_clustering(obj->entries,
obj->sg_count, merged);
if (merged == -1)
obj->sg_count++;
} else
obj->sg_count++;
TRACE_MEM("pg=%d, merged=%d, sg_count=%d", pg, merged,
obj->sg_count);
}
if (clustered) {
pg = 0;
for (i = 0; i < pages; i++) {
int n = obj->entries[i].length >> PAGE_SHIFT;
obj->trans_tbl[i].pg_count = pg;
for (j = 0; j < n; j++)
obj->trans_tbl[pg++].sg_num = i+1;
}
}
out:
TRACE_MEM("res=%d, sg_count=%d", res, obj->sg_count);
return res;
out_free:
sgv_free_sg(obj);
goto out;
}
struct sgv_pool_obj *sgv_pool_alloc_big(int size, int pages,
unsigned long mask, int *count, int clustered)
{
struct sgv_pool_obj *obj;
int elen, cnt = 0;
elen = sizeof(*obj) + pages * (sizeof(obj->entries[0]) +
clustered ? sizeof(obj->trans_tbl[0]) : 0);
obj = kzalloc(elen, mask & ~(__GFP_HIGHMEM|GFP_DMA));
if (obj == NULL) {
TRACE(TRACE_OUT_OF_MEM, "Allocation big of sgv_pool_obj "
"failed (elen=%d, size=%d)", elen, size);
goto out;
}
obj->entries = (struct scatterlist*)&obj->trans_tbl[pages];
atomic_inc(&sgv_big_total_alloc);
if (sgv_alloc_sg(obj, pages, mask, clustered) != 0)
goto out_free;
cnt = obj->sg_count;
if (size & ~PAGE_MASK) {
obj->entries[cnt-1].length -=
PAGE_SIZE - (size & ~PAGE_MASK);
}
*count = cnt;
out:
TRACE_MEM("obj=%p (count=%d)", obj, cnt);
return obj;
out_free:
kfree(obj);
obj = NULL;
goto out;
}
void __sgv_pool_free_big(struct sgv_pool_obj *obj)
{
TRACE_MEM("obj=%p", obj);
sgv_free_sg(obj);
kfree(obj);
}
struct sgv_pool_obj *sgv_pool_alloc(struct sgv_pool *pool, int size,
unsigned long mask, int *count)
{
struct sgv_pool_obj *obj;
int order, pages, cnt, sg;
if (unlikely(size == 0))
return NULL;
pages = (size >> PAGE_SHIFT) + ((size & ~PAGE_MASK) != 0);
order = get_order(size);
TRACE_MEM("size=%d, pages=%d, order=%d", size, pages, order);
if (order >= SGV_POOL_ELEMENTS) {
obj = NULL;
if (mask & GFP_ATOMIC)
goto out;
obj = sgv_pool_alloc_big(size, pages, mask, count,
pool->clustered);
goto out;
}
obj = kmem_cache_alloc(pool->caches[order],
mask & ~(__GFP_HIGHMEM|GFP_DMA));
if (obj == NULL) {
if (!(mask & GFP_ATOMIC)) {
TRACE(TRACE_OUT_OF_MEM, "Allocation of sgv_pool_obj "
"failed (size %d)", size);
}
goto out;
}
if (obj->owner_cache != pool->caches[order]) {
int esz, epg, eorder;
if (mask & GFP_ATOMIC)
goto out_free;
esz = (1 << order) * sizeof(obj->entries[0]);
epg = (esz >> PAGE_SHIFT) + ((esz & ~PAGE_MASK) != 0);
eorder = get_order(esz);
TRACE_MEM("Brand new sgv_obj %p (esz=%d, epg=%d, eorder=%d)",
obj, esz, epg, eorder);
obj->eorder = eorder;
obj->entries = (struct scatterlist*)__get_free_pages(
mask|__GFP_ZERO, eorder);
if (obj->entries == NULL) {
TRACE(TRACE_OUT_OF_MEM, "Allocation of sgv_pool_obj "
"SG vector order %d failed", eorder);
goto out_free;
}
if (sgv_alloc_sg(obj, (1 << order), mask,
pool->clustered) != 0)
goto out_free_entries;
obj->owner_cache = pool->caches[order];
} else {
TRACE_MEM("Cached sgv_obj %p", obj);
atomic_inc(&pool->acc.hit_alloc);
atomic_inc(&pool->cache_acc[order].hit_alloc);
}
atomic_inc(&pool->acc.total_alloc);
atomic_inc(&pool->cache_acc[order].total_alloc);
if (pool->clustered)
cnt = obj->trans_tbl[pages-1].sg_num;
else
cnt = pages;
sg = cnt-1;
obj->orig_sg = sg;
obj->orig_length = obj->entries[sg].length;
if (pool->clustered) {
obj->entries[sg].length =
(pages - obj->trans_tbl[sg].pg_count) << PAGE_SHIFT;
}
if (size & ~PAGE_MASK) {
obj->entries[sg].length -= PAGE_SIZE - (size & ~PAGE_MASK);
}
*count = cnt;
TRACE_MEM("sgv_obj=%p (size=%d, pages=%d, "
"sg_count=%d, count=%d, last_len=%d)", obj, size, pages,
obj->sg_count, *count, obj->entries[obj->orig_sg].length);
out:
return obj;
out_free_entries:
free_pages((unsigned long)obj->entries, obj->eorder);
obj->entries = NULL;
out_free:
kmem_cache_free(pool->caches[order], obj);
obj = NULL;
goto out;
}
static void sgv_ctor(void *data, kmem_cache_t *c, unsigned long flags)
{
struct sgv_pool_obj *obj = data;
if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) !=
SLAB_CTOR_CONSTRUCTOR)
return;
TRACE_MEM("Constructor for sgv_obj %p", obj);
memset(obj, 0, sizeof(*obj));
}
static void __sgv_dtor(void *data, int pages)
{
struct sgv_pool_obj *obj = data;
TRACE_MEM("Destructor for sgv_obj %p", obj);
if (obj->entries) {
sgv_free_sg(obj);
free_pages((unsigned long)obj->entries, obj->eorder);
}
}
#define SGV_DTOR_NAME(order) sgv_dtor##order
#define SGV_DTOR(order) static void sgv_dtor##order(void *d, kmem_cache_t *k, \
unsigned long f) { __sgv_dtor(d, 1 << order); }
SGV_DTOR(0);
SGV_DTOR(1);
SGV_DTOR(2);
SGV_DTOR(3);
SGV_DTOR(4);
SGV_DTOR(5);
SGV_DTOR(6);
SGV_DTOR(7);
SGV_DTOR(8);
SGV_DTOR(9);
SGV_DTOR(10);
typedef void (*dtor_t)(void *, kmem_cache_t *, unsigned long);
dtor_t cache_dtors[SGV_POOL_ELEMENTS] =
{ SGV_DTOR_NAME(0), SGV_DTOR_NAME(1), SGV_DTOR_NAME(2), SGV_DTOR_NAME(3),
SGV_DTOR_NAME(4), SGV_DTOR_NAME(5), SGV_DTOR_NAME(6), SGV_DTOR_NAME(7),
SGV_DTOR_NAME(8), SGV_DTOR_NAME(9), SGV_DTOR_NAME(10) };
int sgv_pool_init(struct sgv_pool *pool, const char *name, int clustered)
{
int res = -ENOMEM;
int i;
struct sgv_pool_obj *obj;
TRACE_ENTRY();
memset(pool, 0, sizeof(*pool));
pool->clustered = clustered;
TRACE_MEM("sizeof(*obj)=%d, clustered=%d, sizeof(obj->trans_tbl[0])=%d",
sizeof(*obj), clustered, sizeof(obj->trans_tbl[0]));
for(i = 0; i < SGV_POOL_ELEMENTS; i++) {
int size, pages;
atomic_set(&pool->cache_acc[i].total_alloc, 0);
atomic_set(&pool->cache_acc[i].hit_alloc, 0);
pages = 1 << i;
size = sizeof(*obj) + pages *
(clustered ? sizeof(obj->trans_tbl[0]) : 0);
TRACE_MEM("pages=%d, size=%d", pages, size);
scnprintf(pool->cache_names[i], sizeof(pool->cache_names[i]),
"%s-%luK", name, (PAGE_SIZE >> 10) << i);
pool->caches[i] = kmem_cache_create(pool->cache_names[i],
size, 0, SCST_SLAB_FLAGS, sgv_ctor, cache_dtors[i]);
if (pool->caches[i] == NULL) {
TRACE(TRACE_OUT_OF_MEM, "Allocation of sgv_pool cache "
"%s(%d) failed", name, i);
goto out_free;
}
}
res = 0;
out:
TRACE_EXIT_RES(res);
return res;
out_free:
for(i = 0; i < SGV_POOL_ELEMENTS; i++) {
if (pool->caches[i]) {
kmem_cache_destroy(pool->caches[i]);
pool->caches[i] = NULL;
} else
break;
}
goto out;
}
void sgv_pool_deinit(struct sgv_pool *pool)
{
int i;
TRACE_ENTRY();
for(i = 0; i < SGV_POOL_ELEMENTS; i++) {
if (pool->caches[i])
kmem_cache_destroy(pool->caches[i]);
pool->caches[i] = NULL;
}
TRACE_EXIT();
}
struct sgv_pool *sgv_pool_create(const char *name, int clustered)
{
struct sgv_pool *pool;
int rc;
TRACE_ENTRY();
pool = kmalloc(sizeof(*pool), GFP_KERNEL);
if (pool == NULL) {
TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of sgv_pool failed");
goto out;
}
rc = sgv_pool_init(pool, name, clustered);
if (rc != 0)
goto out_free;
out:
TRACE_EXIT_RES(pool != NULL);
return pool;
out_free:
kfree(pool);
pool = NULL;
goto out;
}
void sgv_pool_destroy(struct sgv_pool *pool)
{
TRACE_ENTRY();
sgv_pool_deinit(pool);
kfree(pool);
TRACE_EXIT();
}
int scst_sgv_pools_init(struct scst_sgv_pools *pools)
{
int res;
TRACE_ENTRY();
atomic_set(&sgv_big_total_alloc, 0);
res = sgv_pool_init(&pools->norm, "sgv", 0);
if (res != 0)
goto out_free_clust;
res = sgv_pool_init(&pools->norm_clust, "sgv-clust", 1);
if (res != 0)
goto out;
res = sgv_pool_init(&pools->dma, "sgv-dma", 0);
if (res != 0)
goto out_free_norm;
#ifdef SCST_HIGHMEM
res = sgv_pool_init(&pools->highmem, "sgv-high", 0);
if (res != 0)
goto out_free_dma;
#endif
out:
TRACE_EXIT_RES(res);
return res;
#ifdef SCST_HIGHMEM
out_free_dma:
sgv_pool_deinit(&pools->dma);
#endif
out_free_norm:
sgv_pool_deinit(&pools->norm);
out_free_clust:
sgv_pool_deinit(&pools->norm_clust);
goto out;
}
void scst_sgv_pools_deinit(struct scst_sgv_pools *pools)
{
TRACE_ENTRY();
#ifdef SCST_HIGHMEM
sgv_pool_deinit(&pools->highmem);
#endif
sgv_pool_deinit(&pools->dma);
sgv_pool_deinit(&pools->norm);
sgv_pool_deinit(&pools->norm_clust);
TRACE_EXIT();
return;
}
+102
View File
@@ -0,0 +1,102 @@
/*
* scst_sgv_pool.h
*
* Copyright (C) 2006 Vladislav Bolkhovitin <vst@vlnb.net>
*
* 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, version 2
* of the License.
*
* 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.
*/
#include <asm/scatterlist.h>
#define SGV_POOL_ELEMENTS 11
#if defined(DEBUG) && defined(CONFIG_DEBUG_SLAB)
#define SCST_SLAB_FLAGS ( SLAB_RED_ZONE | SLAB_POISON )
#else
#define SCST_SLAB_FLAGS 0L
#endif
/*
* sg_num is indexed by the page number, pg_count is indexed by the sg number.
* Made in one entry to simplify the code (eg all sizeof(*) parts) and save
* the CPU cache for non-clustered case.
*/
struct trans_tbl_ent {
unsigned short sg_num;
unsigned short pg_count;
};
struct sgv_pool_obj
{
kmem_cache_t *owner_cache;
int eorder;
int orig_sg;
int orig_length;
int sg_count;
struct scatterlist *entries;
struct trans_tbl_ent trans_tbl[0];
};
struct sgv_pool_acc
{
atomic_t total_alloc, hit_alloc;
};
struct sgv_pool
{
struct sgv_pool_acc acc;
struct sgv_pool_acc cache_acc[SGV_POOL_ELEMENTS];
unsigned int clustered:1;
/* 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048 */
kmem_cache_t *caches[SGV_POOL_ELEMENTS];
char cache_names[SGV_POOL_ELEMENTS][25];
};
struct scst_sgv_pools
{
struct sgv_pool norm_clust, norm;
struct sgv_pool dma;
#ifdef SCST_HIGHMEM
struct sgv_pool highmem;
#endif
};
extern atomic_t sgv_big_total_alloc;
extern struct sgv_pool *sgv_pool_create(const char *name, int clustered);
extern void sgv_pool_destroy(struct sgv_pool *pool);
extern int sgv_pool_init(struct sgv_pool *pool, const char *name,
int clustered);
extern void sgv_pool_deinit(struct sgv_pool *pool);
extern struct sgv_pool_obj *sgv_pool_alloc(struct sgv_pool *pool, int size,
unsigned long flags, int *count);
extern void __sgv_pool_free_big(struct sgv_pool_obj *obj);
static inline void sgv_pool_free(struct sgv_pool_obj *obj)
{
TRACE_MEM("Freeing sgv_obj %p", obj);
if (obj->owner_cache != NULL) {
obj->entries[obj->orig_sg].length = obj->orig_length;
kmem_cache_free(obj->owner_cache, obj);
}
else
__sgv_pool_free_big(obj);
}
static inline struct scatterlist *sgv_pool_sg(struct sgv_pool_obj *obj)
{
return obj->entries;
}
extern int scst_sgv_pools_init(struct scst_sgv_pools *pools);
extern void scst_sgv_pools_deinit(struct scst_sgv_pools *pools);
+68
View File
@@ -0,0 +1,68 @@
/*
* scst_module.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* Support for loading target modules. The usage is similar to scsi_module.c
*
* 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, version 2
* of the License.
*
* 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.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <scsi_tgt.h>
static int __init init_this_scst_driver(void)
{
int res;
TRACE_ENTRY();
res = scst_register_target_template(&driver_target_template);
TRACE_DBG("scst_register_target_template() returned %d", res);
if (res < 0)
goto out;
#ifdef SCST_REGISTER_INITIATOR_DRIVER
driver_template.module = THIS_MODULE;
scsi_register_module(MODULE_SCSI_HA, &driver_template);
TRACE_DBG("driver_template.present=%d",
driver_template.present);
if (driver_template.present == 0) {
res = -ENODEV;
MOD_DEC_USE_COUNT;
goto out;
}
#endif
out:
TRACE_EXIT_RES(res);
return res;
}
static void __exit exit_this_scst_driver(void)
{
TRACE_ENTRY();
#ifdef SCST_REGISTER_INITIATOR_DRIVER
scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
#endif
scst_unregister_target_template(&driver_target_template);
TRACE_EXIT();
return;
}
module_init(init_this_scst_driver);
module_exit(exit_this_scst_driver);
+464
View File
@@ -0,0 +1,464 @@
/*
* scst_priv.h
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* 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, version 2
* of the License.
*
* 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.
*/
#ifndef __SCST_PRIV_H
#define __SCST_PRIV_H
#include <linux/types.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_driver.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_request.h>
#include <scsi/scsi_host.h>
#define SCST_MAJOR 177
#define TRACE_RETRY 0x80000000
#define TRACE_SCSI_SERIALIZING 0x40000000
#define TRACE_SEND_TOP 0x20000000 /** top being the edge away from the interupt */
#define TRACE_RECV_TOP 0x01000000
#define TRACE_SEND_BOT 0x08000000 /** bottom being the edge toward the interupt */
#define TRACE_RECV_BOT 0x04000000
#define LOG_PREFIX "scst"
#ifdef DEBUG
/*#define SCST_DEFAULT_LOG_FLAGS (TRACE_ALL & ~TRACE_MEMORY & ~TRACE_BUFF \
& ~TRACE_FUNCTION)
#define SCST_DEFAULT_LOG_FLAGS (TRACE_ALL & ~TRACE_MEMORY & ~TRACE_BUFF & \
~TRACE_SCSI & ~TRACE_SCSI_SERIALIZING & ~TRACE_DEBUG)
*/
#define SCST_DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MINOR | TRACE_PID | \
TRACE_FUNCTION | TRACE_SPECIAL | TRACE_MGMT | TRACE_MGMT_DEBUG | \
TRACE_RETRY)
#else
# ifdef TRACING
#define SCST_DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MINOR | TRACE_PID | \
TRACE_SPECIAL)
# else
#define SCST_DEFAULT_LOG_FLAGS 0
# endif
#endif
/**
** Bits for scst_flags
**/
/* Set if new commands initialization should be suspended for a while */
#define SCST_FLAG_SUSPENDED 0
/*
* If set, SCST's threads exit immediately not performing any
* sessions' shutdown tasks, therefore at this point all the sessions
* must be already down.
*/
#define SCST_FLAG_SHUTDOWN 1
/* Set if a TM command is being performed */
#define SCST_FLAG_TM_ACTIVE 2
/**
** Return codes for cmd state process functions
**/
#define SCST_CMD_STATE_RES_CONT_SAME 0
#define SCST_CMD_STATE_RES_CONT_NEXT 1
#define SCST_CMD_STATE_RES_NEED_THREAD 2
#define SCST_CMD_STATE_RES_RESTART 3
/** Name of the "default" security group **/
#define SCST_DEFAULT_ACG_NAME "Default"
/**
** Maximum count of uncompleted commands that an initiator could
** queue on any device. Then it will take TASK QUEUE FULL status.
**/
#define SCST_MAX_DEVICE_COMMANDS 128
#define SCST_THREAD_FLAGS CLONE_KERNEL
#define SCST_TGT_RETRY_TIMEOUT (3/2*HZ)
static inline int scst_get_context(void) {
/* Be overinsured */
return (in_atomic() || in_interrupt()) ? SCST_CONTEXT_DIRECT_ATOMIC :
SCST_CONTEXT_DIRECT;
}
#define SCST_MGMT_CMD_CACHE_STRING "scst_mgmt_cmd"
extern kmem_cache_t *scst_mgmt_cachep;
extern mempool_t *scst_mgmt_mempool;
#define SCST_UA_CACHE_STRING "scst_ua"
extern kmem_cache_t *scst_ua_cachep;
extern mempool_t *scst_ua_mempool;
#define SCST_CMD_CACHE_STRING "scst_cmd"
extern kmem_cache_t *scst_cmd_cachep;
#define SCST_SESSION_CACHE_STRING "scst_session"
extern kmem_cache_t *scst_sess_cachep;
#define SCST_TGT_DEV_CACHE_STRING "scst_tgt_dev"
extern kmem_cache_t *scst_tgtd_cachep;
#define SCST_ACG_DEV_CACHE_STRING "scst_acg_dev"
extern kmem_cache_t *scst_acgd_cachep;
extern struct scst_sgv_pools scst_sgv;
extern int scst_num_cpus;
extern unsigned long scst_flags;
extern struct semaphore scst_mutex;
extern atomic_t scst_cmd_count;
extern spinlock_t scst_list_lock;
extern struct list_head scst_dev_wait_sess_list; /* protected by scst_list_lock */
extern struct list_head scst_template_list; /* protected by scst_mutex */
extern struct list_head scst_dev_list; /* protected by scst_mutex */
extern struct list_head scst_dev_type_list; /* protected by scst_mutex */
extern wait_queue_head_t scst_dev_cmd_waitQ;
extern struct list_head scst_acg_list;
extern struct scst_acg *scst_default_acg;
/* The following lists protected by scst_list_lock */
extern struct list_head scst_active_cmd_list;
extern struct list_head scst_init_cmd_list;
extern struct list_head scst_cmd_list;
extern struct list_head scst_mgmt_cmd_list;
extern struct list_head scst_active_mgmt_cmd_list;
extern struct list_head scst_delayed_mgmt_cmd_list;
extern struct tasklet_struct scst_tasklets[NR_CPUS];
extern wait_queue_head_t scst_list_waitQ;
extern wait_queue_head_t scst_mgmt_cmd_list_waitQ;
extern wait_queue_head_t scst_mgmt_waitQ;
extern spinlock_t scst_mgmt_lock;
extern struct list_head scst_sess_mgmt_list;
extern int scst_threads;
extern int scst_shut_threads_count;
extern atomic_t scst_threads_count;
extern int scst_thread_num;
extern struct semaphore *scst_shutdown_mutex;
extern spinlock_t scst_temp_UA_lock;
extern uint8_t scst_temp_UA[SCSI_SENSE_BUFFERSIZE];
extern struct scst_cmd *__scst_check_deferred_commands(
struct scst_tgt_dev *tgt_dev, int expected_sn);
/* Used to save the function call on th fast path */
static inline struct scst_cmd *scst_check_deferred_commands(
struct scst_tgt_dev *tgt_dev, int expected_sn)
{
if (tgt_dev->def_cmd_count == 0)
return NULL;
else
return __scst_check_deferred_commands(tgt_dev, expected_sn);
}
static inline int __scst_inc_expected_sn(struct scst_tgt_dev *tgt_dev)
{
/*
* No locks is needed, because only one thread at time can
* call it (serialized by sn). Also it is supposed that there
* could not be half-incremented halves.
*/
typeof(tgt_dev->expected_sn) e;
e = tgt_dev->expected_sn;
tgt_dev->expected_sn++;
smp_mb(); /* write must be before def_cmd_count read */
e++;
TRACE(TRACE_DEBUG/*TRACE_SCSI_SERIALIZING*/, "Next expected_sn: %d", e);
return e;
}
void scst_inc_expected_sn_unblock(struct scst_tgt_dev *tgt_dev,
struct scst_cmd *cmd_sn, int locked);
int scst_cmd_thread(void *arg);
void scst_cmd_tasklet(long p);
int scst_mgmt_cmd_thread(void *arg);
int scst_mgmt_thread(void *arg);
struct scst_device *scst_alloc_device(int gfp_mask);
void scst_free_device(struct scst_device *tgt_dev);
struct scst_acg *scst_alloc_add_acg(const char *acg_name);
int scst_destroy_acg(struct scst_acg *acg);
int scst_sess_alloc_tgt_devs(struct scst_session *sess);
void scst_sess_free_tgt_devs(struct scst_session *sess);
void scst_reset_tgt_dev(struct scst_tgt_dev *tgt_dev, int nexus_loss);
int scst_acg_add_dev(struct scst_acg *acg, struct scst_device *dev, lun_t lun,
int read_only);
int scst_acg_remove_dev(struct scst_acg *acg, struct scst_device *dev);
int scst_acg_add_name(struct scst_acg *acg, const char *name);
int scst_acg_remove_name(struct scst_acg *acg, const char *name);
int scst_assign_dev_handler(struct scst_device *dev,
struct scst_dev_type *handler);
struct scst_session *scst_alloc_session(struct scst_tgt *tgt, int gfp_mask,
const char *initiator_name);
void scst_free_session(struct scst_session *sess);
void scst_free_session_callback(struct scst_session *sess);
struct scst_cmd *scst_alloc_cmd(int gfp_mask);
void scst_free_cmd(struct scst_cmd *cmd);
static inline void scst_destroy_cmd(struct scst_cmd *cmd)
{
TRACE_MEM("kfree for cmd: %p", cmd);
kmem_cache_free(scst_cmd_cachep, cmd);
return;
}
void scst_check_retries(struct scst_tgt *tgt, int processible_env);
void scst_tgt_retry_timer_fn(unsigned long arg);
int scst_alloc_request(struct scst_cmd *cmd);
void scst_release_request(struct scst_cmd *cmd);
static inline void scst_do_req(struct scsi_request *sreq,
const void *cmnd, void *buffer, unsigned bufflen,
void (*done)(struct scsi_cmnd *), int timeout, int retries)
{
#ifdef STRICT_SERIALIZING
scsi_do_req(sreq, cmnd, buffer, bufflen, done, timeout, retries);
#else
scsi_do_req_fifo(sreq, cmnd, buffer, bufflen, done, timeout, retries);
#endif
}
int scst_alloc_space(struct scst_cmd *cmd);
void scst_release_space(struct scst_cmd *cmd);
void scst_scsi_op_list_init(void);
lun_t scst_unpack_lun(const uint8_t *lun, int len);
struct scst_cmd *__scst_find_cmd_by_tag(struct scst_session *sess,
uint32_t tag);
struct scst_mgmt_cmd *scst_alloc_mgmt_cmd(int gfp_mask);
void scst_free_mgmt_cmd(struct scst_mgmt_cmd *mcmd, int del);
/* /proc support */
int scst_proc_init_module(void);
void scst_proc_cleanup_module(void);
int scst_build_proc_target_dir_entries(struct scst_tgt_template *vtt);
void scst_cleanup_proc_target_dir_entries(struct scst_tgt_template *vtt);
int scst_build_proc_target_entries(struct scst_tgt *vtt);
void scst_cleanup_proc_target_entries(struct scst_tgt *vtt);
int scst_build_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type);
void scst_cleanup_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type);
int scst_get_cdb_len(const uint8_t *cdb);
void __scst_process_UA(struct scst_device *dev, struct scst_cmd *exclude,
const uint8_t *sense, int sense_len, int internal);
static inline void scst_process_UA(struct scst_device *dev,
struct scst_cmd *exclude, const uint8_t *sense, int sense_len,
int internal)
{
spin_lock_bh(&dev->dev_lock);
__scst_process_UA(dev, exclude, sense, sense_len, internal);
spin_unlock_bh(&dev->dev_lock);
return;
}
void scst_alloc_set_UA(struct scst_tgt_dev *tgt_dev, const uint8_t *sense,
int sense_len);
void scst_check_set_UA(struct scst_tgt_dev *tgt_dev,
const uint8_t *sense, int sense_len);
int scst_set_pending_UA(struct scst_cmd *cmd);
void scst_free_all_UA(struct scst_tgt_dev *tgt_dev);
void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
int other_ini, int call_dev_task_mgmt_fn);
void scst_process_reset(struct scst_device *dev,
struct scst_session *originator, struct scst_cmd *exclude_cmd,
struct scst_mgmt_cmd *mcmd);
static inline int scst_is_ua_command(struct scst_cmd *cmd)
{
return ((cmd->cdb[0] != INQUIRY) &&
(cmd->cdb[0] != REQUEST_SENSE) &&
(cmd->cdb[0] != REPORT_LUNS));
}
/*
* Returns 1, if cmd's CDB is locally handled by SCST and 0 otherwise.
* Dev handlers parse() and dev_done() not called for such commands.
*/
static inline int scst_is_cmd_local(struct scst_cmd *cmd)
{
int res = 0;
switch (cmd->cdb[0]) {
case REPORT_LUNS:
res = 1;
}
return res;
}
/*
* Some notes on devices "blocking". Blocking means that no
* commands will go from SCST to underlying SCSI device until it
* is unblocked. But we don't care about all commands that
* already on the device.
*/
extern int scst_inc_on_dev_cmd(struct scst_cmd *cmd);
extern void scst_unblock_cmds(struct scst_device *dev);
static inline void __scst_block_dev(struct scst_device *dev)
{
dev->block_count++;
smp_mb();
TRACE_MGMT_DBG("Device BLOCK(%d), dev %p", dev->block_count, dev);
}
static inline void scst_block_dev(struct scst_device *dev,
unsigned int outstanding)
{
spin_lock_bh(&dev->dev_lock);
__scst_block_dev(dev);
spin_unlock_bh(&dev->dev_lock);
TRACE_MGMT_DBG("%s", "Waiting during blocking");
wait_event(dev->on_dev_waitQ,
atomic_read(&dev->on_dev_count) <= outstanding);
TRACE_MGMT_DBG("%s", "wait_event() returned");
}
static inline void scst_unblock_dev(struct scst_device *dev)
{
spin_lock_bh(&dev->dev_lock);
TRACE_MGMT_DBG("Device UNBLOCK(%d), dev %p",
dev->block_count-1, dev);
if (--dev->block_count == 0)
scst_unblock_cmds(dev);
spin_unlock_bh(&dev->dev_lock);
}
static inline void scst_dec_on_dev_cmd(struct scst_cmd *cmd)
{
if (cmd->blocking) {
TRACE_MGMT_DBG("cmd %p (tag %d): unblocking dev %p", cmd,
cmd->tag, cmd->dev);
cmd->blocking = 0;
scst_unblock_dev(cmd->dev);
}
atomic_dec(&cmd->dev->on_dev_count);
smp_mb__after_atomic_dec();
if (unlikely(cmd->dev->block_count != 0))
wake_up_all(&cmd->dev->on_dev_waitQ);
}
static inline void scst_inc_cmd_count(void)
{
atomic_inc(&scst_cmd_count);
smp_mb__after_atomic_inc();
TRACE_DBG("Incrementing scst_cmd_count(%d)",
atomic_read(&scst_cmd_count));
}
static inline void scst_dec_cmd_count(void)
{
int f;
f = atomic_dec_and_test(&scst_cmd_count);
smp_mb__after_atomic_dec();
if (f && unlikely(test_bit(SCST_FLAG_SUSPENDED, &scst_flags)))
wake_up_all(&scst_dev_cmd_waitQ);
TRACE_DBG("Decrementing scst_cmd_count(%d)",
atomic_read(&scst_cmd_count));
}
void scst_sched_session_free(struct scst_session *sess);
static inline void scst_sess_get(struct scst_session *sess)
{
atomic_inc(&sess->refcnt);
}
static inline void scst_sess_put(struct scst_session *sess)
{
if (atomic_dec_and_test(&sess->refcnt))
scst_sched_session_free(sess);
}
void __scst_suspend_activity(void);
void __scst_resume_activity(void);
extern void scst_throttle_cmd(struct scst_cmd *cmd);
extern void scst_unthrottle_cmd(struct scst_cmd *cmd);
static inline void scst_set_sense(uint8_t *buffer, int len, int key,
int asc, int ascq)
{
memset(buffer, 0, len);
buffer[0] = 0x70; /* Error Code */
buffer[2] = key; /* Sense Key */
buffer[7] = 0x0a; /* Additional Sense Length */
buffer[12] = asc; /* ASC */
buffer[13] = ascq; /* ASCQ */
TRACE_BUFFER("Sense set", buffer, len);
return;
}
static inline void scst_check_restore_sg_buff(struct scst_cmd *cmd)
{
if (cmd->sg_buff_modified) {
cmd->sg[cmd->orig_sg_entry].length = cmd->orig_entry_len;
cmd->sg_cnt = cmd->orig_sg_cnt;
}
}
#ifdef DEBUG_TM
extern void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev,
struct scst_acg_dev *acg_dev);
extern void tm_dbg_deinit_tgt_dev(struct scst_tgt_dev *tgt_dev);
extern void tm_dbg_check_released_cmds(void);
extern int tm_dbg_check_cmd(struct scst_cmd *cmd);
extern void tm_dbg_release_cmd(struct scst_cmd *cmd);
extern void tm_dbg_task_mgmt(const char *fn);
extern int tm_dbg_is_release(void);
#else
static inline void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev,
struct scst_acg_dev *acg_dev) {}
static inline void tm_dbg_deinit_tgt_dev(struct scst_tgt_dev *tgt_dev) {}
static inline void tm_dbg_check_released_cmds(void) {}
static inline int tm_dbg_check_cmd(struct scst_cmd *cmd)
{
return 0;
}
static inline void tm_dbg_release_cmd(struct scst_cmd *cmd) {}
static inline void tm_dbg_task_mgmt(const char *fn) {}
static inline int tm_dbg_is_release(void)
{
return 0;
}
#endif /* DEBUG_TM */
#endif /* __SCST_PRIV_H */
+2249
View File
File diff suppressed because it is too large Load Diff
+3911
View File
File diff suppressed because it is too large Load Diff