提交 d54b3538 编写于 作者: L Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (119 commits)
  [SCSI] scsi_dh_rdac: Retry for NOT_READY check condition
  [SCSI] mpt2sas: make global symbols unique
  [SCSI] sd: Make revalidate less chatty
  [SCSI] sd: Try READ CAPACITY 16 first for SBC-2 devices
  [SCSI] sd: Refactor sd_read_capacity()
  [SCSI] mpt2sas v00.100.11.15
  [SCSI] mpt2sas: add MPT2SAS_MINOR(221) to miscdevice.h
  [SCSI] ch: Add scsi type modalias
  [SCSI] 3w-9xxx: add power management support
  [SCSI] bsg: add linux/types.h include to bsg.h
  [SCSI] cxgb3i: fix function descriptions
  [SCSI] libiscsi: fix possbile null ptr session command cleanup
  [SCSI] iscsi class: remove host no argument from session creation callout
  [SCSI] libiscsi: pass session failure a session struct
  [SCSI] iscsi lib: remove qdepth param from iscsi host allocation
  [SCSI] iscsi lib: have lib create work queue for transmitting IO
  [SCSI] iscsi class: fix lock dep warning on logout
  [SCSI] libiscsi: don't cap queue depth in iscsi modules
  [SCSI] iscsi_tcp: replace scsi_debug/tcp_debug logging with iscsi conn logging
  [SCSI] libiscsi_tcp: replace tcp_debug/scsi_debug logging with session/conn logging
  ...
......@@ -3145,6 +3145,12 @@ Your cooperation is appreciated.
1 = /dev/blockrom1 Second ROM card's translation layer interface
...
260 char OSD (Object-based-device) SCSI Device
0 = /dev/osd0 First OSD Device
1 = /dev/osd1 Second OSD Device
...
255 = /dev/osd255 256th OSD Device
**** ADDITIONAL /dev DIRECTORY ENTRIES
This section details additional entries that should or may exist in
......
The OSD Standard
================
OSD (Object-Based Storage Device) is a T10 SCSI command set that is designed
to provide efficient operation of input/output logical units that manage the
allocation, placement, and accessing of variable-size data-storage containers,
called objects. Objects are intended to contain operating system and application
constructs. Each object has associated attributes attached to it, which are
integral part of the object and provide metadata about the object. The standard
defines some common obligatory attributes, but user attributes can be added as
needed.
See: http://www.t10.org/ftp/t10/drafts/osd2/ for the latest draft for OSD 2
or search the web for "OSD SCSI"
OSD in the Linux Kernel
=======================
osd-initiator:
The main component of OSD in Kernel is the osd-initiator library. Its main
user is intended to be the pNFS-over-objects layout driver, which uses objects
as its back-end data storage. Other clients are the other osd parts listed below.
osd-uld:
This is a SCSI ULD that registers for OSD type devices and provides a testing
platform, both for the in-kernel initiator as well as connected targets. It
currently has no useful user-mode API, though it could have if need be.
exofs:
Is an OSD based Linux file system. It uses the osd-initiator and osd-uld,
to export a usable file system for users.
See Documentation/filesystems/exofs.txt for more details
osd target:
There are no current plans for an OSD target implementation in kernel. For all
needs, a user-mode target that is based on the scsi tgt target framework is
available from Ohio Supercomputer Center (OSC) at:
http://www.open-osd.org/bin/view/Main/OscOsdProject
There are several other target implementations. See http://open-osd.org for more
links.
Files and Folders
=================
This is the complete list of files included in this work:
include/scsi/
osd_initiator.h Main API for the initiator library
osd_types.h Common OSD types
osd_sec.h Security Manager API
osd_protocol.h Wire definitions of the OSD standard protocol
osd_attributes.h Wire definitions of OSD attributes
drivers/scsi/osd/
osd_initiator.c OSD-Initiator library implementation
osd_uld.c The OSD scsi ULD
osd_ktest.{h,c} In-kernel test suite (called by osd_uld)
osd_debug.h Some printk macros
Makefile For both in-tree and out-of-tree compilation
Kconfig Enables inclusion of the different pieces
osd_test.c User-mode application to call the kernel tests
The OSD-Initiator Library
=========================
osd_initiator is a low level implementation of an osd initiator encoder.
But even though, it should be intuitive and easy to use. Perhaps over time an
higher lever will form that automates some of the more common recipes.
init/fini:
- osd_dev_init() associates a scsi_device with an osd_dev structure
and initializes some global pools. This should be done once per scsi_device
(OSD LUN). The osd_dev structure is needed for calling osd_start_request().
- osd_dev_fini() cleans up before a osd_dev/scsi_device destruction.
OSD commands encoding, execution, and decoding of results:
struct osd_request's is used to iteratively encode an OSD command and carry
its state throughout execution. Each request goes through these stages:
a. osd_start_request() allocates the request.
b. Any of the osd_req_* methods is used to encode a request of the specified
type.
c. osd_req_add_{get,set}_attr_* may be called to add get/set attributes to the
CDB. "List" or "Page" mode can be used exclusively. The attribute-list API
can be called multiple times on the same request. However, only one
attribute-page can be read, as mandated by the OSD standard.
d. osd_finalize_request() computes offsets into the data-in and data-out buffers
and signs the request using the provided capability key and integrity-
check parameters.
e. osd_execute_request() may be called to execute the request via the block
layer and wait for its completion. The request can be executed
asynchronously by calling the block layer API directly.
f. After execution, osd_req_decode_sense() can be called to decode the request's
sense information.
g. osd_req_decode_get_attr() may be called to retrieve osd_add_get_attr_list()
values.
h. osd_end_request() must be called to deallocate the request and any resource
associated with it. Note that osd_end_request cleans up the request at any
stage and it must always be called after a successful osd_start_request().
osd_request's structure:
The OSD standard defines a complex structure of IO segments pointed to by
members in the CDB. Up to 3 segments can be deployed in the IN-Buffer and up to
4 in the OUT-Buffer. The ASCII illustration below depicts a secure-read with
associated get+set of attributes-lists. Other combinations very on the same
basic theme. From no-segments-used up to all-segments-used.
|________OSD-CDB__________|
| |
|read_len (offset=0) -|---------\
| | |
|get_attrs_list_length | |
|get_attrs_list_offset -|----\ |
| | | |
|retrieved_attrs_alloc_len| | |
|retrieved_attrs_offset -|----|----|-\
| | | | |
|set_attrs_list_length | | | |
|set_attrs_list_offset -|-\ | | |
| | | | | |
|in_data_integ_offset -|-|--|----|-|-\
|out_data_integ_offset -|-|--|--\ | | |
\_________________________/ | | | | | |
| | | | | |
|_______OUT-BUFFER________| | | | | | |
| Set attr list |</ | | | | |
| | | | | | |
|-------------------------| | | | | |
| Get attr descriptors |<---/ | | | |
| | | | | |
|-------------------------| | | | |
| Out-data integrity |<------/ | | |
| | | | |
\_________________________/ | | |
| | |
|________IN-BUFFER________| | | |
| In-Data read |<--------/ | |
| | | |
|-------------------------| | |
| Get attr list |<----------/ |
| | |
|-------------------------| |
| In-data integrity |<------------/
| |
\_________________________/
A block device request can carry bidirectional payload by means of associating
a bidi_read request with a main write-request. Each in/out request is described
by a chain of BIOs associated with each request.
The CDB is of a SCSI VARLEN CDB format, as described by OSD standard.
The OSD standard also mandates alignment restrictions at start of each segment.
In the code, in struct osd_request, there are two _osd_io_info structures to
describe the IN/OUT buffers above, two BIOs for the data payload and up to five
_osd_req_data_segment structures to hold the different segments allocation and
information.
Important: We have chosen to disregard the assumption that a BIO-chain (and
the resulting sg-list) describes a linear memory buffer. Meaning only first and
last scatter chain can be incomplete and all the middle chains are of PAGE_SIZE.
For us, a scatter-gather-list, as its name implies and as used by the Networking
layer, is to describe a vector of buffers that will be transferred to/from the
wire. It works very well with current iSCSI transport. iSCSI is currently the
only deployed OSD transport. In the future we anticipate SAS and FC attached OSD
devices as well.
The OSD Testing ULD
===================
TODO: More user-mode control on tests.
Authors, Mailing list
=====================
Please communicate with us on any deployment of osd, whether using this code
or not.
Any problems, questions, bug reports, lonely OSD nights, please email:
OSD Dev List <osd-dev@open-osd.org>
More up-to-date information can be found on:
http://open-osd.org
Boaz Harrosh <bharrosh@panasas.com>
Benny Halevy <bhalevy@panasas.com>
References
==========
Weber, R., "SCSI Object-Based Storage Device Commands",
T10/1355-D ANSI/INCITS 400-2004,
http://www.t10.org/ftp/t10/drafts/osd/osd-r10.pdf
Weber, R., "SCSI Object-Based Storage Device Commands -2 (OSD-2)"
T10/1729-D, Working Draft, rev. 3
http://www.t10.org/ftp/t10/drafts/osd2/osd2r03.pdf
......@@ -3310,6 +3310,16 @@ L: orinoco-devel@lists.sourceforge.net
W: http://www.nongnu.org/orinoco/
S: Maintained
OSD LIBRARY
P: Boaz Harrosh
M: bharrosh@panasas.com
P: Benny Halevy
M: bhalevy@panasas.com
L: osd-dev@open-osd.org
W: http://open-osd.org
T: git://git.open-osd.org/open-osd.git
S: Maintained
P54 WIRELESS DRIVER
P: Michael Wu
M: flamingice@sourmilk.net
......
......@@ -22,6 +22,7 @@
#include <linux/spinlock.h>
#include <linux/capability.h>
#include <linux/bitops.h>
#include <linux/blkdev.h>
#include <scsi/scsi.h>
#include <linux/cdrom.h>
......
......@@ -168,7 +168,7 @@ iscsi_iser_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task)
{
int error = 0;
debug_scsi("task deq [cid %d itt 0x%x]\n", conn->id, task->itt);
iser_dbg("task deq [cid %d itt 0x%x]\n", conn->id, task->itt);
error = iser_send_control(conn, task);
......@@ -195,7 +195,7 @@ iscsi_iser_task_xmit_unsol_data(struct iscsi_conn *conn,
/* Send data-out PDUs while there's still unsolicited data to send */
while (iscsi_task_has_unsol_data(task)) {
iscsi_prep_data_out_pdu(task, r2t, &hdr);
debug_scsi("Sending data-out: itt 0x%x, data count %d\n",
iser_dbg("Sending data-out: itt 0x%x, data count %d\n",
hdr.itt, r2t->data_count);
/* the buffer description has been passed with the command */
......@@ -206,7 +206,7 @@ iscsi_iser_task_xmit_unsol_data(struct iscsi_conn *conn,
goto iscsi_iser_task_xmit_unsol_data_exit;
}
r2t->sent += r2t->data_count;
debug_scsi("Need to send %d more as data-out PDUs\n",
iser_dbg("Need to send %d more as data-out PDUs\n",
r2t->data_length - r2t->sent);
}
......@@ -227,12 +227,12 @@ iscsi_iser_task_xmit(struct iscsi_task *task)
if (task->sc->sc_data_direction == DMA_TO_DEVICE) {
BUG_ON(scsi_bufflen(task->sc) == 0);
debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n",
iser_dbg("cmd [itt %x total %d imm %d unsol_data %d\n",
task->itt, scsi_bufflen(task->sc),
task->imm_count, task->unsol_r2t.data_length);
}
debug_scsi("task deq [cid %d itt 0x%x]\n",
iser_dbg("task deq [cid %d itt 0x%x]\n",
conn->id, task->itt);
/* Send the cmd PDU */
......@@ -397,14 +397,14 @@ static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session)
static struct iscsi_cls_session *
iscsi_iser_session_create(struct iscsi_endpoint *ep,
uint16_t cmds_max, uint16_t qdepth,
uint32_t initial_cmdsn, uint32_t *hostno)
uint32_t initial_cmdsn)
{
struct iscsi_cls_session *cls_session;
struct iscsi_session *session;
struct Scsi_Host *shost;
struct iser_conn *ib_conn;
shost = iscsi_host_alloc(&iscsi_iser_sht, 0, ISCSI_MAX_CMD_PER_LUN);
shost = iscsi_host_alloc(&iscsi_iser_sht, 0, 1);
if (!shost)
return NULL;
shost->transportt = iscsi_iser_scsi_transport;
......@@ -423,7 +423,6 @@ iscsi_iser_session_create(struct iscsi_endpoint *ep,
if (iscsi_host_add(shost,
ep ? ib_conn->device->ib_device->dma_device : NULL))
goto free_host;
*hostno = shost->host_no;
/*
* we do not support setting can_queue cmd_per_lun from userspace yet
......@@ -596,7 +595,7 @@ static struct scsi_host_template iscsi_iser_sht = {
.change_queue_depth = iscsi_change_queue_depth,
.sg_tablesize = ISCSI_ISER_SG_TABLESIZE,
.max_sectors = 1024,
.cmd_per_lun = ISCSI_MAX_CMD_PER_LUN,
.cmd_per_lun = ISER_DEF_CMD_PER_LUN,
.eh_abort_handler = iscsi_eh_abort,
.eh_device_reset_handler= iscsi_eh_device_reset,
.eh_target_reset_handler= iscsi_eh_target_reset,
......
......@@ -93,7 +93,7 @@
/* support upto 512KB in one RDMA */
#define ISCSI_ISER_SG_TABLESIZE (0x80000 >> SHIFT_4K)
#define ISCSI_ISER_MAX_LUN 256
#define ISER_DEF_CMD_PER_LUN 128
/* QP settings */
/* Maximal bounds on received asynchronous PDUs */
......
......@@ -661,7 +661,7 @@ void iser_snd_completion(struct iser_desc *tx_desc)
if (resume_tx) {
iser_dbg("%ld resuming tx\n",jiffies);
scsi_queue_work(conn->session->host, &conn->xmitwork);
iscsi_conn_queue_work(conn);
}
if (tx_desc->type == ISCSI_TX_CONTROL) {
......
......@@ -1511,7 +1511,7 @@ static int xennet_set_tso(struct net_device *dev, u32 data)
static void xennet_set_features(struct net_device *dev)
{
/* Turn off all GSO bits except ROBUST. */
dev->features &= (1 << NETIF_F_GSO_SHIFT) - 1;
dev->features &= ~NETIF_F_GSO_MASK;
dev->features |= NETIF_F_GSO_ROBUST;
xennet_set_sg(dev, 0);
......
......@@ -3,7 +3,7 @@
*
* Module interface and handling of zfcp data structures.
*
* Copyright IBM Corporation 2002, 2008
* Copyright IBM Corporation 2002, 2009
*/
/*
......@@ -249,8 +249,8 @@ struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter,
struct zfcp_port *port;
list_for_each_entry(port, &adapter->port_list_head, list)
if ((port->wwpn == wwpn) && !(atomic_read(&port->status) &
(ZFCP_STATUS_PORT_NO_WWPN | ZFCP_STATUS_COMMON_REMOVE)))
if ((port->wwpn == wwpn) &&
!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE))
return port;
return NULL;
}
......@@ -421,7 +421,8 @@ int zfcp_status_read_refill(struct zfcp_adapter *adapter)
while (atomic_read(&adapter->stat_miss) > 0)
if (zfcp_fsf_status_read(adapter)) {
if (atomic_read(&adapter->stat_miss) >= 16) {
zfcp_erp_adapter_reopen(adapter, 0, 103, NULL);
zfcp_erp_adapter_reopen(adapter, 0, "axsref1",
NULL);
return 1;
}
break;
......@@ -501,6 +502,7 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
spin_lock_init(&adapter->scsi_dbf_lock);
spin_lock_init(&adapter->rec_dbf_lock);
spin_lock_init(&adapter->req_q_lock);
spin_lock_init(&adapter->qdio_stat_lock);
rwlock_init(&adapter->erp_lock);
rwlock_init(&adapter->abort_lock);
......@@ -522,7 +524,6 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
goto sysfs_failed;
atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
zfcp_fc_nameserver_init(adapter);
if (!zfcp_adapter_scsi_register(adapter))
return 0;
......@@ -552,6 +553,7 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
cancel_work_sync(&adapter->scan_work);
cancel_work_sync(&adapter->stat_work);
cancel_delayed_work_sync(&adapter->nsp.work);
zfcp_adapter_scsi_unregister(adapter);
sysfs_remove_group(&adapter->ccw_device->dev.kobj,
&zfcp_sysfs_adapter_attrs);
......@@ -603,10 +605,13 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
init_waitqueue_head(&port->remove_wq);
INIT_LIST_HEAD(&port->unit_list_head);
INIT_WORK(&port->gid_pn_work, zfcp_erp_port_strategy_open_lookup);
INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work);
INIT_WORK(&port->rport_work, zfcp_scsi_rport_work);
port->adapter = adapter;
port->d_id = d_id;
port->wwpn = wwpn;
port->rport_task = RPORT_NONE;
/* mark port unusable as long as sysfs registration is not complete */
atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status);
......@@ -620,11 +625,10 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
dev_set_drvdata(&port->sysfs_device, port);
read_lock_irq(&zfcp_data.config_lock);
if (!(status & ZFCP_STATUS_PORT_NO_WWPN))
if (zfcp_get_port_by_wwpn(adapter, wwpn)) {
read_unlock_irq(&zfcp_data.config_lock);
goto err_out_free;
}
if (zfcp_get_port_by_wwpn(adapter, wwpn)) {
read_unlock_irq(&zfcp_data.config_lock);
goto err_out_free;
}
read_unlock_irq(&zfcp_data.config_lock);
if (device_register(&port->sysfs_device))
......
......@@ -3,7 +3,7 @@
*
* Registration and callback for the s390 common I/O layer.
*
* Copyright IBM Corporation 2002, 2008
* Copyright IBM Corporation 2002, 2009
*/
#define KMSG_COMPONENT "zfcp"
......@@ -72,8 +72,7 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
list_for_each_entry_safe(port, p, &port_remove_lh, list) {
list_for_each_entry_safe(unit, u, &unit_remove_lh, list) {
if (atomic_read(&unit->status) &
ZFCP_STATUS_UNIT_REGISTERED)
if (unit->device)
scsi_remove_device(unit->device);
zfcp_unit_dequeue(unit);
}
......@@ -109,11 +108,12 @@ static int zfcp_ccw_set_online(struct ccw_device *ccw_device)
/* initialize request counter */
BUG_ON(!zfcp_reqlist_isempty(adapter));
adapter->req_no = 0;
zfcp_fc_nameserver_init(adapter);
zfcp_erp_modify_adapter_status(adapter, 10, NULL,
zfcp_erp_modify_adapter_status(adapter, "ccsonl1", NULL,
ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 85,
NULL);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
"ccsonl2", NULL);
zfcp_erp_wait(adapter);
up(&zfcp_data.config_sema);
flush_work(&adapter->scan_work);
......@@ -137,7 +137,7 @@ static int zfcp_ccw_set_offline(struct ccw_device *ccw_device)
down(&zfcp_data.config_sema);
adapter = dev_get_drvdata(&ccw_device->dev);
zfcp_erp_adapter_shutdown(adapter, 0, 86, NULL);
zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL);
zfcp_erp_wait(adapter);
zfcp_erp_thread_kill(adapter);
up(&zfcp_data.config_sema);
......@@ -160,21 +160,21 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
case CIO_GONE:
dev_warn(&adapter->ccw_device->dev,
"The FCP device has been detached\n");
zfcp_erp_adapter_shutdown(adapter, 0, 87, NULL);
zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1", NULL);
break;
case CIO_NO_PATH:
dev_warn(&adapter->ccw_device->dev,
"The CHPID for the FCP device is offline\n");
zfcp_erp_adapter_shutdown(adapter, 0, 88, NULL);
zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2", NULL);
break;
case CIO_OPER:
dev_info(&adapter->ccw_device->dev,
"The FCP device is operational again\n");
zfcp_erp_modify_adapter_status(adapter, 11, NULL,
zfcp_erp_modify_adapter_status(adapter, "ccnoti3", NULL,
ZFCP_STATUS_COMMON_RUNNING,
ZFCP_SET);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
89, NULL);
"ccnoti4", NULL);
break;
}
return 1;
......@@ -190,7 +190,7 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev)
down(&zfcp_data.config_sema);
adapter = dev_get_drvdata(&cdev->dev);
zfcp_erp_adapter_shutdown(adapter, 0, 90, NULL);
zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL);
zfcp_erp_wait(adapter);
up(&zfcp_data.config_sema);
}
......
......@@ -490,172 +490,17 @@ static const char *zfcp_rec_dbf_tags[] = {
[ZFCP_REC_DBF_ID_ACTION] = "action",
};
static const char *zfcp_rec_dbf_ids[] = {
[1] = "new",
[2] = "ready",
[3] = "kill",
[4] = "down sleep",
[5] = "down wakeup",
[6] = "down sleep ecd",
[7] = "down wakeup ecd",
[8] = "down sleep epd",
[9] = "down wakeup epd",
[10] = "online",
[11] = "operational",
[12] = "scsi slave destroy",
[13] = "propagate failed adapter",
[14] = "propagate failed port",
[15] = "block adapter",
[16] = "unblock adapter",
[17] = "block port",
[18] = "unblock port",
[19] = "block unit",
[20] = "unblock unit",
[21] = "unit recovery failed",
[22] = "port recovery failed",
[23] = "adapter recovery failed",
[24] = "qdio queues down",
[25] = "p2p failed",
[26] = "nameserver lookup failed",
[27] = "nameserver port failed",
[28] = "link up",
[29] = "link down",
[30] = "link up status read",
[31] = "open port failed",
[32] = "",
[33] = "close port",
[34] = "open unit failed",
[35] = "exclusive open unit failed",
[36] = "shared open unit failed",
[37] = "link down",
[38] = "link down status read no link",
[39] = "link down status read fdisc login",
[40] = "link down status read firmware update",
[41] = "link down status read unknown reason",
[42] = "link down ecd incomplete",
[43] = "link down epd incomplete",
[44] = "sysfs adapter recovery",
[45] = "sysfs port recovery",
[46] = "sysfs unit recovery",
[47] = "port boxed abort",
[48] = "unit boxed abort",
[49] = "port boxed ct",
[50] = "port boxed close physical",
[51] = "port boxed open unit",
[52] = "port boxed close unit",
[53] = "port boxed fcp",
[54] = "unit boxed fcp",
[55] = "port access denied",
[56] = "",
[57] = "",
[58] = "",
[59] = "unit access denied",
[60] = "shared unit access denied open unit",
[61] = "",
[62] = "request timeout",
[63] = "adisc link test reject or timeout",
[64] = "adisc link test d_id changed",
[65] = "adisc link test failed",
[66] = "recovery out of memory",
[67] = "adapter recovery repeated after state change",
[68] = "port recovery repeated after state change",
[69] = "unit recovery repeated after state change",
[70] = "port recovery follow-up after successful adapter recovery",
[71] = "adapter recovery escalation after failed adapter recovery",
[72] = "port recovery follow-up after successful physical port "
"recovery",
[73] = "adapter recovery escalation after failed physical port "
"recovery",
[74] = "unit recovery follow-up after successful port recovery",
[75] = "physical port recovery escalation after failed port "
"recovery",
[76] = "port recovery escalation after failed unit recovery",
[77] = "",
[78] = "duplicate request id",
[79] = "link down",
[80] = "exclusive read-only unit access unsupported",
[81] = "shared read-write unit access unsupported",
[82] = "incoming rscn",
[83] = "incoming wwpn",
[84] = "wka port handle not valid close port",
[85] = "online",
[86] = "offline",
[87] = "ccw device gone",
[88] = "ccw device no path",
[89] = "ccw device operational",
[90] = "ccw device shutdown",
[91] = "sysfs port addition",
[92] = "sysfs port removal",
[93] = "sysfs adapter recovery",
[94] = "sysfs unit addition",
[95] = "sysfs unit removal",
[96] = "sysfs port recovery",
[97] = "sysfs unit recovery",
[98] = "sequence number mismatch",
[99] = "link up",
[100] = "error state",
[101] = "status read physical port closed",
[102] = "link up status read",
[103] = "too many failed status read buffers",
[104] = "port handle not valid abort",
[105] = "lun handle not valid abort",
[106] = "port handle not valid ct",
[107] = "port handle not valid close port",
[108] = "port handle not valid close physical port",
[109] = "port handle not valid open unit",
[110] = "port handle not valid close unit",
[111] = "lun handle not valid close unit",
[112] = "port handle not valid fcp",
[113] = "lun handle not valid fcp",
[114] = "handle mismatch fcp",
[115] = "lun not valid fcp",
[116] = "qdio send failed",
[117] = "version mismatch",
[118] = "incompatible qtcb type",
[119] = "unknown protocol status",
[120] = "unknown fsf command",
[121] = "no recommendation for status qualifier",
[122] = "status read physical port closed in error",
[123] = "fc service class not supported",
[124] = "",
[125] = "need newer zfcp",
[126] = "need newer microcode",
[127] = "arbitrated loop not supported",
[128] = "",
[129] = "qtcb size mismatch",
[130] = "unknown fsf status ecd",
[131] = "fcp request too big",
[132] = "",
[133] = "data direction not valid fcp",
[134] = "command length not valid fcp",
[135] = "status read act update",
[136] = "status read cfdc update",
[137] = "hbaapi port open",
[138] = "hbaapi unit open",
[139] = "hbaapi unit shutdown",
[140] = "qdio error outbound",
[141] = "scsi host reset",
[142] = "dismissing fsf request for recovery action",
[143] = "recovery action timed out",
[144] = "recovery action gone",
[145] = "recovery action being processed",
[146] = "recovery action ready for next step",
[147] = "qdio error inbound",
[148] = "nameserver needed for port scan",
[149] = "port scan",
[150] = "ptp attach",
[151] = "port validation failed",
};
static int zfcp_rec_dbf_view_format(debug_info_t *id, struct debug_view *view,
char *buf, const char *_rec)
{
struct zfcp_rec_dbf_record *r = (struct zfcp_rec_dbf_record *)_rec;
char *p = buf;
char hint[ZFCP_DBF_ID_SIZE + 1];
memcpy(hint, r->id2, ZFCP_DBF_ID_SIZE);
hint[ZFCP_DBF_ID_SIZE] = 0;
zfcp_dbf_outs(&p, "tag", zfcp_rec_dbf_tags[r->id]);
zfcp_dbf_outs(&p, "hint", zfcp_rec_dbf_ids[r->id2]);
zfcp_dbf_out(&p, "id", "%d", r->id2);
zfcp_dbf_outs(&p, "hint", hint);
switch (r->id) {
case ZFCP_REC_DBF_ID_THREAD:
zfcp_dbf_out(&p, "total", "%d", r->u.thread.total);
......@@ -707,7 +552,7 @@ static struct debug_view zfcp_rec_dbf_view = {
* @adapter: adapter
* This function assumes that the caller is holding erp_lock.
*/
void zfcp_rec_dbf_event_thread(u8 id2, struct zfcp_adapter *adapter)
void zfcp_rec_dbf_event_thread(char *id2, struct zfcp_adapter *adapter)
{
struct zfcp_rec_dbf_record *r = &adapter->rec_dbf_buf;
unsigned long flags = 0;
......@@ -723,7 +568,7 @@ void zfcp_rec_dbf_event_thread(u8 id2, struct zfcp_adapter *adapter)
spin_lock_irqsave(&adapter->rec_dbf_lock, flags);
memset(r, 0, sizeof(*r));
r->id = ZFCP_REC_DBF_ID_THREAD;
r->id2 = id2;
memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE);
r->u.thread.total = total;
r->u.thread.ready = ready;
r->u.thread.running = running;
......@@ -737,7 +582,7 @@ void zfcp_rec_dbf_event_thread(u8 id2, struct zfcp_adapter *adapter)
* @adapter: adapter
* This function assumes that the caller does not hold erp_lock.
*/
void zfcp_rec_dbf_event_thread_lock(u8 id2, struct zfcp_adapter *adapter)
void zfcp_rec_dbf_event_thread_lock(char *id2, struct zfcp_adapter *adapter)
{
unsigned long flags;
......@@ -746,7 +591,7 @@ void zfcp_rec_dbf_event_thread_lock(u8 id2, struct zfcp_adapter *adapter)
read_unlock_irqrestore(&adapter->erp_lock, flags);
}
static void zfcp_rec_dbf_event_target(u8 id2, void *ref,
static void zfcp_rec_dbf_event_target(char *id2, void *ref,
struct zfcp_adapter *adapter,
atomic_t *status, atomic_t *erp_count,
u64 wwpn, u32 d_id, u64 fcp_lun)
......@@ -757,7 +602,7 @@ static void zfcp_rec_dbf_event_target(u8 id2, void *ref,
spin_lock_irqsave(&adapter->rec_dbf_lock, flags);
memset(r, 0, sizeof(*r));
r->id = ZFCP_REC_DBF_ID_TARGET;
r->id2 = id2;
memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE);
r->u.target.ref = (unsigned long)ref;
r->u.target.status = atomic_read(status);
r->u.target.wwpn = wwpn;
......@@ -774,7 +619,8 @@ static void zfcp_rec_dbf_event_target(u8 id2, void *ref,
* @ref: additional reference (e.g. request)
* @adapter: adapter
*/
void zfcp_rec_dbf_event_adapter(u8 id, void *ref, struct zfcp_adapter *adapter)
void zfcp_rec_dbf_event_adapter(char *id, void *ref,
struct zfcp_adapter *adapter)
{
zfcp_rec_dbf_event_target(id, ref, adapter, &adapter->status,
&adapter->erp_counter, 0, 0, 0);
......@@ -786,7 +632,7 @@ void zfcp_rec_dbf_event_adapter(u8 id, void *ref, struct zfcp_adapter *adapter)
* @ref: additional reference (e.g. request)
* @port: port
*/
void zfcp_rec_dbf_event_port(u8 id, void *ref, struct zfcp_port *port)
void zfcp_rec_dbf_event_port(char *id, void *ref, struct zfcp_port *port)
{
struct zfcp_adapter *adapter = port->adapter;
......@@ -801,7 +647,7 @@ void zfcp_rec_dbf_event_port(u8 id, void *ref, struct zfcp_port *port)
* @ref: additional reference (e.g. request)
* @unit: unit
*/
void zfcp_rec_dbf_event_unit(u8 id, void *ref, struct zfcp_unit *unit)
void zfcp_rec_dbf_event_unit(char *id, void *ref, struct zfcp_unit *unit)
{
struct zfcp_port *port = unit->port;
struct zfcp_adapter *adapter = port->adapter;
......@@ -822,7 +668,7 @@ void zfcp_rec_dbf_event_unit(u8 id, void *ref, struct zfcp_unit *unit)
* @port: port
* @unit: unit
*/
void zfcp_rec_dbf_event_trigger(u8 id2, void *ref, u8 want, u8 need,
void zfcp_rec_dbf_event_trigger(char *id2, void *ref, u8 want, u8 need,
void *action, struct zfcp_adapter *adapter,
struct zfcp_port *port, struct zfcp_unit *unit)
{
......@@ -832,7 +678,7 @@ void zfcp_rec_dbf_event_trigger(u8 id2, void *ref, u8 want, u8 need,
spin_lock_irqsave(&adapter->rec_dbf_lock, flags);
memset(r, 0, sizeof(*r));
r->id = ZFCP_REC_DBF_ID_TRIGGER;
r->id2 = id2;
memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE);
r->u.trigger.ref = (unsigned long)ref;
r->u.trigger.want = want;
r->u.trigger.need = need;
......@@ -855,7 +701,7 @@ void zfcp_rec_dbf_event_trigger(u8 id2, void *ref, u8 want, u8 need,
* @id2: identifier
* @erp_action: error recovery action struct pointer
*/
void zfcp_rec_dbf_event_action(u8 id2, struct zfcp_erp_action *erp_action)
void zfcp_rec_dbf_event_action(char *id2, struct zfcp_erp_action *erp_action)
{
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_rec_dbf_record *r = &adapter->rec_dbf_buf;
......@@ -864,7 +710,7 @@ void zfcp_rec_dbf_event_action(u8 id2, struct zfcp_erp_action *erp_action)
spin_lock_irqsave(&adapter->rec_dbf_lock, flags);
memset(r, 0, sizeof(*r));
r->id = ZFCP_REC_DBF_ID_ACTION;
r->id2 = id2;
memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE);
r->u.action.action = (unsigned long)erp_action;
r->u.action.status = erp_action->status;
r->u.action.step = erp_action->step;
......
......@@ -25,6 +25,7 @@
#include "zfcp_fsf.h"
#define ZFCP_DBF_TAG_SIZE 4
#define ZFCP_DBF_ID_SIZE 7
struct zfcp_dbf_dump {
u8 tag[ZFCP_DBF_TAG_SIZE];
......@@ -70,7 +71,7 @@ struct zfcp_rec_dbf_record_action {
struct zfcp_rec_dbf_record {
u8 id;
u8 id2;
char id2[7];
union {
struct zfcp_rec_dbf_record_action action;
struct zfcp_rec_dbf_record_thread thread;
......
......@@ -3,7 +3,7 @@
*
* Global definitions for the zfcp device driver.
*
* Copyright IBM Corporation 2002, 2008
* Copyright IBM Corporation 2002, 2009
*/
#ifndef ZFCP_DEF_H
......@@ -243,9 +243,6 @@ struct zfcp_ls_adisc {
/* remote port status */
#define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001
#define ZFCP_STATUS_PORT_PHYS_CLOSING 0x00000004
#define ZFCP_STATUS_PORT_NO_WWPN 0x00000008
#define ZFCP_STATUS_PORT_INVALID_WWPN 0x00000020
/* well known address (WKA) port status*/
enum zfcp_wka_status {
......@@ -258,7 +255,6 @@ enum zfcp_wka_status {
/* logical unit status */
#define ZFCP_STATUS_UNIT_SHARED 0x00000004
#define ZFCP_STATUS_UNIT_READONLY 0x00000008
#define ZFCP_STATUS_UNIT_REGISTERED 0x00000010
#define ZFCP_STATUS_UNIT_SCSI_WORK_PENDING 0x00000020
/* FSF request status (this does not have a common part) */
......@@ -447,8 +443,9 @@ struct zfcp_adapter {
spinlock_t req_list_lock; /* request list lock */
struct zfcp_qdio_queue req_q; /* request queue */
spinlock_t req_q_lock; /* for operations on queue */
int req_q_pci_batch; /* SBALs since PCI indication
was last set */
ktime_t req_q_time; /* time of last fill level change */
u64 req_q_util; /* for accounting */
spinlock_t qdio_stat_lock;
u32 fsf_req_seq_no; /* FSF cmnd seq number */
wait_queue_head_t request_wq; /* can be used to wait for
more avaliable SBALs */
......@@ -514,6 +511,9 @@ struct zfcp_port {
u32 maxframe_size;
u32 supported_classes;
struct work_struct gid_pn_work;
struct work_struct test_link_work;
struct work_struct rport_work;
enum { RPORT_NONE, RPORT_ADD, RPORT_DEL } rport_task;
};
struct zfcp_unit {
......@@ -587,9 +587,6 @@ struct zfcp_fsf_req_qtcb {
/********************** ZFCP SPECIFIC DEFINES ********************************/
#define ZFCP_REQ_AUTO_CLEANUP 0x00000002
#define ZFCP_REQ_NO_QTCB 0x00000008
#define ZFCP_SET 0x00000100
#define ZFCP_CLEAR 0x00000200
......
此差异已折叠。
......@@ -3,7 +3,7 @@
*
* External function declarations.
*
* Copyright IBM Corporation 2002, 2008
* Copyright IBM Corporation 2002, 2009
*/
#ifndef ZFCP_EXT_H
......@@ -35,15 +35,15 @@ extern struct miscdevice zfcp_cfdc_misc;
/* zfcp_dbf.c */
extern int zfcp_adapter_debug_register(struct zfcp_adapter *);
extern void zfcp_adapter_debug_unregister(struct zfcp_adapter *);
extern void zfcp_rec_dbf_event_thread(u8, struct zfcp_adapter *);
extern void zfcp_rec_dbf_event_thread_lock(u8, struct zfcp_adapter *);
extern void zfcp_rec_dbf_event_adapter(u8, void *, struct zfcp_adapter *);
extern void zfcp_rec_dbf_event_port(u8, void *, struct zfcp_port *);
extern void zfcp_rec_dbf_event_unit(u8, void *, struct zfcp_unit *);
extern void zfcp_rec_dbf_event_trigger(u8, void *, u8, u8, void *,
extern void zfcp_rec_dbf_event_thread(char *, struct zfcp_adapter *);
extern void zfcp_rec_dbf_event_thread_lock(char *, struct zfcp_adapter *);
extern void zfcp_rec_dbf_event_adapter(char *, void *, struct zfcp_adapter *);
extern void zfcp_rec_dbf_event_port(char *, void *, struct zfcp_port *);
extern void zfcp_rec_dbf_event_unit(char *, void *, struct zfcp_unit *);
extern void zfcp_rec_dbf_event_trigger(char *, void *, u8, u8, void *,
struct zfcp_adapter *,
struct zfcp_port *, struct zfcp_unit *);
extern void zfcp_rec_dbf_event_action(u8, struct zfcp_erp_action *);
extern void zfcp_rec_dbf_event_action(char *, struct zfcp_erp_action *);
extern void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *);
extern void zfcp_hba_dbf_event_fsf_unsol(const char *, struct zfcp_adapter *,
struct fsf_status_read_buffer *);
......@@ -66,31 +66,34 @@ extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *,
struct scsi_cmnd *);
/* zfcp_erp.c */
extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, u8, void *,
u32, int);
extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, u8, void *);
extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, u8, void *);
extern void zfcp_erp_adapter_failed(struct zfcp_adapter *, u8, void *);
extern void zfcp_erp_modify_port_status(struct zfcp_port *, u8, void *, u32,
extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, char *,
void *, u32, int);
extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, char *, void *);
extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, char *,
void *);
extern void zfcp_erp_adapter_failed(struct zfcp_adapter *, char *, void *);
extern void zfcp_erp_modify_port_status(struct zfcp_port *, char *, void *, u32,
int);
extern int zfcp_erp_port_reopen(struct zfcp_port *, int, u8, void *);
extern void zfcp_erp_port_shutdown(struct zfcp_port *, int, u8, void *);
extern void zfcp_erp_port_forced_reopen(struct zfcp_port *, int, u8, void *);
extern void zfcp_erp_port_failed(struct zfcp_port *, u8, void *);
extern void zfcp_erp_modify_unit_status(struct zfcp_unit *, u8, void *, u32,
extern int zfcp_erp_port_reopen(struct zfcp_port *, int, char *, void *);
extern void zfcp_erp_port_shutdown(struct zfcp_port *, int, char *, void *);
extern void zfcp_erp_port_forced_reopen(struct zfcp_port *, int, char *,
void *);
extern void zfcp_erp_port_failed(struct zfcp_port *, char *, void *);
extern void zfcp_erp_modify_unit_status(struct zfcp_unit *, char *, void *, u32,
int);
extern void zfcp_erp_unit_reopen(struct zfcp_unit *, int, u8, void *);
extern void zfcp_erp_unit_shutdown(struct zfcp_unit *, int, u8, void *);
extern void zfcp_erp_unit_failed(struct zfcp_unit *, u8, void *);
extern void zfcp_erp_unit_reopen(struct zfcp_unit *, int, char *, void *);
extern void zfcp_erp_unit_shutdown(struct zfcp_unit *, int, char *, void *);
extern void zfcp_erp_unit_failed(struct zfcp_unit *, char *, void *);
extern int zfcp_erp_thread_setup(struct zfcp_adapter *);
extern void zfcp_erp_thread_kill(struct zfcp_adapter *);
extern void zfcp_erp_wait(struct zfcp_adapter *);
extern void zfcp_erp_notify(struct zfcp_erp_action *, unsigned long);
extern void zfcp_erp_port_boxed(struct zfcp_port *, u8, void *);
extern void zfcp_erp_unit_boxed(struct zfcp_unit *, u8, void *);
extern void zfcp_erp_port_access_denied(struct zfcp_port *, u8, void *);
extern void zfcp_erp_unit_access_denied(struct zfcp_unit *, u8, void *);
extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, u8, void *);
extern void zfcp_erp_port_boxed(struct zfcp_port *, char *, void *);
extern void zfcp_erp_unit_boxed(struct zfcp_unit *, char *, void *);
extern void zfcp_erp_port_access_denied(struct zfcp_port *, char *, void *);
extern void zfcp_erp_unit_access_denied(struct zfcp_unit *, char *, void *);
extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, char *,
void *);
extern void zfcp_erp_timeout_handler(unsigned long);
extern void zfcp_erp_port_strategy_open_lookup(struct work_struct *);
......@@ -101,6 +104,7 @@ extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *);
extern int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *);
extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *);
extern void zfcp_test_link(struct zfcp_port *);
extern void zfcp_fc_link_test_work(struct work_struct *);
extern void zfcp_fc_nameserver_init(struct zfcp_adapter *);
/* zfcp_fsf.c */
......@@ -125,16 +129,13 @@ extern int zfcp_status_read_refill(struct zfcp_adapter *adapter);
extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *,
struct zfcp_erp_action *);
extern int zfcp_fsf_send_els(struct zfcp_send_els *);
extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *,
struct zfcp_unit *,
struct scsi_cmnd *, int, int);
extern int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *,
struct scsi_cmnd *);
extern void zfcp_fsf_req_complete(struct zfcp_fsf_req *);
extern void zfcp_fsf_req_free(struct zfcp_fsf_req *);
extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *,
struct zfcp_unit *, u8, int);
extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *, u8);
extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long,
struct zfcp_adapter *,
struct zfcp_unit *, int);
struct zfcp_unit *);
/* zfcp_qdio.c */
extern int zfcp_qdio_allocate(struct zfcp_adapter *);
......@@ -153,6 +154,10 @@ extern int zfcp_adapter_scsi_register(struct zfcp_adapter *);
extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *);
extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *);
extern struct fc_function_template zfcp_transport_functions;
extern void zfcp_scsi_rport_work(struct work_struct *);
extern void zfcp_scsi_schedule_rport_register(struct zfcp_port *);
extern void zfcp_scsi_schedule_rport_block(struct zfcp_port *);
extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *);
/* zfcp_sysfs.c */
extern struct attribute_group zfcp_sysfs_unit_attrs;
......
......@@ -3,7 +3,7 @@
*
* Fibre Channel related functions for the zfcp device driver.
*
* Copyright IBM Corporation 2008
* Copyright IBM Corporation 2008, 2009
*/
#define KMSG_COMPONENT "zfcp"
......@@ -98,8 +98,12 @@ static void zfcp_wka_port_offline(struct work_struct *work)
struct zfcp_wka_port *wka_port =
container_of(dw, struct zfcp_wka_port, work);
wait_event(wka_port->completion_wq,
atomic_read(&wka_port->refcount) == 0);
/* Don't wait forvever. If the wka_port is too busy take it offline
through a new call later */
if (!wait_event_timeout(wka_port->completion_wq,
atomic_read(&wka_port->refcount) == 0,
HZ >> 1))
return;
mutex_lock(&wka_port->mutex);
if ((atomic_read(&wka_port->refcount) != 0) ||
......@@ -145,16 +149,10 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
struct zfcp_port *port;
read_lock_irqsave(&zfcp_data.config_lock, flags);
list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) {
if (!(atomic_read(&port->status) & ZFCP_STATUS_PORT_PHYS_OPEN))
/* Try to connect to unused ports anyway. */
zfcp_erp_port_reopen(port,
ZFCP_STATUS_COMMON_ERP_FAILED,
82, fsf_req);
else if ((port->d_id & range) == (elem->nport_did & range))
/* Check connection status for connected ports */
list_for_each_entry(port, &fsf_req->adapter->port_list_head, list)
if ((port->d_id & range) == (elem->nport_did & range))
zfcp_test_link(port);
}
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
}
......@@ -196,7 +194,7 @@ static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn)
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
if (port && (port->wwpn == wwpn))
zfcp_erp_port_forced_reopen(port, 0, 83, req);
zfcp_erp_port_forced_reopen(port, 0, "fciwwp1", req);
}
static void zfcp_fc_incoming_plogi(struct zfcp_fsf_req *req)
......@@ -259,10 +257,9 @@ static void zfcp_fc_ns_gid_pn_eval(unsigned long data)
if (ct->status)
return;
if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT) {
atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status);
if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT)
return;
}
/* paranoia */
if (ct_iu_req->wwpn != port->wwpn)
return;
......@@ -375,16 +372,22 @@ static void zfcp_fc_adisc_handler(unsigned long data)
if (adisc->els.status) {
/* request rejected or timed out */
zfcp_erp_port_forced_reopen(port, 0, 63, NULL);
zfcp_erp_port_forced_reopen(port, 0, "fcadh_1", NULL);
goto out;
}
if (!port->wwnn)
port->wwnn = ls_adisc->wwnn;
if (port->wwpn != ls_adisc->wwpn)
zfcp_erp_port_reopen(port, 0, 64, NULL);
if ((port->wwpn != ls_adisc->wwpn) ||
!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)) {
zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED,
"fcadh_2", NULL);
goto out;
}
/* port is good, unblock rport without going through erp */
zfcp_scsi_schedule_rport_register(port);
out:
zfcp_port_put(port);
kfree(adisc);
......@@ -422,6 +425,31 @@ static int zfcp_fc_adisc(struct zfcp_port *port)
return zfcp_fsf_send_els(&adisc->els);
}
void zfcp_fc_link_test_work(struct work_struct *work)
{
struct zfcp_port *port =
container_of(work, struct zfcp_port, test_link_work);
int retval;
if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_UNBLOCKED)) {
zfcp_port_put(port);
return; /* port erp is running and will update rport status */
}
zfcp_port_get(port);
port->rport_task = RPORT_DEL;
zfcp_scsi_rport_work(&port->rport_work);
retval = zfcp_fc_adisc(port);
if (retval == 0)
return;
/* send of ADISC was not possible */
zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL);
zfcp_port_put(port);
}
/**
* zfcp_test_link - lightweight link test procedure
* @port: port to be tested
......@@ -432,17 +460,9 @@ static int zfcp_fc_adisc(struct zfcp_port *port)
*/
void zfcp_test_link(struct zfcp_port *port)
{
int retval;
zfcp_port_get(port);
retval = zfcp_fc_adisc(port);
if (retval == 0)
return;
/* send of ADISC was not possible */
zfcp_port_put(port);
if (retval != -EBUSY)
zfcp_erp_port_forced_reopen(port, 0, 65, NULL);
if (!queue_work(zfcp_data.work_queue, &port->test_link_work))
zfcp_port_put(port);
}
static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num)
......@@ -529,7 +549,7 @@ static void zfcp_validate_port(struct zfcp_port *port)
zfcp_port_put(port);
return;
}
zfcp_erp_port_shutdown(port, 0, 151, NULL);
zfcp_erp_port_shutdown(port, 0, "fcpval1", NULL);
zfcp_erp_wait(adapter);
zfcp_port_put(port);
zfcp_port_dequeue(port);
......@@ -592,7 +612,7 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries)
if (IS_ERR(port))
ret = PTR_ERR(port);
else
zfcp_erp_port_reopen(port, 0, 149, NULL);
zfcp_erp_port_reopen(port, 0, "fcegpf1", NULL);
}
zfcp_erp_wait(adapter);
......
此差异已折叠。
......@@ -127,10 +127,6 @@
#define FSF_STATUS_READ_CFDC_UPDATED 0x0000000A
#define FSF_STATUS_READ_FEATURE_UPDATE_ALERT 0x0000000C
/* status subtypes in status read buffer */
#define FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT 0x00000001
#define FSF_STATUS_READ_SUB_ERROR_PORT 0x00000002
/* status subtypes for link down */
#define FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK 0x00000000
#define FSF_STATUS_READ_SUB_FDISC_FAILED 0x00000001
......
......@@ -11,9 +11,6 @@
#include "zfcp_ext.h"
/* FIXME(tune): free space should be one max. SBAL chain plus what? */
#define ZFCP_QDIO_PCI_INTERVAL (QDIO_MAX_BUFFERS_PER_Q \
- (FSF_MAX_SBALS_PER_REQ + 4))
#define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer))
static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal)
......@@ -58,7 +55,7 @@ void zfcp_qdio_free(struct zfcp_adapter *adapter)
}
}
static void zfcp_qdio_handler_error(struct zfcp_adapter *adapter, u8 id)
static void zfcp_qdio_handler_error(struct zfcp_adapter *adapter, char *id)
{
dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n");
......@@ -77,6 +74,23 @@ static void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt)
}
}
/* this needs to be called prior to updating the queue fill level */
static void zfcp_qdio_account(struct zfcp_adapter *adapter)
{
ktime_t now;
s64 span;
int free, used;
spin_lock(&adapter->qdio_stat_lock);
now = ktime_get();
span = ktime_us_delta(now, adapter->req_q_time);
free = max(0, atomic_read(&adapter->req_q.count));
used = QDIO_MAX_BUFFERS_PER_Q - free;
adapter->req_q_util += used * span;
adapter->req_q_time = now;
spin_unlock(&adapter->qdio_stat_lock);
}
static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err,
int queue_no, int first, int count,
unsigned long parm)
......@@ -86,13 +100,14 @@ static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err,
if (unlikely(qdio_err)) {
zfcp_hba_dbf_event_qdio(adapter, qdio_err, first, count);
zfcp_qdio_handler_error(adapter, 140);
zfcp_qdio_handler_error(adapter, "qdireq1");
return;
}
/* cleanup all SBALs being program-owned now */
zfcp_qdio_zero_sbals(queue->sbal, first, count);
zfcp_qdio_account(adapter);
atomic_add(count, &queue->count);
wake_up(&adapter->request_wq);
}
......@@ -154,7 +169,7 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
if (unlikely(qdio_err)) {
zfcp_hba_dbf_event_qdio(adapter, qdio_err, first, count);
zfcp_qdio_handler_error(adapter, 147);
zfcp_qdio_handler_error(adapter, "qdires1");
return;
}
......@@ -346,21 +361,12 @@ int zfcp_qdio_send(struct zfcp_fsf_req *fsf_req)
struct zfcp_qdio_queue *req_q = &adapter->req_q;
int first = fsf_req->sbal_first;
int count = fsf_req->sbal_number;
int retval, pci, pci_batch;
struct qdio_buffer_element *sbale;
int retval;
unsigned int qdio_flags = QDIO_FLAG_SYNC_OUTPUT;
/* acknowledgements for transferred buffers */
pci_batch = adapter->req_q_pci_batch + count;
if (unlikely(pci_batch >= ZFCP_QDIO_PCI_INTERVAL)) {
pci_batch %= ZFCP_QDIO_PCI_INTERVAL;
pci = first + count - (pci_batch + 1);
pci %= QDIO_MAX_BUFFERS_PER_Q;
sbale = zfcp_qdio_sbale(req_q, pci, 0);
sbale->flags |= SBAL_FLAGS0_PCI;
}
zfcp_qdio_account(adapter);
retval = do_QDIO(adapter->ccw_device, QDIO_FLAG_SYNC_OUTPUT, 0, first,
count);
retval = do_QDIO(adapter->ccw_device, qdio_flags, 0, first, count);
if (unlikely(retval)) {
zfcp_qdio_zero_sbals(req_q->sbal, first, count);
return retval;
......@@ -370,7 +376,6 @@ int zfcp_qdio_send(struct zfcp_fsf_req *fsf_req)
atomic_sub(count, &req_q->count);
req_q->first += count;
req_q->first %= QDIO_MAX_BUFFERS_PER_Q;
adapter->req_q_pci_batch = pci_batch;
return 0;
}
......@@ -441,7 +446,6 @@ void zfcp_qdio_close(struct zfcp_adapter *adapter)
}
req_q->first = 0;
atomic_set(&req_q->count, 0);
adapter->req_q_pci_batch = 0;
adapter->resp_q.first = 0;
atomic_set(&adapter->resp_q.count, 0);
}
......@@ -479,7 +483,6 @@ int zfcp_qdio_open(struct zfcp_adapter *adapter)
/* set index of first avalable SBALS / number of available SBALS */
adapter->req_q.first = 0;
atomic_set(&adapter->req_q.count, QDIO_MAX_BUFFERS_PER_Q);
adapter->req_q_pci_batch = 0;
return 0;
......
......@@ -3,7 +3,7 @@
*
* Interface to Linux SCSI midlayer.
*
* Copyright IBM Corporation 2002, 2008
* Copyright IBM Corporation 2002, 2009
*/
#define KMSG_COMPONENT "zfcp"
......@@ -27,9 +27,7 @@ char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu)
static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
{
struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata;
atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status);
unit->device = NULL;
zfcp_erp_unit_failed(unit, 12, NULL);
zfcp_unit_put(unit);
}
......@@ -58,8 +56,8 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
{
struct zfcp_unit *unit;
struct zfcp_adapter *adapter;
int status;
int ret;
int status, scsi_result, ret;
struct fc_rport *rport = starget_to_rport(scsi_target(scpnt->device));
/* reset the status for this request */
scpnt->result = 0;
......@@ -81,6 +79,14 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
return 0;
}
scsi_result = fc_remote_port_chkready(rport);
if (unlikely(scsi_result)) {
scpnt->result = scsi_result;
zfcp_scsi_dbf_event_result("fail", 4, adapter, scpnt, NULL);
scpnt->scsi_done(scpnt);
return 0;
}
status = atomic_read(&unit->status);
if (unlikely((status & ZFCP_STATUS_COMMON_ERP_FAILED) ||
!(status & ZFCP_STATUS_COMMON_RUNNING))) {
......@@ -88,8 +94,7 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
return 0;;
}
ret = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, 0,
ZFCP_REQ_AUTO_CLEANUP);
ret = zfcp_fsf_send_fcp_command_task(unit, scpnt);
if (unlikely(ret == -EBUSY))
return SCSI_MLQUEUE_DEVICE_BUSY;
else if (unlikely(ret < 0))
......@@ -133,8 +138,7 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdp)
read_lock_irqsave(&zfcp_data.config_lock, flags);
unit = zfcp_unit_lookup(adapter, sdp->channel, sdp->id, sdp->lun);
if (unit &&
(atomic_read(&unit->status) & ZFCP_STATUS_UNIT_REGISTERED)) {
if (unit) {
sdp->hostdata = unit;
unit->device = sdp;
zfcp_unit_get(unit);
......@@ -147,79 +151,91 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdp)
static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
{
struct Scsi_Host *scsi_host;
struct zfcp_adapter *adapter;
struct zfcp_unit *unit;
struct zfcp_fsf_req *fsf_req;
struct Scsi_Host *scsi_host = scpnt->device->host;
struct zfcp_adapter *adapter =
(struct zfcp_adapter *) scsi_host->hostdata[0];
struct zfcp_unit *unit = scpnt->device->hostdata;
struct zfcp_fsf_req *old_req, *abrt_req;
unsigned long flags;
unsigned long old_req_id = (unsigned long) scpnt->host_scribble;
int retval = SUCCESS;
scsi_host = scpnt->device->host;
adapter = (struct zfcp_adapter *) scsi_host->hostdata[0];
unit = scpnt->device->hostdata;
int retry = 3;
/* avoid race condition between late normal completion and abort */
write_lock_irqsave(&adapter->abort_lock, flags);
/* Check whether corresponding fsf_req is still pending */
spin_lock(&adapter->req_list_lock);
fsf_req = zfcp_reqlist_find(adapter, old_req_id);
old_req = zfcp_reqlist_find(adapter, old_req_id);
spin_unlock(&adapter->req_list_lock);
if (!fsf_req) {
if (!old_req) {
write_unlock_irqrestore(&adapter->abort_lock, flags);
zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, 0);
return retval;
zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL,
old_req_id);
return SUCCESS;
}
fsf_req->data = NULL;
old_req->data = NULL;
/* don't access old fsf_req after releasing the abort_lock */
write_unlock_irqrestore(&adapter->abort_lock, flags);
fsf_req = zfcp_fsf_abort_fcp_command(old_req_id, adapter, unit, 0);
if (!fsf_req) {
zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL,
old_req_id);
retval = FAILED;
return retval;
while (retry--) {
abrt_req = zfcp_fsf_abort_fcp_command(old_req_id, unit);
if (abrt_req)
break;
zfcp_erp_wait(adapter);
if (!(atomic_read(&adapter->status) &
ZFCP_STATUS_COMMON_RUNNING)) {
zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL,
old_req_id);
return SUCCESS;
}
}
if (!abrt_req)
return FAILED;
__wait_event(fsf_req->completion_wq,
fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
wait_event(abrt_req->completion_wq,
abrt_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) {
zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, fsf_req, 0);
} else if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) {
zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, fsf_req, 0);
} else {
zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, fsf_req, 0);
if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED)
zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, abrt_req, 0);
else if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED)
zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, abrt_req, 0);
else {
zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, abrt_req, 0);
retval = FAILED;
}
zfcp_fsf_req_free(fsf_req);
zfcp_fsf_req_free(abrt_req);
return retval;
}
static int zfcp_task_mgmt_function(struct zfcp_unit *unit, u8 tm_flags,
struct scsi_cmnd *scpnt)
static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
{
struct zfcp_unit *unit = scpnt->device->hostdata;
struct zfcp_adapter *adapter = unit->port->adapter;
struct zfcp_fsf_req *fsf_req;
int retval = SUCCESS;
/* issue task management function */
fsf_req = zfcp_fsf_send_fcp_ctm(adapter, unit, tm_flags, 0);
if (!fsf_req) {
zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, scpnt);
return FAILED;
int retry = 3;
while (retry--) {
fsf_req = zfcp_fsf_send_fcp_ctm(unit, tm_flags);
if (fsf_req)
break;
zfcp_erp_wait(adapter);
if (!(atomic_read(&adapter->status) &
ZFCP_STATUS_COMMON_RUNNING)) {
zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit,
scpnt);
return SUCCESS;
}
}
if (!fsf_req)
return FAILED;
__wait_event(fsf_req->completion_wq,
fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
wait_event(fsf_req->completion_wq,
fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
/*
* check completion status of task management function
*/
if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) {
zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt);
retval = FAILED;
......@@ -230,40 +246,25 @@ static int zfcp_task_mgmt_function(struct zfcp_unit *unit, u8 tm_flags,
zfcp_scsi_dbf_event_devreset("okay", tm_flags, unit, scpnt);
zfcp_fsf_req_free(fsf_req);
return retval;
}
static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
{
struct zfcp_unit *unit = scpnt->device->hostdata;
if (!unit) {
WARN_ON(1);
return SUCCESS;
}
return zfcp_task_mgmt_function(unit, FCP_LOGICAL_UNIT_RESET, scpnt);
return zfcp_task_mgmt_function(scpnt, FCP_LOGICAL_UNIT_RESET);
}
static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt)
{
struct zfcp_unit *unit = scpnt->device->hostdata;
if (!unit) {
WARN_ON(1);
return SUCCESS;
}
return zfcp_task_mgmt_function(unit, FCP_TARGET_RESET, scpnt);
return zfcp_task_mgmt_function(scpnt, FCP_TARGET_RESET);
}
static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
{
struct zfcp_unit *unit;
struct zfcp_adapter *adapter;
struct zfcp_unit *unit = scpnt->device->hostdata;
struct zfcp_adapter *adapter = unit->port->adapter;
unit = scpnt->device->hostdata;
adapter = unit->port->adapter;
zfcp_erp_adapter_reopen(adapter, 0, 141, scpnt);
zfcp_erp_adapter_reopen(adapter, 0, "schrh_1", scpnt);
zfcp_erp_wait(adapter);
return SUCCESS;
......@@ -479,6 +480,109 @@ static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
rport->dev_loss_tmo = timeout;
}
/**
* zfcp_scsi_dev_loss_tmo_callbk - Free any reference to rport
* @rport: The rport that is about to be deleted.
*/
static void zfcp_scsi_dev_loss_tmo_callbk(struct fc_rport *rport)
{
struct zfcp_port *port = rport->dd_data;
write_lock_irq(&zfcp_data.config_lock);
port->rport = NULL;
write_unlock_irq(&zfcp_data.config_lock);
}
/**
* zfcp_scsi_terminate_rport_io - Terminate all I/O on a rport
* @rport: The FC rport where to teminate I/O
*
* Abort all pending SCSI commands for a port by closing the
* port. Using a reopen for avoids a conflict with a shutdown
* overwriting a reopen.
*/
static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)
{
struct zfcp_port *port = rport->dd_data;
zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL);
}
static void zfcp_scsi_rport_register(struct zfcp_port *port)
{
struct fc_rport_identifiers ids;
struct fc_rport *rport;
ids.node_name = port->wwnn;
ids.port_name = port->wwpn;
ids.port_id = port->d_id;
ids.roles = FC_RPORT_ROLE_FCP_TARGET;
rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids);
if (!rport) {
dev_err(&port->adapter->ccw_device->dev,
"Registering port 0x%016Lx failed\n",
(unsigned long long)port->wwpn);
return;
}
rport->dd_data = port;
rport->maxframe_size = port->maxframe_size;
rport->supported_classes = port->supported_classes;
port->rport = rport;
}
static void zfcp_scsi_rport_block(struct zfcp_port *port)
{
if (port->rport)
fc_remote_port_delete(port->rport);
}
void zfcp_scsi_schedule_rport_register(struct zfcp_port *port)
{
zfcp_port_get(port);
port->rport_task = RPORT_ADD;
if (!queue_work(zfcp_data.work_queue, &port->rport_work))
zfcp_port_put(port);
}
void zfcp_scsi_schedule_rport_block(struct zfcp_port *port)
{
zfcp_port_get(port);
port->rport_task = RPORT_DEL;
if (!queue_work(zfcp_data.work_queue, &port->rport_work))
zfcp_port_put(port);
}
void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter)
{
struct zfcp_port *port;
list_for_each_entry(port, &adapter->port_list_head, list)
zfcp_scsi_schedule_rport_block(port);
}
void zfcp_scsi_rport_work(struct work_struct *work)
{
struct zfcp_port *port = container_of(work, struct zfcp_port,
rport_work);
while (port->rport_task) {
if (port->rport_task == RPORT_ADD) {
port->rport_task = RPORT_NONE;
zfcp_scsi_rport_register(port);
} else {
port->rport_task = RPORT_NONE;
zfcp_scsi_rport_block(port);
}
}
zfcp_port_put(port);
}
struct fc_function_template zfcp_transport_functions = {
.show_starget_port_id = 1,
.show_starget_port_name = 1,
......@@ -497,6 +601,8 @@ struct fc_function_template zfcp_transport_functions = {
.reset_fc_host_stats = zfcp_reset_fc_host_stats,
.set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo,
.get_host_port_state = zfcp_get_host_port_state,
.dev_loss_tmo_callbk = zfcp_scsi_dev_loss_tmo_callbk,
.terminate_rport_io = zfcp_scsi_terminate_rport_io,
.show_host_port_state = 1,
/* no functions registered for following dynamic attributes but
directly set by LLDD */
......
......@@ -112,9 +112,9 @@ static ZFCP_DEV_ATTR(_feat, failed, S_IWUSR | S_IRUGO, \
zfcp_sysfs_##_feat##_failed_show, \
zfcp_sysfs_##_feat##_failed_store);
ZFCP_SYSFS_FAILED(zfcp_adapter, adapter, adapter, 44, 93);
ZFCP_SYSFS_FAILED(zfcp_port, port, port->adapter, 45, 96);
ZFCP_SYSFS_FAILED(zfcp_unit, unit, unit->port->adapter, 46, 97);
ZFCP_SYSFS_FAILED(zfcp_adapter, adapter, adapter, "syafai1", "syafai2");
ZFCP_SYSFS_FAILED(zfcp_port, port, port->adapter, "sypfai1", "sypfai2");
ZFCP_SYSFS_FAILED(zfcp_unit, unit, unit->port->adapter, "syufai1", "syufai2");
static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev,
struct device_attribute *attr,
......@@ -168,7 +168,7 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
goto out;
}
zfcp_erp_port_shutdown(port, 0, 92, NULL);
zfcp_erp_port_shutdown(port, 0, "syprs_1", NULL);
zfcp_erp_wait(adapter);
zfcp_port_put(port);
zfcp_port_dequeue(port);
......@@ -222,7 +222,7 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
retval = 0;
zfcp_erp_unit_reopen(unit, 0, 94, NULL);
zfcp_erp_unit_reopen(unit, 0, "syuas_1", NULL);
zfcp_erp_wait(unit->port->adapter);
zfcp_unit_put(unit);
out:
......@@ -268,7 +268,7 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
goto out;
}
zfcp_erp_unit_shutdown(unit, 0, 95, NULL);
zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL);
zfcp_erp_wait(unit->port->adapter);
zfcp_unit_put(unit);
zfcp_unit_dequeue(unit);
......@@ -318,10 +318,9 @@ zfcp_sysfs_unit_##_name##_latency_show(struct device *dev, \
struct zfcp_unit *unit = sdev->hostdata; \
struct zfcp_latencies *lat = &unit->latencies; \
struct zfcp_adapter *adapter = unit->port->adapter; \
unsigned long flags; \
unsigned long long fsum, fmin, fmax, csum, cmin, cmax, cc; \
\
spin_lock_irqsave(&lat->lock, flags); \
spin_lock_bh(&lat->lock); \
fsum = lat->_name.fabric.sum * adapter->timer_ticks; \
fmin = lat->_name.fabric.min * adapter->timer_ticks; \
fmax = lat->_name.fabric.max * adapter->timer_ticks; \
......@@ -329,7 +328,7 @@ zfcp_sysfs_unit_##_name##_latency_show(struct device *dev, \
cmin = lat->_name.channel.min * adapter->timer_ticks; \
cmax = lat->_name.channel.max * adapter->timer_ticks; \
cc = lat->_name.counter; \
spin_unlock_irqrestore(&lat->lock, flags); \
spin_unlock_bh(&lat->lock); \
\
do_div(fsum, 1000); \
do_div(fmin, 1000); \
......@@ -487,7 +486,8 @@ static ssize_t zfcp_sysfs_adapter_q_full_show(struct device *dev,
struct zfcp_adapter *adapter =
(struct zfcp_adapter *) scsi_host->hostdata[0];
return sprintf(buf, "%d\n", atomic_read(&adapter->qdio_outb_full));
return sprintf(buf, "%d %llu\n", atomic_read(&adapter->qdio_outb_full),
(unsigned long long)adapter->req_q_util);
}
static DEVICE_ATTR(queue_full, S_IRUGO, zfcp_sysfs_adapter_q_full_show, NULL);
......
......@@ -4,7 +4,7 @@
Written By: Adam Radford <linuxraid@amcc.com>
Modifications By: Tom Couch <linuxraid@amcc.com>
Copyright (C) 2004-2008 Applied Micro Circuits Corporation.
Copyright (C) 2004-2009 Applied Micro Circuits Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -75,6 +75,7 @@
Add MSI support and "use_msi" module parameter.
Fix bug in twa_get_param() on 4GB+.
Use pci_resource_len() for ioremap().
2.26.02.012 - Add power management support.
*/
#include <linux/module.h>
......@@ -99,7 +100,7 @@
#include "3w-9xxx.h"
/* Globals */
#define TW_DRIVER_VERSION "2.26.02.011"
#define TW_DRIVER_VERSION "2.26.02.012"
static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
static unsigned int twa_device_extension_count;
static int twa_major = -1;
......@@ -2182,6 +2183,98 @@ static void twa_remove(struct pci_dev *pdev)
twa_device_extension_count--;
} /* End twa_remove() */
#ifdef CONFIG_PM
/* This function is called on PCI suspend */
static int twa_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct Scsi_Host *host = pci_get_drvdata(pdev);
TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
printk(KERN_WARNING "3w-9xxx: Suspending host %d.\n", tw_dev->host->host_no);
TW_DISABLE_INTERRUPTS(tw_dev);
free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
if (test_bit(TW_USING_MSI, &tw_dev->flags))
pci_disable_msi(pdev);
/* Tell the card we are shutting down */
if (twa_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x38, "Connection shutdown failed during suspend");
} else {
printk(KERN_WARNING "3w-9xxx: Suspend complete.\n");
}
TW_CLEAR_ALL_INTERRUPTS(tw_dev);
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
} /* End twa_suspend() */
/* This function is called on PCI resume */
static int twa_resume(struct pci_dev *pdev)
{
int retval = 0;
struct Scsi_Host *host = pci_get_drvdata(pdev);
TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
printk(KERN_WARNING "3w-9xxx: Resuming host %d.\n", tw_dev->host->host_no);
pci_set_power_state(pdev, PCI_D0);
pci_enable_wake(pdev, PCI_D0, 0);
pci_restore_state(pdev);
retval = pci_enable_device(pdev);
if (retval) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x39, "Enable device failed during resume");
return retval;
}
pci_set_master(pdev);
pci_try_set_mwi(pdev);
if (pci_set_dma_mask(pdev, DMA_64BIT_MASK)
|| pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)
|| pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
TW_PRINTK(host, TW_DRIVER, 0x40, "Failed to set dma mask during resume");
retval = -ENODEV;
goto out_disable_device;
}
/* Initialize the card */
if (twa_reset_sequence(tw_dev, 0)) {
retval = -ENODEV;
goto out_disable_device;
}
/* Now setup the interrupt handler */
retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev);
if (retval) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x42, "Error requesting IRQ during resume");
retval = -ENODEV;
goto out_disable_device;
}
/* Now enable MSI if enabled */
if (test_bit(TW_USING_MSI, &tw_dev->flags))
pci_enable_msi(pdev);
/* Re-enable interrupts on the card */
TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
printk(KERN_WARNING "3w-9xxx: Resume complete.\n");
return 0;
out_disable_device:
scsi_remove_host(host);
pci_disable_device(pdev);
return retval;
} /* End twa_resume() */
#endif
/* PCI Devices supported by this driver */
static struct pci_device_id twa_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9000,
......@@ -2202,6 +2295,10 @@ static struct pci_driver twa_driver = {
.id_table = twa_pci_tbl,
.probe = twa_probe,
.remove = twa_remove,
#ifdef CONFIG_PM
.suspend = twa_suspend,
.resume = twa_resume,
#endif
.shutdown = twa_shutdown
};
......
......@@ -4,7 +4,7 @@
Written By: Adam Radford <linuxraid@amcc.com>
Modifications By: Tom Couch <linuxraid@amcc.com>
Copyright (C) 2004-2008 Applied Micro Circuits Corporation.
Copyright (C) 2004-2009 Applied Micro Circuits Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......
......@@ -224,14 +224,15 @@ config SCSI_LOGGING
can enable logging by saying Y to "/proc file system support" and
"Sysctl support" below and executing the command
echo "scsi log token [level]" > /proc/scsi/scsi
echo <bitmask> > /proc/sys/dev/scsi/logging_level
at boot time after the /proc file system has been mounted.
where <bitmask> is a four byte value representing the logging type
and logging level for each type of logging selected.
There are a number of things that can be used for 'token' (you can
find them in the source: <file:drivers/scsi/scsi.c>), and this
allows you to select the types of information you want, and the
level allows you to select the level of verbosity.
There are a number of logging types and you can find them in the
source at <file:drivers/scsi/scsi_logging.h>. The logging levels
are also described in that file and they determine the verbosity of
the logging for each logging type.
If you say N here, it may be harder to track down some types of SCSI
problems. If you say Y here your kernel will be somewhat larger, but
......@@ -570,6 +571,7 @@ config SCSI_ARCMSR_AER
To enable this function, choose Y here.
source "drivers/scsi/megaraid/Kconfig.megaraid"
source "drivers/scsi/mpt2sas/Kconfig"
config SCSI_HPTIOP
tristate "HighPoint RocketRAID 3xxx/4xxx Controller support"
......@@ -608,6 +610,7 @@ config SCSI_FLASHPOINT
config LIBFC
tristate "LibFC module"
select SCSI_FC_ATTRS
select CRC32
---help---
Fibre Channel library module
......@@ -1535,6 +1538,7 @@ config SCSI_NSP32
config SCSI_DEBUG
tristate "SCSI debugging host simulator"
depends on SCSI
select CRC_T10DIF
help
This is a host adapter simulator that can simulate multiple hosts
each with multiple dummy SCSI devices (disks). It defaults to one
......@@ -1803,4 +1807,6 @@ source "drivers/scsi/pcmcia/Kconfig"
source "drivers/scsi/device_handler/Kconfig"
source "drivers/scsi/osd/Kconfig"
endmenu
......@@ -99,6 +99,7 @@ obj-$(CONFIG_SCSI_DC390T) += tmscsim.o
obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o
obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/
obj-$(CONFIG_MEGARAID_SAS) += megaraid/
obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas/
obj-$(CONFIG_SCSI_ACARD) += atp870u.o
obj-$(CONFIG_SCSI_SUNESP) += esp_scsi.o sun_esp.o
obj-$(CONFIG_SCSI_GDTH) += gdth.o
......@@ -137,6 +138,8 @@ obj-$(CONFIG_CHR_DEV_SG) += sg.o
obj-$(CONFIG_CHR_DEV_SCH) += ch.o
obj-$(CONFIG_SCSI_ENCLOSURE) += ses.o
obj-$(CONFIG_SCSI_OSD_INITIATOR) += osd/
# This goes last, so that "real" scsi devices probe earlier
obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o
......
......@@ -41,6 +41,7 @@ MODULE_DESCRIPTION("device driver for scsi media changer devices");
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org>");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV_MAJOR(SCSI_CHANGER_MAJOR);
MODULE_ALIAS_SCSI_DEVICE(TYPE_MEDIUM_CHANGER);
static int init = 1;
module_param(init, int, 0444);
......
......@@ -1373,21 +1373,14 @@ static const char * const driverbyte_table[]={
"DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE"};
#define NUM_DRIVERBYTE_STRS ARRAY_SIZE(driverbyte_table)
static const char * const driversuggest_table[]={"SUGGEST_OK",
"SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP", "SUGGEST_DIE",
"SUGGEST_5", "SUGGEST_6", "SUGGEST_7", "SUGGEST_SENSE"};
#define NUM_SUGGEST_STRS ARRAY_SIZE(driversuggest_table)
void scsi_show_result(int result)
{
int hb = host_byte(result);
int db = (driver_byte(result) & DRIVER_MASK);
int su = ((driver_byte(result) & SUGGEST_MASK) >> 4);
int db = driver_byte(result);
printk("Result: hostbyte=%s driverbyte=%s,%s\n",
printk("Result: hostbyte=%s driverbyte=%s\n",
(hb < NUM_HOSTBYTE_STRS ? hostbyte_table[hb] : "invalid"),
(db < NUM_DRIVERBYTE_STRS ? driverbyte_table[db] : "invalid"),
(su < NUM_SUGGEST_STRS ? driversuggest_table[su] : "invalid"));
(db < NUM_DRIVERBYTE_STRS ? driverbyte_table[db] : "invalid"));
}
#else
......
......@@ -196,7 +196,7 @@ static inline int ddp_alloc_gl_skb(struct cxgb3i_ddp_info *ddp, int idx,
}
/**
* cxgb3i_ddp_find_page_index - return ddp page index for a given page size.
* cxgb3i_ddp_find_page_index - return ddp page index for a given page size
* @pgsz: page size
* return the ddp page index, if no match is found return DDP_PGIDX_MAX.
*/
......@@ -355,8 +355,7 @@ EXPORT_SYMBOL_GPL(cxgb3i_ddp_release_gl);
* @tdev: t3cdev adapter
* @tid: connection id
* @tformat: tag format
* @tagp: the s/w tag, if ddp setup is successful, it will be updated with
* ddp/hw tag
* @tagp: contains s/w tag initially, will be updated with ddp/hw tag
* @gl: the page momory list
* @gfp: allocation mode
*
......
......@@ -185,12 +185,11 @@ static inline int cxgb3i_is_ddp_tag(struct cxgb3i_tag_format *tformat, u32 tag)
}
/**
* cxgb3i_sw_tag_usable - check if a given s/w tag has enough bits left for
* the reserved/hw bits
* cxgb3i_sw_tag_usable - check if s/w tag has enough bits left for hw bits
* @tformat: tag format information
* @sw_tag: s/w tag to be checked
*
* return true if the tag is a ddp tag, false otherwise.
* return true if the tag can be used for hw ddp tag, false otherwise.
*/
static inline int cxgb3i_sw_tag_usable(struct cxgb3i_tag_format *tformat,
u32 sw_tag)
......@@ -222,8 +221,7 @@ static inline u32 cxgb3i_set_non_ddp_tag(struct cxgb3i_tag_format *tformat,
}
/**
* cxgb3i_ddp_tag_base - shift the s/w tag bits so that reserved bits are not
* used.
* cxgb3i_ddp_tag_base - shift s/w tag bits so that reserved bits are not used
* @tformat: tag format information
* @sw_tag: s/w tag to be checked
*/
......
......@@ -101,8 +101,7 @@ struct cxgb3i_adapter *cxgb3i_adapter_add(struct t3cdev *t3dev)
}
/**
* cxgb3i_adapter_remove - release all the resources held and cleanup any
* h/w settings
* cxgb3i_adapter_remove - release the resources held and cleanup h/w settings
* @t3dev: t3cdev adapter
*/
void cxgb3i_adapter_remove(struct t3cdev *t3dev)
......@@ -135,8 +134,7 @@ void cxgb3i_adapter_remove(struct t3cdev *t3dev)
}
/**
* cxgb3i_hba_find_by_netdev - find the cxgb3i_hba structure with a given
* net_device
* cxgb3i_hba_find_by_netdev - find the cxgb3i_hba structure via net_device
* @t3dev: t3cdev adapter
*/
struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *ndev)
......@@ -170,8 +168,7 @@ struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *snic,
int err;
shost = iscsi_host_alloc(&cxgb3i_host_template,
sizeof(struct cxgb3i_hba),
CXGB3I_SCSI_QDEPTH_DFLT);
sizeof(struct cxgb3i_hba), 1);
if (!shost) {
cxgb3i_log_info("iscsi_host_alloc failed.\n");
return NULL;
......@@ -335,13 +332,12 @@ static void cxgb3i_ep_disconnect(struct iscsi_endpoint *ep)
* @cmds_max: max # of commands
* @qdepth: scsi queue depth
* @initial_cmdsn: initial iscsi CMDSN for this session
* @host_no: pointer to return host no
*
* Creates a new iSCSI session
*/
static struct iscsi_cls_session *
cxgb3i_session_create(struct iscsi_endpoint *ep, u16 cmds_max, u16 qdepth,
u32 initial_cmdsn, u32 *host_no)
u32 initial_cmdsn)
{
struct cxgb3i_endpoint *cep;
struct cxgb3i_hba *hba;
......@@ -360,8 +356,6 @@ cxgb3i_session_create(struct iscsi_endpoint *ep, u16 cmds_max, u16 qdepth,
cxgb3i_api_debug("ep 0x%p, cep 0x%p, hba 0x%p.\n", ep, cep, hba);
BUG_ON(hba != iscsi_host_priv(shost));
*host_no = shost->host_no;
cls_session = iscsi_session_setup(&cxgb3i_iscsi_transport, shost,
cmds_max,
sizeof(struct iscsi_tcp_task) +
......@@ -394,9 +388,9 @@ static void cxgb3i_session_destroy(struct iscsi_cls_session *cls_session)
}
/**
* cxgb3i_conn_max_xmit_dlength -- check the max. xmit pdu segment size,
* reduce it to be within the hardware limit if needed
* cxgb3i_conn_max_xmit_dlength -- calc the max. xmit pdu segment size
* @conn: iscsi connection
* check the max. xmit pdu payload, reduce it if needed
*/
static inline int cxgb3i_conn_max_xmit_dlength(struct iscsi_conn *conn)
......@@ -417,8 +411,7 @@ static inline int cxgb3i_conn_max_xmit_dlength(struct iscsi_conn *conn)
}
/**
* cxgb3i_conn_max_recv_dlength -- check the max. recv pdu segment size against
* the hardware limit
* cxgb3i_conn_max_recv_dlength -- check the max. recv pdu segment size
* @conn: iscsi connection
* return 0 if the value is valid, < 0 otherwise.
*/
......@@ -759,9 +752,9 @@ static void cxgb3i_parse_itt(struct iscsi_conn *conn, itt_t itt,
/**
* cxgb3i_reserve_itt - generate tag for a give task
* Try to set up ddp for a scsi read task.
* @task: iscsi task
* @hdr_itt: tag, filled in by this function
* Set up ddp for scsi read tasks if possible.
*/
int cxgb3i_reserve_itt(struct iscsi_task *task, itt_t *hdr_itt)
{
......@@ -809,9 +802,9 @@ int cxgb3i_reserve_itt(struct iscsi_task *task, itt_t *hdr_itt)
/**
* cxgb3i_release_itt - release the tag for a given task
* if the tag is a ddp tag, release the ddp setup
* @task: iscsi task
* @hdr_itt: tag
* If the tag is a ddp tag, release the ddp setup
*/
void cxgb3i_release_itt(struct iscsi_task *task, itt_t hdr_itt)
{
......@@ -843,7 +836,7 @@ static struct scsi_host_template cxgb3i_host_template = {
.can_queue = CXGB3I_SCSI_QDEPTH_DFLT - 1,
.sg_tablesize = SG_ALL,
.max_sectors = 0xFFFF,
.cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,
.cmd_per_lun = CXGB3I_SCSI_QDEPTH_DFLT,
.eh_abort_handler = iscsi_eh_abort,
.eh_device_reset_handler = iscsi_eh_device_reset,
.eh_target_reset_handler = iscsi_eh_target_reset,
......
......@@ -1417,8 +1417,7 @@ static void c3cn_active_close(struct s3_conn *c3cn)
}
/**
* cxgb3i_c3cn_release - close and release an iscsi tcp connection and any
* resource held
* cxgb3i_c3cn_release - close and release an iscsi tcp connection
* @c3cn: the iscsi tcp connection
*/
void cxgb3i_c3cn_release(struct s3_conn *c3cn)
......
......@@ -139,6 +139,7 @@ enum c3cn_flags {
/**
* cxgb3i_sdev_data - Per adapter data.
*
* Linked off of each Ethernet device port on the adapter.
* Also available via the t3cdev structure since we have pointers to our port
* net_device's there ...
......
......@@ -479,7 +479,7 @@ void cxgb3i_conn_tx_open(struct s3_conn *c3cn)
cxgb3i_tx_debug("cn 0x%p.\n", c3cn);
if (conn) {
cxgb3i_tx_debug("cn 0x%p, cid %d.\n", c3cn, conn->id);
scsi_queue_work(conn->session->host, &conn->xmitwork);
iscsi_conn_queue_work(conn);
}
}
......
......@@ -247,8 +247,8 @@ static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
/* Prepare the data buffer */
memset(h->buff, 0, stpg_len);
h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f;
h->buff[6] = (h->group_id >> 8) & 0x0f;
h->buff[7] = h->group_id & 0x0f;
h->buff[6] = (h->group_id >> 8) & 0xff;
h->buff[7] = h->group_id & 0xff;
rq = get_alua_req(sdev, h->buff, stpg_len, WRITE);
if (!rq)
......@@ -461,6 +461,15 @@ static int alua_check_sense(struct scsi_device *sdev,
*/
return ADD_TO_MLQUEUE;
}
if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x0e) {
/*
* REPORTED_LUNS_DATA_HAS_CHANGED is reported
* when switching controllers on targets like
* Intel Multi-Flex. We can just retry.
*/
return ADD_TO_MLQUEUE;
}
break;
}
......@@ -691,6 +700,7 @@ static const struct scsi_dh_devlist alua_dev_list[] = {
{"IBM", "2107900" },
{"IBM", "2145" },
{"Pillar", "Axiom" },
{"Intel", "Multi-Flex"},
{NULL, NULL}
};
......
......@@ -449,28 +449,40 @@ static int mode_select_handle_sense(struct scsi_device *sdev,
unsigned char *sensebuf)
{
struct scsi_sense_hdr sense_hdr;
int sense, err = SCSI_DH_IO, ret;
int err = SCSI_DH_IO, ret;
ret = scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, &sense_hdr);
if (!ret)
goto done;
err = SCSI_DH_OK;
sense = (sense_hdr.sense_key << 16) | (sense_hdr.asc << 8) |
sense_hdr.ascq;
/* If it is retryable failure, submit the c9 inquiry again */
if (sense == 0x59136 || sense == 0x68b02 || sense == 0xb8b02 ||
sense == 0x62900) {
/* 0x59136 - Command lock contention
* 0x[6b]8b02 - Quiesense in progress or achieved
* 0x62900 - Power On, Reset, or Bus Device Reset
*/
switch (sense_hdr.sense_key) {
case NO_SENSE:
case ABORTED_COMMAND:
case UNIT_ATTENTION:
err = SCSI_DH_RETRY;
break;
case NOT_READY:
if (sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x01)
/* LUN Not Ready and is in the Process of Becoming
* Ready
*/
err = SCSI_DH_RETRY;
break;
case ILLEGAL_REQUEST:
if (sense_hdr.asc == 0x91 && sense_hdr.ascq == 0x36)
/*
* Command Lock contention
*/
err = SCSI_DH_RETRY;
break;
default:
sdev_printk(KERN_INFO, sdev,
"MODE_SELECT failed with sense %02x/%02x/%02x.\n",
sense_hdr.sense_key, sense_hdr.asc, sense_hdr.ascq);
}
if (sense)
sdev_printk(KERN_INFO, sdev,
"MODE_SELECT failed with sense 0x%x.\n", sense);
done:
return err;
}
......@@ -562,6 +574,12 @@ static int rdac_check_sense(struct scsi_device *sdev,
* Just retry and wait.
*/
return ADD_TO_MLQUEUE;
if (sense_hdr->asc == 0xA1 && sense_hdr->ascq == 0x02)
/* LUN Not Ready - Quiescense in progress
* or has been achieved
* Just retry.
*/
return ADD_TO_MLQUEUE;
break;
case ILLEGAL_REQUEST:
if (sense_hdr->asc == 0x94 && sense_hdr->ascq == 0x01) {
......@@ -579,6 +597,11 @@ static int rdac_check_sense(struct scsi_device *sdev,
* Power On, Reset, or Bus Device Reset, just retry.
*/
return ADD_TO_MLQUEUE;
if (sense_hdr->asc == 0x8b && sense_hdr->ascq == 0x02)
/*
* Quiescence in progress , just retry.
*/
return ADD_TO_MLQUEUE;
break;
}
/* success just means we do not care what scsi-ml does */
......
......@@ -133,6 +133,13 @@ static int fcoe_sw_lport_config(struct fc_lport *lp)
/* lport fc_lport related configuration */
fc_lport_config(lp);
/* offload related configuration */
lp->crc_offload = 0;
lp->seq_offload = 0;
lp->lro_enabled = 0;
lp->lro_xid = 0;
lp->lso_max = 0;
return 0;
}
......@@ -186,7 +193,27 @@ static int fcoe_sw_netdev_config(struct fc_lport *lp, struct net_device *netdev)
if (fc->real_dev->features & NETIF_F_SG)
lp->sg_supp = 1;
#ifdef NETIF_F_FCOE_CRC
if (netdev->features & NETIF_F_FCOE_CRC) {
lp->crc_offload = 1;
printk(KERN_DEBUG "fcoe:%s supports FCCRC offload\n",
netdev->name);
}
#endif
#ifdef NETIF_F_FSO
if (netdev->features & NETIF_F_FSO) {
lp->seq_offload = 1;
lp->lso_max = netdev->gso_max_size;
printk(KERN_DEBUG "fcoe:%s supports LSO for max len 0x%x\n",
netdev->name, lp->lso_max);
}
#endif
if (netdev->fcoe_ddp_xid) {
lp->lro_enabled = 1;
lp->lro_xid = netdev->fcoe_ddp_xid;
printk(KERN_DEBUG "fcoe:%s supports LRO for max xid 0x%x\n",
netdev->name, lp->lro_xid);
}
skb_queue_head_init(&fc->fcoe_pending_queue);
fc->fcoe_pending_queue_active = 0;
......@@ -346,8 +373,46 @@ static int fcoe_sw_destroy(struct net_device *netdev)
return 0;
}
/*
* fcoe_sw_ddp_setup - calls LLD's ddp_setup through net_device
* @lp: the corresponding fc_lport
* @xid: the exchange id for this ddp transfer
* @sgl: the scatterlist describing this transfer
* @sgc: number of sg items
*
* Returns : 0 no ddp
*/
static int fcoe_sw_ddp_setup(struct fc_lport *lp, u16 xid,
struct scatterlist *sgl, unsigned int sgc)
{
struct net_device *n = fcoe_netdev(lp);
if (n->netdev_ops && n->netdev_ops->ndo_fcoe_ddp_setup)
return n->netdev_ops->ndo_fcoe_ddp_setup(n, xid, sgl, sgc);
return 0;
}
/*
* fcoe_sw_ddp_done - calls LLD's ddp_done through net_device
* @lp: the corresponding fc_lport
* @xid: the exchange id for this ddp transfer
*
* Returns : the length of data that have been completed by ddp
*/
static int fcoe_sw_ddp_done(struct fc_lport *lp, u16 xid)
{
struct net_device *n = fcoe_netdev(lp);
if (n->netdev_ops && n->netdev_ops->ndo_fcoe_ddp_done)
return n->netdev_ops->ndo_fcoe_ddp_done(n, xid);
return 0;
}
static struct libfc_function_template fcoe_sw_libfc_fcn_templ = {
.frame_send = fcoe_xmit,
.ddp_setup = fcoe_sw_ddp_setup,
.ddp_done = fcoe_sw_ddp_done,
};
/**
......
......@@ -423,7 +423,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
/* crc offload */
if (likely(lp->crc_offload)) {
skb->ip_summed = CHECKSUM_COMPLETE;
skb->ip_summed = CHECKSUM_PARTIAL;
skb->csum_start = skb_headroom(skb);
skb->csum_offset = skb->len;
crc = 0;
......@@ -460,7 +460,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
skb_reset_mac_header(skb);
skb_reset_network_header(skb);
skb->mac_len = elen;
skb->protocol = htons(ETH_P_802_3);
skb->protocol = htons(ETH_P_FCOE);
skb->dev = fc->real_dev;
/* fill up mac and fcoe headers */
......@@ -483,6 +483,16 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER);
hp->fcoe_sof = sof;
#ifdef NETIF_F_FSO
/* fcoe lso, mss is in max_payload which is non-zero for FCP data */
if (lp->seq_offload && fr_max_payload(fp)) {
skb_shinfo(skb)->gso_type = SKB_GSO_FCOE;
skb_shinfo(skb)->gso_size = fr_max_payload(fp);
} else {
skb_shinfo(skb)->gso_type = 0;
skb_shinfo(skb)->gso_size = 0;
}
#endif
/* update tx stats: regardless if LLD fails */
stats = lp->dev_stats[smp_processor_id()];
if (stats) {
......@@ -623,7 +633,7 @@ int fcoe_percpu_receive_thread(void *arg)
* it's solicited data, in which case, the FCP layer would
* check it during the copy.
*/
if (lp->crc_offload)
if (lp->crc_offload && skb->ip_summed == CHECKSUM_UNNECESSARY)
fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
else
fr_flags(fp) |= FCPHF_CRC_UNCHECKED;
......
......@@ -176,7 +176,6 @@ void scsi_remove_host(struct Scsi_Host *shost)
transport_unregister_device(&shost->shost_gendev);
device_unregister(&shost->shost_dev);
device_del(&shost->shost_gendev);
scsi_proc_hostdir_rm(shost->hostt);
}
EXPORT_SYMBOL(scsi_remove_host);
......@@ -270,6 +269,8 @@ static void scsi_host_dev_release(struct device *dev)
struct Scsi_Host *shost = dev_to_shost(dev);
struct device *parent = dev->parent;
scsi_proc_hostdir_rm(shost->hostt);
if (shost->ehandler)
kthread_stop(shost->ehandler);
if (shost->work_q)
......
......@@ -580,8 +580,7 @@ static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
break;
default:
scp->result = ((DRIVER_INVALID|SUGGEST_ABORT)<<24) |
(DID_ABORT<<16);
scp->result = DRIVER_INVALID << 24 | DID_ABORT << 16;
break;
}
......
......@@ -2767,6 +2767,40 @@ static void ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt,
ibmvfc_init_tgt(tgt, job_step);
}
/* Defined in FC-LS */
static const struct {
int code;
int retry;
int logged_in;
} prli_rsp [] = {
{ 0, 1, 0 },
{ 1, 0, 1 },
{ 2, 1, 0 },
{ 3, 1, 0 },
{ 4, 0, 0 },
{ 5, 0, 0 },
{ 6, 0, 1 },
{ 7, 0, 0 },
{ 8, 1, 0 },
};
/**
* ibmvfc_get_prli_rsp - Find PRLI response index
* @flags: PRLI response flags
*
**/
static int ibmvfc_get_prli_rsp(u16 flags)
{
int i;
int code = (flags & 0x0f00) >> 8;
for (i = 0; i < ARRAY_SIZE(prli_rsp); i++)
if (prli_rsp[i].code == code)
return i;
return 0;
}
/**
* ibmvfc_tgt_prli_done - Completion handler for Process Login
* @evt: ibmvfc event struct
......@@ -2777,15 +2811,36 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt)
struct ibmvfc_target *tgt = evt->tgt;
struct ibmvfc_host *vhost = evt->vhost;
struct ibmvfc_process_login *rsp = &evt->xfer_iu->prli;
struct ibmvfc_prli_svc_parms *parms = &rsp->parms;
u32 status = rsp->common.status;
int index;
vhost->discovery_threads--;
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
switch (status) {
case IBMVFC_MAD_SUCCESS:
tgt_dbg(tgt, "Process Login succeeded\n");
tgt->need_login = 0;
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_ADD_RPORT);
tgt_dbg(tgt, "Process Login succeeded: %X %02X %04X\n",
parms->type, parms->flags, parms->service_parms);
if (parms->type == IBMVFC_SCSI_FCP_TYPE) {
index = ibmvfc_get_prli_rsp(parms->flags);
if (prli_rsp[index].logged_in) {
if (parms->flags & IBMVFC_PRLI_EST_IMG_PAIR) {
tgt->need_login = 0;
tgt->ids.roles = 0;
if (parms->service_parms & IBMVFC_PRLI_TARGET_FUNC)
tgt->ids.roles |= FC_PORT_ROLE_FCP_TARGET;
if (parms->service_parms & IBMVFC_PRLI_INITIATOR_FUNC)
tgt->ids.roles |= FC_PORT_ROLE_FCP_INITIATOR;
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_ADD_RPORT);
} else
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
} else if (prli_rsp[index].retry)
ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli);
else
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
} else
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
break;
case IBMVFC_MAD_DRIVER_FAILED:
break;
......@@ -2874,7 +2929,6 @@ static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt)
tgt->ids.node_name = wwn_to_u64(rsp->service_parms.node_name);
tgt->ids.port_name = wwn_to_u64(rsp->service_parms.port_name);
tgt->ids.port_id = tgt->scsi_id;
tgt->ids.roles = FC_PORT_ROLE_FCP_TARGET;
memcpy(&tgt->service_parms, &rsp->service_parms,
sizeof(tgt->service_parms));
memcpy(&tgt->service_parms_change, &rsp->service_parms_change,
......
......@@ -152,13 +152,13 @@ module_param_named(log_level, ipr_log_level, uint, 0);
MODULE_PARM_DESC(log_level, "Set to 0 - 4 for increasing verbosity of device driver");
module_param_named(testmode, ipr_testmode, int, 0);
MODULE_PARM_DESC(testmode, "DANGEROUS!!! Allows unsupported configurations");
module_param_named(fastfail, ipr_fastfail, int, 0);
module_param_named(fastfail, ipr_fastfail, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(fastfail, "Reduce timeouts and retries");
module_param_named(transop_timeout, ipr_transop_timeout, int, 0);
MODULE_PARM_DESC(transop_timeout, "Time in seconds to wait for adapter to come operational (default: 300)");
module_param_named(enable_cache, ipr_enable_cache, int, 0);
MODULE_PARM_DESC(enable_cache, "Enable adapter's non-volatile write cache (default: 1)");
module_param_named(debug, ipr_debug, int, 0);
module_param_named(debug, ipr_debug, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Enable device driver debugging logging. Set to 1 to enable. (default: 0)");
module_param_named(dual_ioa_raid, ipr_dual_ioa_raid, int, 0);
MODULE_PARM_DESC(dual_ioa_raid, "Enable dual adapter RAID support. Set to 1 to enable. (default: 1)");
......@@ -354,6 +354,8 @@ struct ipr_error_table_t ipr_error_table[] = {
"9076: Configuration error, missing remote IOA"},
{0x06679100, 0, IPR_DEFAULT_LOG_LEVEL,
"4050: Enclosure does not support a required multipath function"},
{0x06690000, 0, IPR_DEFAULT_LOG_LEVEL,
"4070: Logically bad block written on device"},
{0x06690200, 0, IPR_DEFAULT_LOG_LEVEL,
"9041: Array protection temporarily suspended"},
{0x06698200, 0, IPR_DEFAULT_LOG_LEVEL,
......@@ -7147,6 +7149,7 @@ static void ipr_free_all_resources(struct ipr_ioa_cfg *ioa_cfg)
ENTER;
free_irq(pdev->irq, ioa_cfg);
pci_disable_msi(pdev);
iounmap(ioa_cfg->hdw_dma_regs);
pci_release_regions(pdev);
ipr_free_mem(ioa_cfg);
......@@ -7432,6 +7435,11 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
goto out;
}
if (!(rc = pci_enable_msi(pdev)))
dev_info(&pdev->dev, "MSI enabled\n");
else if (ipr_debug)
dev_info(&pdev->dev, "Cannot enable MSI\n");
dev_info(&pdev->dev, "Found IOA with IRQ: %d\n", pdev->irq);
host = scsi_host_alloc(&driver_template, sizeof(*ioa_cfg));
......@@ -7574,6 +7582,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
out_scsi_host_put:
scsi_host_put(host);
out_disable:
pci_disable_msi(pdev);
pci_disable_device(pdev);
goto out;
}
......
......@@ -37,8 +37,8 @@
/*
* Literals
*/
#define IPR_DRIVER_VERSION "2.4.1"
#define IPR_DRIVER_DATE "(April 24, 2007)"
#define IPR_DRIVER_VERSION "2.4.2"
#define IPR_DRIVER_DATE "(January 21, 2009)"
/*
* IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
......
......@@ -1004,8 +1004,7 @@ static int __ips_eh_reset(struct scsi_cmnd *SC)
DEBUG_VAR(1, "(%s%d) Failing active commands", ips_name, ha->host_num);
while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
scb->scsi_cmd->result =
(DID_RESET << 16) | (SUGGEST_RETRY << 24);
scb->scsi_cmd->result = DID_RESET << 16;
scb->scsi_cmd->scsi_done(scb->scsi_cmd);
ips_freescb(ha, scb);
}
......
......@@ -48,13 +48,6 @@ MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, "
"Alex Aizman <itn780@yahoo.com>");
MODULE_DESCRIPTION("iSCSI/TCP data-path");
MODULE_LICENSE("GPL");
#undef DEBUG_TCP
#ifdef DEBUG_TCP
#define debug_tcp(fmt...) printk(KERN_INFO "tcp: " fmt)
#else
#define debug_tcp(fmt...)
#endif
static struct scsi_transport_template *iscsi_sw_tcp_scsi_transport;
static struct scsi_host_template iscsi_sw_tcp_sht;
......@@ -63,6 +56,21 @@ static struct iscsi_transport iscsi_sw_tcp_transport;
static unsigned int iscsi_max_lun = 512;
module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
static int iscsi_sw_tcp_dbg;
module_param_named(debug_iscsi_tcp, iscsi_sw_tcp_dbg, int,
S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug_iscsi_tcp, "Turn on debugging for iscsi_tcp module "
"Set to 1 to turn on, and zero to turn off. Default is off.");
#define ISCSI_SW_TCP_DBG(_conn, dbg_fmt, arg...) \
do { \
if (iscsi_sw_tcp_dbg) \
iscsi_conn_printk(KERN_INFO, _conn, \
"%s " dbg_fmt, \
__func__, ##arg); \
} while (0);
/**
* iscsi_sw_tcp_recv - TCP receive in sendfile fashion
* @rd_desc: read descriptor
......@@ -77,7 +85,7 @@ static int iscsi_sw_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
unsigned int consumed, total_consumed = 0;
int status;
debug_tcp("in %d bytes\n", skb->len - offset);
ISCSI_SW_TCP_DBG(conn, "in %d bytes\n", skb->len - offset);
do {
status = 0;
......@@ -86,7 +94,8 @@ static int iscsi_sw_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
total_consumed += consumed;
} while (consumed != 0 && status != ISCSI_TCP_SKB_DONE);
debug_tcp("read %d bytes status %d\n", skb->len - offset, status);
ISCSI_SW_TCP_DBG(conn, "read %d bytes status %d\n",
skb->len - offset, status);
return total_consumed;
}
......@@ -131,7 +140,8 @@ static void iscsi_sw_tcp_state_change(struct sock *sk)
if ((sk->sk_state == TCP_CLOSE_WAIT ||
sk->sk_state == TCP_CLOSE) &&
!atomic_read(&sk->sk_rmem_alloc)) {
debug_tcp("iscsi_tcp_state_change: TCP_CLOSE|TCP_CLOSE_WAIT\n");
ISCSI_SW_TCP_DBG(conn, "iscsi_tcp_state_change: "
"TCP_CLOSE|TCP_CLOSE_WAIT\n");
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
}
......@@ -155,8 +165,8 @@ static void iscsi_sw_tcp_write_space(struct sock *sk)
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
tcp_sw_conn->old_write_space(sk);
debug_tcp("iscsi_write_space: cid %d\n", conn->id);
scsi_queue_work(conn->session->host, &conn->xmitwork);
ISCSI_SW_TCP_DBG(conn, "iscsi_write_space\n");
iscsi_conn_queue_work(conn);
}
static void iscsi_sw_tcp_conn_set_callbacks(struct iscsi_conn *conn)
......@@ -283,7 +293,7 @@ static int iscsi_sw_tcp_xmit(struct iscsi_conn *conn)
}
}
debug_tcp("xmit %d bytes\n", consumed);
ISCSI_SW_TCP_DBG(conn, "xmit %d bytes\n", consumed);
conn->txdata_octets += consumed;
return consumed;
......@@ -291,7 +301,7 @@ static int iscsi_sw_tcp_xmit(struct iscsi_conn *conn)
error:
/* Transmit error. We could initiate error recovery
* here. */
debug_tcp("Error sending PDU, errno=%d\n", rc);
ISCSI_SW_TCP_DBG(conn, "Error sending PDU, errno=%d\n", rc);
iscsi_conn_failure(conn, rc);
return -EIO;
}
......@@ -334,9 +344,10 @@ static int iscsi_sw_tcp_send_hdr_done(struct iscsi_tcp_conn *tcp_conn,
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
tcp_sw_conn->out.segment = tcp_sw_conn->out.data_segment;
debug_tcp("Header done. Next segment size %u total_size %u\n",
tcp_sw_conn->out.segment.size,
tcp_sw_conn->out.segment.total_size);
ISCSI_SW_TCP_DBG(tcp_conn->iscsi_conn,
"Header done. Next segment size %u total_size %u\n",
tcp_sw_conn->out.segment.size,
tcp_sw_conn->out.segment.total_size);
return 0;
}
......@@ -346,8 +357,8 @@ static void iscsi_sw_tcp_send_hdr_prep(struct iscsi_conn *conn, void *hdr,
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
debug_tcp("%s(%p%s)\n", __func__, tcp_conn,
conn->hdrdgst_en? ", digest enabled" : "");
ISCSI_SW_TCP_DBG(conn, "%s\n", conn->hdrdgst_en ?
"digest enabled" : "digest disabled");
/* Clear the data segment - needs to be filled in by the
* caller using iscsi_tcp_send_data_prep() */
......@@ -389,9 +400,9 @@ iscsi_sw_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg,
struct hash_desc *tx_hash = NULL;
unsigned int hdr_spec_len;
debug_tcp("%s(%p, offset=%d, datalen=%d%s)\n", __func__,
tcp_conn, offset, len,
conn->datadgst_en? ", digest enabled" : "");
ISCSI_SW_TCP_DBG(conn, "offset=%d, datalen=%d %s\n", offset, len,
conn->datadgst_en ?
"digest enabled" : "digest disabled");
/* Make sure the datalen matches what the caller
said he would send. */
......@@ -415,8 +426,8 @@ iscsi_sw_tcp_send_linear_data_prep(struct iscsi_conn *conn, void *data,
struct hash_desc *tx_hash = NULL;
unsigned int hdr_spec_len;
debug_tcp("%s(%p, datalen=%d%s)\n", __func__, tcp_conn, len,
conn->datadgst_en? ", digest enabled" : "");
ISCSI_SW_TCP_DBG(conn, "datalen=%zd %s\n", len, conn->datadgst_en ?
"digest enabled" : "digest disabled");
/* Make sure the datalen matches what the caller
said he would send. */
......@@ -754,8 +765,7 @@ iscsi_sw_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn,
static struct iscsi_cls_session *
iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
uint16_t qdepth, uint32_t initial_cmdsn,
uint32_t *hostno)
uint16_t qdepth, uint32_t initial_cmdsn)
{
struct iscsi_cls_session *cls_session;
struct iscsi_session *session;
......@@ -766,10 +776,11 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
return NULL;
}
shost = iscsi_host_alloc(&iscsi_sw_tcp_sht, 0, qdepth);
shost = iscsi_host_alloc(&iscsi_sw_tcp_sht, 0, 1);
if (!shost)
return NULL;
shost->transportt = iscsi_sw_tcp_scsi_transport;
shost->cmd_per_lun = qdepth;
shost->max_lun = iscsi_max_lun;
shost->max_id = 0;
shost->max_channel = 0;
......@@ -777,7 +788,6 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
if (iscsi_host_add(shost, NULL))
goto free_host;
*hostno = shost->host_no;
cls_session = iscsi_session_setup(&iscsi_sw_tcp_transport, shost,
cmds_max,
......@@ -813,6 +823,12 @@ static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session)
iscsi_host_free(shost);
}
static int iscsi_sw_tcp_slave_alloc(struct scsi_device *sdev)
{
set_bit(QUEUE_FLAG_BIDI, &sdev->request_queue->queue_flags);
return 0;
}
static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev)
{
blk_queue_bounce_limit(sdev->request_queue, BLK_BOUNCE_ANY);
......@@ -833,6 +849,7 @@ static struct scsi_host_template iscsi_sw_tcp_sht = {
.eh_device_reset_handler= iscsi_eh_device_reset,
.eh_target_reset_handler= iscsi_eh_target_reset,
.use_clustering = DISABLE_CLUSTERING,
.slave_alloc = iscsi_sw_tcp_slave_alloc,
.slave_configure = iscsi_sw_tcp_slave_configure,
.proc_name = "iscsi_tcp",
.this_id = -1,
......
......@@ -281,7 +281,7 @@ static void fc_exch_release(struct fc_exch *ep)
ep->destructor(&ep->seq, ep->arg);
if (ep->lp->tt.exch_put)
ep->lp->tt.exch_put(ep->lp, mp, ep->xid);
WARN_ON(!ep->esb_stat & ESB_ST_COMPLETE);
WARN_ON(!(ep->esb_stat & ESB_ST_COMPLETE));
mempool_free(ep, mp->ep_pool);
}
}
......@@ -489,7 +489,7 @@ static u16 fc_em_alloc_xid(struct fc_exch_mgr *mp, const struct fc_frame *fp)
struct fc_exch *ep = NULL;
if (mp->max_read) {
if (fc_frame_is_read(fp)) {
if (fc_fcp_is_read(fr_fsp(fp))) {
min = mp->min_xid;
max = mp->max_read;
plast = &mp->last_read;
......@@ -1841,6 +1841,8 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp,
fc_exch_setup_hdr(ep, fp, ep->f_ctl);
sp->cnt++;
fc_fcp_ddp_setup(fr_fsp(fp), ep->xid);
if (unlikely(lp->tt.frame_send(lp, fp)))
goto err;
......
......@@ -259,11 +259,61 @@ static void fc_fcp_retry_cmd(struct fc_fcp_pkt *fsp)
}
fsp->state &= ~FC_SRB_ABORT_PENDING;
fsp->io_status = SUGGEST_RETRY << 24;
fsp->io_status = 0;
fsp->status_code = FC_ERROR;
fc_fcp_complete_locked(fsp);
}
/*
* fc_fcp_ddp_setup - calls to LLD's ddp_setup to set up DDP
* transfer for a read I/O indicated by the fc_fcp_pkt.
* @fsp: ptr to the fc_fcp_pkt
*
* This is called in exch_seq_send() when we have a newly allocated
* exchange with a valid exchange id to setup ddp.
*
* returns: none
*/
void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid)
{
struct fc_lport *lp;
if (!fsp)
return;
lp = fsp->lp;
if ((fsp->req_flags & FC_SRB_READ) &&
(lp->lro_enabled) && (lp->tt.ddp_setup)) {
if (lp->tt.ddp_setup(lp, xid, scsi_sglist(fsp->cmd),
scsi_sg_count(fsp->cmd)))
fsp->xfer_ddp = xid;
}
}
EXPORT_SYMBOL(fc_fcp_ddp_setup);
/*
* fc_fcp_ddp_done - calls to LLD's ddp_done to release any
* DDP related resources for this I/O if it is initialized
* as a ddp transfer
* @fsp: ptr to the fc_fcp_pkt
*
* returns: none
*/
static void fc_fcp_ddp_done(struct fc_fcp_pkt *fsp)
{
struct fc_lport *lp;
if (!fsp)
return;
lp = fsp->lp;
if (fsp->xfer_ddp && lp->tt.ddp_done) {
fsp->xfer_len = lp->tt.ddp_done(lp, fsp->xfer_ddp);
fsp->xfer_ddp = 0;
}
}
/*
* Receive SCSI data from target.
* Called after receiving solicited data.
......@@ -289,6 +339,9 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
len = fr_len(fp) - sizeof(*fh);
buf = fc_frame_payload_get(fp, 0);
/* if this I/O is ddped, update xfer len */
fc_fcp_ddp_done(fsp);
if (offset + len > fsp->data_len) {
/* this should never happen */
if ((fr_flags(fp) & FCPHF_CRC_UNCHECKED) &&
......@@ -435,7 +488,13 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
* burst length (t_blen) to seq_blen, otherwise set t_blen
* to max FC frame payload previously set in fsp->max_payload.
*/
t_blen = lp->seq_offload ? seq_blen : fsp->max_payload;
t_blen = fsp->max_payload;
if (lp->seq_offload) {
t_blen = min(seq_blen, (size_t)lp->lso_max);
FC_DEBUG_FCP("fsp=%p:lso:blen=%zx lso_max=0x%x t_blen=%zx\n",
fsp, seq_blen, lp->lso_max, t_blen);
}
WARN_ON(t_blen < FC_MIN_MAX_PAYLOAD);
if (t_blen > 512)
t_blen &= ~(512 - 1); /* round down to block size */
......@@ -744,6 +803,9 @@ static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
fsp->scsi_comp_flags = flags;
expected_len = fsp->data_len;
/* if ddp, update xfer len */
fc_fcp_ddp_done(fsp);
if (unlikely((flags & ~FCP_CONF_REQ) || fc_rp->fr_status)) {
rp_ex = (void *)(fc_rp + 1);
if (flags & (FCP_RSP_LEN_VAL | FCP_SNS_LEN_VAL)) {
......@@ -859,7 +921,7 @@ static void fc_fcp_complete_locked(struct fc_fcp_pkt *fsp)
(!(fsp->scsi_comp_flags & FCP_RESID_UNDER) ||
fsp->xfer_len < fsp->data_len - fsp->scsi_resid)) {
fsp->status_code = FC_DATA_UNDRUN;
fsp->io_status = SUGGEST_RETRY << 24;
fsp->io_status = 0;
}
}
......@@ -1006,7 +1068,7 @@ static int fc_fcp_cmd_send(struct fc_lport *lp, struct fc_fcp_pkt *fsp,
}
memcpy(fc_frame_payload_get(fp, len), &fsp->cdb_cmd, len);
fr_cmd(fp) = fsp->cmd;
fr_fsp(fp) = fsp;
rport = fsp->rport;
fsp->max_payload = rport->maxframe_size;
rp = rport->dd_data;
......@@ -1267,7 +1329,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp)
rp = rport->dd_data;
if (!fsp->seq_ptr || rp->rp_state != RPORT_ST_READY) {
fsp->status_code = FC_HRD_ERROR;
fsp->io_status = SUGGEST_RETRY << 24;
fsp->io_status = 0;
fc_fcp_complete_locked(fsp);
return;
}
......@@ -1740,6 +1802,9 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
struct fc_lport *lp;
unsigned long flags;
/* release outstanding ddp context */
fc_fcp_ddp_done(fsp);
fsp->state |= FC_SRB_COMPL;
if (!(fsp->state & FC_SRB_FCP_PROCESSING_TMO)) {
spin_unlock_bh(&fsp->scsi_pkt_lock);
......
......@@ -762,10 +762,11 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
remote_wwpn = get_unaligned_be64(&flp->fl_wwpn);
if (remote_wwpn == lport->wwpn) {
FC_DBG("FLOGI from port with same WWPN %llx "
"possible configuration error\n", remote_wwpn);
"possible configuration error\n",
(unsigned long long)remote_wwpn);
goto out;
}
FC_DBG("FLOGI from port WWPN %llx\n", remote_wwpn);
FC_DBG("FLOGI from port WWPN %llx\n", (unsigned long long)remote_wwpn);
/*
* XXX what is the right thing to do for FIDs?
......
......@@ -988,7 +988,7 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport,
switch (rdata->rp_state) {
case RPORT_ST_INIT:
FC_DEBUG_RPORT("incoming PLOGI from %6x wwpn %llx state INIT "
"- reject\n", sid, wwpn);
"- reject\n", sid, (unsigned long long)wwpn);
reject = ELS_RJT_UNSUP;
break;
case RPORT_ST_PLOGI:
......
此差异已折叠。
此差异已折叠。
......@@ -1132,7 +1132,7 @@ lpfc_debugfs_dumpDataDif_release(struct inode *inode, struct file *file)
}
#undef lpfc_debugfs_op_disc_trc
static struct file_operations lpfc_debugfs_op_disc_trc = {
static const struct file_operations lpfc_debugfs_op_disc_trc = {
.owner = THIS_MODULE,
.open = lpfc_debugfs_disc_trc_open,
.llseek = lpfc_debugfs_lseek,
......@@ -1141,7 +1141,7 @@ static struct file_operations lpfc_debugfs_op_disc_trc = {
};
#undef lpfc_debugfs_op_nodelist
static struct file_operations lpfc_debugfs_op_nodelist = {
static const struct file_operations lpfc_debugfs_op_nodelist = {
.owner = THIS_MODULE,
.open = lpfc_debugfs_nodelist_open,
.llseek = lpfc_debugfs_lseek,
......@@ -1150,7 +1150,7 @@ static struct file_operations lpfc_debugfs_op_nodelist = {
};
#undef lpfc_debugfs_op_hbqinfo
static struct file_operations lpfc_debugfs_op_hbqinfo = {
static const struct file_operations lpfc_debugfs_op_hbqinfo = {
.owner = THIS_MODULE,
.open = lpfc_debugfs_hbqinfo_open,
.llseek = lpfc_debugfs_lseek,
......@@ -1159,7 +1159,7 @@ static struct file_operations lpfc_debugfs_op_hbqinfo = {
};
#undef lpfc_debugfs_op_dumpHBASlim
static struct file_operations lpfc_debugfs_op_dumpHBASlim = {
static const struct file_operations lpfc_debugfs_op_dumpHBASlim = {
.owner = THIS_MODULE,
.open = lpfc_debugfs_dumpHBASlim_open,
.llseek = lpfc_debugfs_lseek,
......@@ -1168,7 +1168,7 @@ static struct file_operations lpfc_debugfs_op_dumpHBASlim = {
};
#undef lpfc_debugfs_op_dumpHostSlim
static struct file_operations lpfc_debugfs_op_dumpHostSlim = {
static const struct file_operations lpfc_debugfs_op_dumpHostSlim = {
.owner = THIS_MODULE,
.open = lpfc_debugfs_dumpHostSlim_open,
.llseek = lpfc_debugfs_lseek,
......@@ -1177,7 +1177,7 @@ static struct file_operations lpfc_debugfs_op_dumpHostSlim = {
};
#undef lpfc_debugfs_op_dumpData
static struct file_operations lpfc_debugfs_op_dumpData = {
static const struct file_operations lpfc_debugfs_op_dumpData = {
.owner = THIS_MODULE,
.open = lpfc_debugfs_dumpData_open,
.llseek = lpfc_debugfs_lseek,
......@@ -1187,7 +1187,7 @@ static struct file_operations lpfc_debugfs_op_dumpData = {
};
#undef lpfc_debugfs_op_dumpDif
static struct file_operations lpfc_debugfs_op_dumpDif = {
static const struct file_operations lpfc_debugfs_op_dumpDif = {
.owner = THIS_MODULE,
.open = lpfc_debugfs_dumpDif_open,
.llseek = lpfc_debugfs_lseek,
......@@ -1197,7 +1197,7 @@ static struct file_operations lpfc_debugfs_op_dumpDif = {
};
#undef lpfc_debugfs_op_slow_ring_trc
static struct file_operations lpfc_debugfs_op_slow_ring_trc = {
static const struct file_operations lpfc_debugfs_op_slow_ring_trc = {
.owner = THIS_MODULE,
.open = lpfc_debugfs_slow_ring_trc_open,
.llseek = lpfc_debugfs_lseek,
......
......@@ -1357,7 +1357,7 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,
scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
0x10, 0x1);
cmd->result = (DRIVER_SENSE|SUGGEST_DIE) << 24
cmd->result = DRIVER_SENSE << 24
| ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION);
phba->bg_guard_err_cnt++;
printk(KERN_ERR "BLKGRD: guard_tag error\n");
......@@ -1368,7 +1368,7 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,
scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
0x10, 0x3);
cmd->result = (DRIVER_SENSE|SUGGEST_DIE) << 24
cmd->result = DRIVER_SENSE << 24
| ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION);
phba->bg_reftag_err_cnt++;
......@@ -1380,7 +1380,7 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,
scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
0x10, 0x2);
cmd->result = (DRIVER_SENSE|SUGGEST_DIE) << 24
cmd->result = DRIVER_SENSE << 24
| ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION);
phba->bg_apptag_err_cnt++;
......
#
# Kernel configuration file for the MPT2SAS
#
# This code is based on drivers/scsi/mpt2sas/Kconfig
# Copyright (C) 2007-2008 LSI Corporation
# (mailto:DL-MPTFusionLinux@lsi.com)
# 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.
# NO WARRANTY
# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
# solely responsible for determining the appropriateness of using and
# distributing the Program and assumes all risks associated with its
# exercise of rights under this Agreement, including but not limited to
# the risks and costs of program errors, damage to or loss of data,
# programs or equipment, and unavailability or interruption of operations.
# DISCLAIMER OF LIABILITY
# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
config SCSI_MPT2SAS
tristate "LSI MPT Fusion SAS 2.0 Device Driver"
depends on PCI && SCSI
select SCSI_SAS_ATTRS
---help---
This driver supports PCI-Express SAS 6Gb/s Host Adapters.
config SCSI_MPT2SAS_MAX_SGE
int "LSI MPT Fusion Max number of SG Entries (16 - 128)"
depends on PCI && SCSI && SCSI_MPT2SAS
default "128"
range 16 128
---help---
This option allows you to specify the maximum number of scatter-
gather entries per I/O. The driver default is 128, which matches
SAFE_PHYS_SEGMENTS. However, it may decreased down to 16.
Decreasing this parameter will reduce memory requirements
on a per controller instance.
config SCSI_MPT2SAS_LOGGING
bool "LSI MPT Fusion logging facility"
depends on PCI && SCSI && SCSI_MPT2SAS
---help---
This turns on a logging facility.
# mpt2sas makefile
obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas.o
mpt2sas-y += mpt2sas_base.o \
mpt2sas_config.o \
mpt2sas_scsih.o \
mpt2sas_transport.o \
mpt2sas_ctl.o
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
* Copyright (c) 2000-2007 LSI Corporation.
*
*
* Name: mpi2_type.h
* Title: MPI basic type definitions
* Creation Date: August 16, 2006
*
* mpi2_type.h Version: 02.00.00
*
* Version History
* ---------------
*
* Date Version Description
* -------- -------- ------------------------------------------------------
* 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
* --------------------------------------------------------------------------
*/
#ifndef MPI2_TYPE_H
#define MPI2_TYPE_H
/*******************************************************************************
* Define MPI2_POINTER if it hasn't already been defined. By default
* MPI2_POINTER is defined to be a near pointer. MPI2_POINTER can be defined as
* a far pointer by defining MPI2_POINTER as "far *" before this header file is
* included.
*/
#ifndef MPI2_POINTER
#define MPI2_POINTER *
#endif
/* the basic types may have already been included by mpi_type.h */
#ifndef MPI_TYPE_H
/*****************************************************************************
*
* Basic Types
*
*****************************************************************************/
typedef u8 U8;
typedef __le16 U16;
typedef __le32 U32;
typedef __le64 U64 __attribute__((aligned(4)));
/*****************************************************************************
*
* Pointer Types
*
*****************************************************************************/
typedef U8 *PU8;
typedef U16 *PU16;
typedef U32 *PU32;
typedef U64 *PU64;
#endif
#endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册