mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 13:00:54 +07:00
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 ...
This commit is contained in:
commit
d54b3538b0
@ -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
|
||||
|
198
Documentation/scsi/osd.txt
Normal file
198
Documentation/scsi/osd.txt
Normal file
@ -0,0 +1,198 @@
|
||||
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
|
10
MAINTAINERS
10
MAINTAINERS
@ -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 @@
|
||||
*
|
||||
* Error Recovery Procedures (ERP).
|
||||
*
|
||||
* Copyright IBM Corporation 2002, 2008
|
||||
* Copyright IBM Corporation 2002, 2009
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "zfcp"
|
||||
@ -55,7 +55,7 @@ enum zfcp_erp_act_result {
|
||||
|
||||
static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask)
|
||||
{
|
||||
zfcp_erp_modify_adapter_status(adapter, 15, NULL,
|
||||
zfcp_erp_modify_adapter_status(adapter, "erablk1", NULL,
|
||||
ZFCP_STATUS_COMMON_UNBLOCKED | mask,
|
||||
ZFCP_CLEAR);
|
||||
}
|
||||
@ -75,9 +75,9 @@ static void zfcp_erp_action_ready(struct zfcp_erp_action *act)
|
||||
struct zfcp_adapter *adapter = act->adapter;
|
||||
|
||||
list_move(&act->list, &act->adapter->erp_ready_head);
|
||||
zfcp_rec_dbf_event_action(146, act);
|
||||
zfcp_rec_dbf_event_action("erardy1", act);
|
||||
up(&adapter->erp_ready_sem);
|
||||
zfcp_rec_dbf_event_thread(2, adapter);
|
||||
zfcp_rec_dbf_event_thread("erardy2", adapter);
|
||||
}
|
||||
|
||||
static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act)
|
||||
@ -208,7 +208,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
|
||||
|
||||
static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
|
||||
struct zfcp_port *port,
|
||||
struct zfcp_unit *unit, u8 id, void *ref)
|
||||
struct zfcp_unit *unit, char *id, void *ref)
|
||||
{
|
||||
int retval = 1, need;
|
||||
struct zfcp_erp_action *act = NULL;
|
||||
@ -228,7 +228,7 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
|
||||
++adapter->erp_total_count;
|
||||
list_add_tail(&act->list, &adapter->erp_ready_head);
|
||||
up(&adapter->erp_ready_sem);
|
||||
zfcp_rec_dbf_event_thread(1, adapter);
|
||||
zfcp_rec_dbf_event_thread("eracte1", adapter);
|
||||
retval = 0;
|
||||
out:
|
||||
zfcp_rec_dbf_event_trigger(id, ref, want, need, act,
|
||||
@ -237,13 +237,14 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
|
||||
}
|
||||
|
||||
static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
|
||||
int clear_mask, u8 id, void *ref)
|
||||
int clear_mask, char *id, void *ref)
|
||||
{
|
||||
zfcp_erp_adapter_block(adapter, clear_mask);
|
||||
zfcp_scsi_schedule_rports_block(adapter);
|
||||
|
||||
/* ensure propagation of failed status to new devices */
|
||||
if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
|
||||
zfcp_erp_adapter_failed(adapter, 13, NULL);
|
||||
zfcp_erp_adapter_failed(adapter, "erareo1", NULL);
|
||||
return -EIO;
|
||||
}
|
||||
return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
|
||||
@ -258,7 +259,7 @@ static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
|
||||
* @ref: Reference for debug trace event.
|
||||
*/
|
||||
void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
|
||||
u8 id, void *ref)
|
||||
char *id, void *ref)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
@ -277,7 +278,7 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
|
||||
* @ref: Reference for debug trace event.
|
||||
*/
|
||||
void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear,
|
||||
u8 id, void *ref)
|
||||
char *id, void *ref)
|
||||
{
|
||||
int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
|
||||
zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref);
|
||||
@ -290,7 +291,8 @@ void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear,
|
||||
* @id: Id for debug trace event.
|
||||
* @ref: Reference for debug trace event.
|
||||
*/
|
||||
void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, u8 id, void *ref)
|
||||
void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id,
|
||||
void *ref)
|
||||
{
|
||||
int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
|
||||
zfcp_erp_port_reopen(port, clear | flags, id, ref);
|
||||
@ -303,7 +305,8 @@ void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, u8 id, void *ref)
|
||||
* @id: Id for debug trace event.
|
||||
* @ref: Reference for debug trace event.
|
||||
*/
|
||||
void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, u8 id, void *ref)
|
||||
void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, char *id,
|
||||
void *ref)
|
||||
{
|
||||
int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
|
||||
zfcp_erp_unit_reopen(unit, clear | flags, id, ref);
|
||||
@ -311,15 +314,16 @@ void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, u8 id, void *ref)
|
||||
|
||||
static void zfcp_erp_port_block(struct zfcp_port *port, int clear)
|
||||
{
|
||||
zfcp_erp_modify_port_status(port, 17, NULL,
|
||||
zfcp_erp_modify_port_status(port, "erpblk1", NULL,
|
||||
ZFCP_STATUS_COMMON_UNBLOCKED | clear,
|
||||
ZFCP_CLEAR);
|
||||
}
|
||||
|
||||
static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port,
|
||||
int clear, u8 id, void *ref)
|
||||
int clear, char *id, void *ref)
|
||||
{
|
||||
zfcp_erp_port_block(port, clear);
|
||||
zfcp_scsi_schedule_rport_block(port);
|
||||
|
||||
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
|
||||
return;
|
||||
@ -334,7 +338,7 @@ static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port,
|
||||
* @id: Id for debug trace event.
|
||||
* @ref: Reference for debug trace event.
|
||||
*/
|
||||
void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, u8 id,
|
||||
void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id,
|
||||
void *ref)
|
||||
{
|
||||
unsigned long flags;
|
||||
@ -347,14 +351,15 @@ void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, u8 id,
|
||||
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
|
||||
}
|
||||
|
||||
static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, u8 id,
|
||||
static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
|
||||
void *ref)
|
||||
{
|
||||
zfcp_erp_port_block(port, clear);
|
||||
zfcp_scsi_schedule_rport_block(port);
|
||||
|
||||
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
|
||||
/* ensure propagation of failed status to new devices */
|
||||
zfcp_erp_port_failed(port, 14, NULL);
|
||||
zfcp_erp_port_failed(port, "erpreo1", NULL);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -369,7 +374,7 @@ static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, u8 id,
|
||||
*
|
||||
* Returns 0 if recovery has been triggered, < 0 if not.
|
||||
*/
|
||||
int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, u8 id, void *ref)
|
||||
int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref)
|
||||
{
|
||||
unsigned long flags;
|
||||
int retval;
|
||||
@ -386,12 +391,12 @@ int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, u8 id, void *ref)
|
||||
|
||||
static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask)
|
||||
{
|
||||
zfcp_erp_modify_unit_status(unit, 19, NULL,
|
||||
zfcp_erp_modify_unit_status(unit, "erublk1", NULL,
|
||||
ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask,
|
||||
ZFCP_CLEAR);
|
||||
}
|
||||
|
||||
static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, u8 id,
|
||||
static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
|
||||
void *ref)
|
||||
{
|
||||
struct zfcp_adapter *adapter = unit->port->adapter;
|
||||
@ -411,7 +416,8 @@ static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, u8 id,
|
||||
* @clear_mask: specifies flags in unit status to be cleared
|
||||
* Return: 0 on success, < 0 on error
|
||||
*/
|
||||
void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, u8 id, void *ref)
|
||||
void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
|
||||
void *ref)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct zfcp_port *port = unit->port;
|
||||
@ -437,28 +443,28 @@ static int status_change_clear(unsigned long mask, atomic_t *status)
|
||||
static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
|
||||
{
|
||||
if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status))
|
||||
zfcp_rec_dbf_event_adapter(16, NULL, adapter);
|
||||
zfcp_rec_dbf_event_adapter("eraubl1", NULL, adapter);
|
||||
atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status);
|
||||
}
|
||||
|
||||
static void zfcp_erp_port_unblock(struct zfcp_port *port)
|
||||
{
|
||||
if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status))
|
||||
zfcp_rec_dbf_event_port(18, NULL, port);
|
||||
zfcp_rec_dbf_event_port("erpubl1", NULL, port);
|
||||
atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status);
|
||||
}
|
||||
|
||||
static void zfcp_erp_unit_unblock(struct zfcp_unit *unit)
|
||||
{
|
||||
if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))
|
||||
zfcp_rec_dbf_event_unit(20, NULL, unit);
|
||||
zfcp_rec_dbf_event_unit("eruubl1", NULL, unit);
|
||||
atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status);
|
||||
}
|
||||
|
||||
static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
|
||||
{
|
||||
list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
|
||||
zfcp_rec_dbf_event_action(145, erp_action);
|
||||
zfcp_rec_dbf_event_action("erator1", erp_action);
|
||||
}
|
||||
|
||||
static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
|
||||
@ -474,11 +480,11 @@ static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
|
||||
if (act->status & (ZFCP_STATUS_ERP_DISMISSED |
|
||||
ZFCP_STATUS_ERP_TIMEDOUT)) {
|
||||
act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
|
||||
zfcp_rec_dbf_event_action(142, act);
|
||||
zfcp_rec_dbf_event_action("erscf_1", act);
|
||||
act->fsf_req->erp_action = NULL;
|
||||
}
|
||||
if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
|
||||
zfcp_rec_dbf_event_action(143, act);
|
||||
zfcp_rec_dbf_event_action("erscf_2", act);
|
||||
if (act->fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED |
|
||||
ZFCP_STATUS_FSFREQ_DISMISSED))
|
||||
act->fsf_req = NULL;
|
||||
@ -530,7 +536,7 @@ static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action)
|
||||
}
|
||||
|
||||
static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
|
||||
int clear, u8 id, void *ref)
|
||||
int clear, char *id, void *ref)
|
||||
{
|
||||
struct zfcp_port *port;
|
||||
|
||||
@ -538,8 +544,8 @@ static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
|
||||
_zfcp_erp_port_reopen(port, clear, id, ref);
|
||||
}
|
||||
|
||||
static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear, u8 id,
|
||||
void *ref)
|
||||
static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear,
|
||||
char *id, void *ref)
|
||||
{
|
||||
struct zfcp_unit *unit;
|
||||
|
||||
@ -559,28 +565,28 @@ static void zfcp_erp_strategy_followup_actions(struct zfcp_erp_action *act)
|
||||
|
||||
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
|
||||
if (status == ZFCP_ERP_SUCCEEDED)
|
||||
_zfcp_erp_port_reopen_all(adapter, 0, 70, NULL);
|
||||
_zfcp_erp_port_reopen_all(adapter, 0, "ersfa_1", NULL);
|
||||
else
|
||||
_zfcp_erp_adapter_reopen(adapter, 0, 71, NULL);
|
||||
_zfcp_erp_adapter_reopen(adapter, 0, "ersfa_2", NULL);
|
||||
break;
|
||||
|
||||
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
|
||||
if (status == ZFCP_ERP_SUCCEEDED)
|
||||
_zfcp_erp_port_reopen(port, 0, 72, NULL);
|
||||
_zfcp_erp_port_reopen(port, 0, "ersfa_3", NULL);
|
||||
else
|
||||
_zfcp_erp_adapter_reopen(adapter, 0, 73, NULL);
|
||||
_zfcp_erp_adapter_reopen(adapter, 0, "ersfa_4", NULL);
|
||||
break;
|
||||
|
||||
case ZFCP_ERP_ACTION_REOPEN_PORT:
|
||||
if (status == ZFCP_ERP_SUCCEEDED)
|
||||
_zfcp_erp_unit_reopen_all(port, 0, 74, NULL);
|
||||
_zfcp_erp_unit_reopen_all(port, 0, "ersfa_5", NULL);
|
||||
else
|
||||
_zfcp_erp_port_forced_reopen(port, 0, 75, NULL);
|
||||
_zfcp_erp_port_forced_reopen(port, 0, "ersfa_6", NULL);
|
||||
break;
|
||||
|
||||
case ZFCP_ERP_ACTION_REOPEN_UNIT:
|
||||
if (status != ZFCP_ERP_SUCCEEDED)
|
||||
_zfcp_erp_port_reopen(unit->port, 0, 76, NULL);
|
||||
_zfcp_erp_port_reopen(unit->port, 0, "ersfa_7", NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -617,7 +623,7 @@ static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter)
|
||||
adapter->peer_d_id);
|
||||
if (IS_ERR(port)) /* error or port already attached */
|
||||
return;
|
||||
_zfcp_erp_port_reopen(port, 0, 150, NULL);
|
||||
_zfcp_erp_port_reopen(port, 0, "ereptp1", NULL);
|
||||
}
|
||||
|
||||
static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action)
|
||||
@ -640,9 +646,9 @@ static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action)
|
||||
return ZFCP_ERP_FAILED;
|
||||
}
|
||||
|
||||
zfcp_rec_dbf_event_thread_lock(6, adapter);
|
||||
zfcp_rec_dbf_event_thread_lock("erasfx1", adapter);
|
||||
down(&adapter->erp_ready_sem);
|
||||
zfcp_rec_dbf_event_thread_lock(7, adapter);
|
||||
zfcp_rec_dbf_event_thread_lock("erasfx2", adapter);
|
||||
if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT)
|
||||
break;
|
||||
|
||||
@ -681,9 +687,9 @@ static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act)
|
||||
if (ret)
|
||||
return ZFCP_ERP_FAILED;
|
||||
|
||||
zfcp_rec_dbf_event_thread_lock(8, adapter);
|
||||
zfcp_rec_dbf_event_thread_lock("erasox1", adapter);
|
||||
down(&adapter->erp_ready_sem);
|
||||
zfcp_rec_dbf_event_thread_lock(9, adapter);
|
||||
zfcp_rec_dbf_event_thread_lock("erasox2", adapter);
|
||||
if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
|
||||
return ZFCP_ERP_FAILED;
|
||||
|
||||
@ -705,60 +711,59 @@ static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act)
|
||||
return ZFCP_ERP_SUCCEEDED;
|
||||
}
|
||||
|
||||
static int zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *act,
|
||||
int close)
|
||||
static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act)
|
||||
{
|
||||
int retval = ZFCP_ERP_SUCCEEDED;
|
||||
struct zfcp_adapter *adapter = act->adapter;
|
||||
|
||||
if (close)
|
||||
goto close_only;
|
||||
|
||||
retval = zfcp_erp_adapter_strategy_open_qdio(act);
|
||||
if (retval != ZFCP_ERP_SUCCEEDED)
|
||||
goto failed_qdio;
|
||||
|
||||
retval = zfcp_erp_adapter_strategy_open_fsf(act);
|
||||
if (retval != ZFCP_ERP_SUCCEEDED)
|
||||
goto failed_openfcp;
|
||||
|
||||
atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &act->adapter->status);
|
||||
|
||||
return ZFCP_ERP_SUCCEEDED;
|
||||
|
||||
close_only:
|
||||
atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
|
||||
&act->adapter->status);
|
||||
|
||||
failed_openfcp:
|
||||
/* close queues to ensure that buffers are not accessed by adapter */
|
||||
zfcp_qdio_close(adapter);
|
||||
zfcp_fsf_req_dismiss_all(adapter);
|
||||
adapter->fsf_req_seq_no = 0;
|
||||
/* all ports and units are closed */
|
||||
zfcp_erp_modify_adapter_status(adapter, 24, NULL,
|
||||
zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL,
|
||||
ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
|
||||
failed_qdio:
|
||||
|
||||
atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
|
||||
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
|
||||
&act->adapter->status);
|
||||
return retval;
|
||||
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
|
||||
}
|
||||
|
||||
static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act)
|
||||
{
|
||||
struct zfcp_adapter *adapter = act->adapter;
|
||||
|
||||
if (zfcp_erp_adapter_strategy_open_qdio(act)) {
|
||||
atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
|
||||
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
|
||||
&adapter->status);
|
||||
return ZFCP_ERP_FAILED;
|
||||
}
|
||||
|
||||
if (zfcp_erp_adapter_strategy_open_fsf(act)) {
|
||||
zfcp_erp_adapter_strategy_close(act);
|
||||
return ZFCP_ERP_FAILED;
|
||||
}
|
||||
|
||||
atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &adapter->status);
|
||||
|
||||
return ZFCP_ERP_SUCCEEDED;
|
||||
}
|
||||
|
||||
static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *act)
|
||||
{
|
||||
int retval;
|
||||
struct zfcp_adapter *adapter = act->adapter;
|
||||
|
||||
zfcp_erp_adapter_strategy_generic(act, 1); /* close */
|
||||
if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
|
||||
return ZFCP_ERP_EXIT;
|
||||
if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN) {
|
||||
zfcp_erp_adapter_strategy_close(act);
|
||||
if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
|
||||
return ZFCP_ERP_EXIT;
|
||||
}
|
||||
|
||||
retval = zfcp_erp_adapter_strategy_generic(act, 0); /* open */
|
||||
|
||||
if (retval == ZFCP_ERP_FAILED)
|
||||
if (zfcp_erp_adapter_strategy_open(act)) {
|
||||
ssleep(8);
|
||||
return ZFCP_ERP_FAILED;
|
||||
}
|
||||
|
||||
return retval;
|
||||
return ZFCP_ERP_SUCCEEDED;
|
||||
}
|
||||
|
||||
static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act)
|
||||
@ -777,10 +782,7 @@ static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act)
|
||||
|
||||
static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port)
|
||||
{
|
||||
atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
|
||||
ZFCP_STATUS_PORT_PHYS_CLOSING |
|
||||
ZFCP_STATUS_PORT_INVALID_WWPN,
|
||||
&port->status);
|
||||
atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status);
|
||||
}
|
||||
|
||||
static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
|
||||
@ -836,7 +838,7 @@ static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act)
|
||||
struct zfcp_port *port = act->port;
|
||||
|
||||
if (port->wwpn != adapter->peer_wwpn) {
|
||||
zfcp_erp_port_failed(port, 25, NULL);
|
||||
zfcp_erp_port_failed(port, "eroptp1", NULL);
|
||||
return ZFCP_ERP_FAILED;
|
||||
}
|
||||
port->d_id = adapter->peer_d_id;
|
||||
@ -855,7 +857,7 @@ void zfcp_erp_port_strategy_open_lookup(struct work_struct *work)
|
||||
port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP;
|
||||
if (retval)
|
||||
zfcp_erp_notify(&port->erp_action, ZFCP_ERP_FAILED);
|
||||
|
||||
zfcp_port_put(port);
|
||||
}
|
||||
|
||||
static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
|
||||
@ -871,17 +873,15 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
|
||||
if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
|
||||
return zfcp_erp_open_ptp_port(act);
|
||||
if (!port->d_id) {
|
||||
queue_work(zfcp_data.work_queue, &port->gid_pn_work);
|
||||
zfcp_port_get(port);
|
||||
if (!queue_work(zfcp_data.work_queue,
|
||||
&port->gid_pn_work))
|
||||
zfcp_port_put(port);
|
||||
return ZFCP_ERP_CONTINUES;
|
||||
}
|
||||
case ZFCP_ERP_STEP_NAMESERVER_LOOKUP:
|
||||
if (!port->d_id) {
|
||||
if (p_status & (ZFCP_STATUS_PORT_INVALID_WWPN)) {
|
||||
zfcp_erp_port_failed(port, 26, NULL);
|
||||
return ZFCP_ERP_EXIT;
|
||||
}
|
||||
if (!port->d_id)
|
||||
return ZFCP_ERP_FAILED;
|
||||
}
|
||||
return zfcp_erp_port_strategy_open_port(act);
|
||||
|
||||
case ZFCP_ERP_STEP_PORT_OPENING:
|
||||
@ -995,7 +995,7 @@ static int zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result)
|
||||
"port 0x%016Lx\n",
|
||||
(unsigned long long)unit->fcp_lun,
|
||||
(unsigned long long)unit->port->wwpn);
|
||||
zfcp_erp_unit_failed(unit, 21, NULL);
|
||||
zfcp_erp_unit_failed(unit, "erusck1", NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1025,7 +1025,7 @@ static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result)
|
||||
dev_err(&port->adapter->ccw_device->dev,
|
||||
"ERP failed for remote port 0x%016Lx\n",
|
||||
(unsigned long long)port->wwpn);
|
||||
zfcp_erp_port_failed(port, 22, NULL);
|
||||
zfcp_erp_port_failed(port, "erpsck1", NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1052,7 +1052,7 @@ static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter,
|
||||
dev_err(&adapter->ccw_device->dev,
|
||||
"ERP cannot recover an error "
|
||||
"on the FCP device\n");
|
||||
zfcp_erp_adapter_failed(adapter, 23, NULL);
|
||||
zfcp_erp_adapter_failed(adapter, "erasck1", NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1117,7 +1117,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
|
||||
if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) {
|
||||
_zfcp_erp_adapter_reopen(adapter,
|
||||
ZFCP_STATUS_COMMON_ERP_FAILED,
|
||||
67, NULL);
|
||||
"ersscg1", NULL);
|
||||
return ZFCP_ERP_EXIT;
|
||||
}
|
||||
break;
|
||||
@ -1127,7 +1127,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
|
||||
if (zfcp_erp_strat_change_det(&port->status, erp_status)) {
|
||||
_zfcp_erp_port_reopen(port,
|
||||
ZFCP_STATUS_COMMON_ERP_FAILED,
|
||||
68, NULL);
|
||||
"ersscg2", NULL);
|
||||
return ZFCP_ERP_EXIT;
|
||||
}
|
||||
break;
|
||||
@ -1136,7 +1136,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
|
||||
if (zfcp_erp_strat_change_det(&unit->status, erp_status)) {
|
||||
_zfcp_erp_unit_reopen(unit,
|
||||
ZFCP_STATUS_COMMON_ERP_FAILED,
|
||||
69, NULL);
|
||||
"ersscg3", NULL);
|
||||
return ZFCP_ERP_EXIT;
|
||||
}
|
||||
break;
|
||||
@ -1155,7 +1155,7 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
|
||||
}
|
||||
|
||||
list_del(&erp_action->list);
|
||||
zfcp_rec_dbf_event_action(144, erp_action);
|
||||
zfcp_rec_dbf_event_action("eractd1", erp_action);
|
||||
|
||||
switch (erp_action->action) {
|
||||
case ZFCP_ERP_ACTION_REOPEN_UNIT:
|
||||
@ -1214,38 +1214,8 @@ static void zfcp_erp_schedule_work(struct zfcp_unit *unit)
|
||||
atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
|
||||
INIT_WORK(&p->work, zfcp_erp_scsi_scan);
|
||||
p->unit = unit;
|
||||
queue_work(zfcp_data.work_queue, &p->work);
|
||||
}
|
||||
|
||||
static void zfcp_erp_rport_register(struct zfcp_port *port)
|
||||
{
|
||||
struct fc_rport_identifiers ids;
|
||||
ids.node_name = port->wwnn;
|
||||
ids.port_name = port->wwpn;
|
||||
ids.port_id = port->d_id;
|
||||
ids.roles = FC_RPORT_ROLE_FCP_TARGET;
|
||||
port->rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids);
|
||||
if (!port->rport) {
|
||||
dev_err(&port->adapter->ccw_device->dev,
|
||||
"Registering port 0x%016Lx failed\n",
|
||||
(unsigned long long)port->wwpn);
|
||||
return;
|
||||
}
|
||||
|
||||
scsi_target_unblock(&port->rport->dev);
|
||||
port->rport->maxframe_size = port->maxframe_size;
|
||||
port->rport->supported_classes = port->supported_classes;
|
||||
}
|
||||
|
||||
static void zfcp_erp_rports_del(struct zfcp_adapter *adapter)
|
||||
{
|
||||
struct zfcp_port *port;
|
||||
list_for_each_entry(port, &adapter->port_list_head, list) {
|
||||
if (!port->rport)
|
||||
continue;
|
||||
fc_remote_port_delete(port->rport);
|
||||
port->rport = NULL;
|
||||
}
|
||||
if (!queue_work(zfcp_data.work_queue, &p->work))
|
||||
zfcp_unit_put(unit);
|
||||
}
|
||||
|
||||
static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
|
||||
@ -1256,10 +1226,8 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
|
||||
|
||||
switch (act->action) {
|
||||
case ZFCP_ERP_ACTION_REOPEN_UNIT:
|
||||
if ((result == ZFCP_ERP_SUCCEEDED) &&
|
||||
!unit->device && port->rport) {
|
||||
atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED,
|
||||
&unit->status);
|
||||
flush_work(&port->rport_work);
|
||||
if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) {
|
||||
if (!(atomic_read(&unit->status) &
|
||||
ZFCP_STATUS_UNIT_SCSI_WORK_PENDING))
|
||||
zfcp_erp_schedule_work(unit);
|
||||
@ -1269,27 +1237,17 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
|
||||
|
||||
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
|
||||
case ZFCP_ERP_ACTION_REOPEN_PORT:
|
||||
if (atomic_read(&port->status) & ZFCP_STATUS_PORT_NO_WWPN) {
|
||||
zfcp_port_put(port);
|
||||
return;
|
||||
}
|
||||
if ((result == ZFCP_ERP_SUCCEEDED) && !port->rport)
|
||||
zfcp_erp_rport_register(port);
|
||||
if ((result != ZFCP_ERP_SUCCEEDED) && port->rport) {
|
||||
fc_remote_port_delete(port->rport);
|
||||
port->rport = NULL;
|
||||
}
|
||||
if (result == ZFCP_ERP_SUCCEEDED)
|
||||
zfcp_scsi_schedule_rport_register(port);
|
||||
zfcp_port_put(port);
|
||||
break;
|
||||
|
||||
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
|
||||
if (result != ZFCP_ERP_SUCCEEDED) {
|
||||
unregister_service_level(&adapter->service_level);
|
||||
zfcp_erp_rports_del(adapter);
|
||||
} else {
|
||||
if (result == ZFCP_ERP_SUCCEEDED) {
|
||||
register_service_level(&adapter->service_level);
|
||||
schedule_work(&adapter->scan_work);
|
||||
}
|
||||
} else
|
||||
unregister_service_level(&adapter->service_level);
|
||||
zfcp_adapter_put(adapter);
|
||||
break;
|
||||
}
|
||||
@ -1346,7 +1304,7 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
|
||||
erp_action->status |= ZFCP_STATUS_ERP_LOWMEM;
|
||||
}
|
||||
if (adapter->erp_total_count == adapter->erp_low_mem_count)
|
||||
_zfcp_erp_adapter_reopen(adapter, 0, 66, NULL);
|
||||
_zfcp_erp_adapter_reopen(adapter, 0, "erstgy1", NULL);
|
||||
else {
|
||||
zfcp_erp_strategy_memwait(erp_action);
|
||||
retval = ZFCP_ERP_CONTINUES;
|
||||
@ -1406,9 +1364,9 @@ static int zfcp_erp_thread(void *data)
|
||||
zfcp_erp_wakeup(adapter);
|
||||
}
|
||||
|
||||
zfcp_rec_dbf_event_thread_lock(4, adapter);
|
||||
zfcp_rec_dbf_event_thread_lock("erthrd1", adapter);
|
||||
ignore = down_interruptible(&adapter->erp_ready_sem);
|
||||
zfcp_rec_dbf_event_thread_lock(5, adapter);
|
||||
zfcp_rec_dbf_event_thread_lock("erthrd2", adapter);
|
||||
}
|
||||
|
||||
atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
|
||||
@ -1453,7 +1411,7 @@ void zfcp_erp_thread_kill(struct zfcp_adapter *adapter)
|
||||
{
|
||||
atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status);
|
||||
up(&adapter->erp_ready_sem);
|
||||
zfcp_rec_dbf_event_thread_lock(3, adapter);
|
||||
zfcp_rec_dbf_event_thread_lock("erthrk1", adapter);
|
||||
|
||||
wait_event(adapter->erp_thread_wqh,
|
||||
!(atomic_read(&adapter->status) &
|
||||
@ -1469,7 +1427,7 @@ void zfcp_erp_thread_kill(struct zfcp_adapter *adapter)
|
||||
* @id: Event id for debug trace.
|
||||
* @ref: Reference for debug trace.
|
||||
*/
|
||||
void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, u8 id, void *ref)
|
||||
void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, char *id, void *ref)
|
||||
{
|
||||
zfcp_erp_modify_adapter_status(adapter, id, ref,
|
||||
ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
|
||||
@ -1481,7 +1439,7 @@ void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, u8 id, void *ref)
|
||||
* @id: Event id for debug trace.
|
||||
* @ref: Reference for debug trace.
|
||||
*/
|
||||
void zfcp_erp_port_failed(struct zfcp_port *port, u8 id, void *ref)
|
||||
void zfcp_erp_port_failed(struct zfcp_port *port, char *id, void *ref)
|
||||
{
|
||||
zfcp_erp_modify_port_status(port, id, ref,
|
||||
ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
|
||||
@ -1493,7 +1451,7 @@ void zfcp_erp_port_failed(struct zfcp_port *port, u8 id, void *ref)
|
||||
* @id: Event id for debug trace.
|
||||
* @ref: Reference for debug trace.
|
||||
*/
|
||||
void zfcp_erp_unit_failed(struct zfcp_unit *unit, u8 id, void *ref)
|
||||
void zfcp_erp_unit_failed(struct zfcp_unit *unit, char *id, void *ref)
|
||||
{
|
||||
zfcp_erp_modify_unit_status(unit, id, ref,
|
||||
ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
|
||||
@ -1520,7 +1478,7 @@ void zfcp_erp_wait(struct zfcp_adapter *adapter)
|
||||
*
|
||||
* Changes in common status bits are propagated to attached ports and units.
|
||||
*/
|
||||
void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, u8 id,
|
||||
void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id,
|
||||
void *ref, u32 mask, int set_or_clear)
|
||||
{
|
||||
struct zfcp_port *port;
|
||||
@ -1554,7 +1512,7 @@ void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, u8 id,
|
||||
*
|
||||
* Changes in common status bits are propagated to attached units.
|
||||
*/
|
||||
void zfcp_erp_modify_port_status(struct zfcp_port *port, u8 id, void *ref,
|
||||
void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref,
|
||||
u32 mask, int set_or_clear)
|
||||
{
|
||||
struct zfcp_unit *unit;
|
||||
@ -1586,7 +1544,7 @@ void zfcp_erp_modify_port_status(struct zfcp_port *port, u8 id, void *ref,
|
||||
* @mask: status bits to change
|
||||
* @set_or_clear: ZFCP_SET or ZFCP_CLEAR
|
||||
*/
|
||||
void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, u8 id, void *ref,
|
||||
void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref,
|
||||
u32 mask, int set_or_clear)
|
||||
{
|
||||
if (set_or_clear == ZFCP_SET) {
|
||||
@ -1609,7 +1567,7 @@ void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, u8 id, void *ref,
|
||||
* @id: The debug trace id.
|
||||
* @id: Reference for the debug trace.
|
||||
*/
|
||||
void zfcp_erp_port_boxed(struct zfcp_port *port, u8 id, void *ref)
|
||||
void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
@ -1626,7 +1584,7 @@ void zfcp_erp_port_boxed(struct zfcp_port *port, u8 id, void *ref)
|
||||
* @id: The debug trace id.
|
||||
* @id: Reference for the debug trace.
|
||||
*/
|
||||
void zfcp_erp_unit_boxed(struct zfcp_unit *unit, u8 id, void *ref)
|
||||
void zfcp_erp_unit_boxed(struct zfcp_unit *unit, char *id, void *ref)
|
||||
{
|
||||
zfcp_erp_modify_unit_status(unit, id, ref,
|
||||
ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
|
||||
@ -1642,7 +1600,7 @@ void zfcp_erp_unit_boxed(struct zfcp_unit *unit, u8 id, void *ref)
|
||||
* Since the adapter has denied access, stop using the port and the
|
||||
* attached units.
|
||||
*/
|
||||
void zfcp_erp_port_access_denied(struct zfcp_port *port, u8 id, void *ref)
|
||||
void zfcp_erp_port_access_denied(struct zfcp_port *port, char *id, void *ref)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
@ -1661,14 +1619,14 @@ void zfcp_erp_port_access_denied(struct zfcp_port *port, u8 id, void *ref)
|
||||
*
|
||||
* Since the adapter has denied access, stop using the unit.
|
||||
*/
|
||||
void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, u8 id, void *ref)
|
||||
void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, char *id, void *ref)
|
||||
{
|
||||
zfcp_erp_modify_unit_status(unit, id, ref,
|
||||
ZFCP_STATUS_COMMON_ERP_FAILED |
|
||||
ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
|
||||
}
|
||||
|
||||
static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, u8 id,
|
||||
static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, char *id,
|
||||
void *ref)
|
||||
{
|
||||
int status = atomic_read(&unit->status);
|
||||
@ -1679,7 +1637,7 @@ static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, u8 id,
|
||||
zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
|
||||
}
|
||||
|
||||
static void zfcp_erp_port_access_changed(struct zfcp_port *port, u8 id,
|
||||
static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id,
|
||||
void *ref)
|
||||
{
|
||||
struct zfcp_unit *unit;
|
||||
@ -1701,7 +1659,7 @@ static void zfcp_erp_port_access_changed(struct zfcp_port *port, u8 id,
|
||||
* @id: Id for debug trace
|
||||
* @ref: Reference for debug trace
|
||||
*/
|
||||
void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, u8 id,
|
||||
void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id,
|
||||
void *ref)
|
||||
{
|
||||
struct zfcp_port *port;
|
||||
|
@ -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);
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Implementation of FSF commands.
|
||||
*
|
||||
* Copyright IBM Corporation 2002, 2008
|
||||
* Copyright IBM Corporation 2002, 2009
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "zfcp"
|
||||
@ -12,11 +12,14 @@
|
||||
#include <linux/blktrace_api.h>
|
||||
#include "zfcp_ext.h"
|
||||
|
||||
#define ZFCP_REQ_AUTO_CLEANUP 0x00000002
|
||||
#define ZFCP_REQ_NO_QTCB 0x00000008
|
||||
|
||||
static void zfcp_fsf_request_timeout_handler(unsigned long data)
|
||||
{
|
||||
struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
|
||||
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 62,
|
||||
NULL);
|
||||
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
|
||||
"fsrth_1", NULL);
|
||||
}
|
||||
|
||||
static void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req,
|
||||
@ -75,7 +78,7 @@ static void zfcp_fsf_access_denied_port(struct zfcp_fsf_req *req,
|
||||
(unsigned long long)port->wwpn);
|
||||
zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
|
||||
zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
|
||||
zfcp_erp_port_access_denied(port, 55, req);
|
||||
zfcp_erp_port_access_denied(port, "fspad_1", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
}
|
||||
|
||||
@ -89,7 +92,7 @@ static void zfcp_fsf_access_denied_unit(struct zfcp_fsf_req *req,
|
||||
(unsigned long long)unit->port->wwpn);
|
||||
zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
|
||||
zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
|
||||
zfcp_erp_unit_access_denied(unit, 59, req);
|
||||
zfcp_erp_unit_access_denied(unit, "fsuad_1", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
}
|
||||
|
||||
@ -97,7 +100,7 @@ static void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req)
|
||||
{
|
||||
dev_err(&req->adapter->ccw_device->dev, "FCP device not "
|
||||
"operational because of an unsupported FC class\n");
|
||||
zfcp_erp_adapter_shutdown(req->adapter, 0, 123, req);
|
||||
zfcp_erp_adapter_shutdown(req->adapter, 0, "fscns_1", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
}
|
||||
|
||||
@ -159,20 +162,13 @@ static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req)
|
||||
list_for_each_entry(port, &adapter->port_list_head, list)
|
||||
if (port->d_id == d_id) {
|
||||
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
|
||||
switch (sr_buf->status_subtype) {
|
||||
case FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT:
|
||||
zfcp_erp_port_reopen(port, 0, 101, req);
|
||||
break;
|
||||
case FSF_STATUS_READ_SUB_ERROR_PORT:
|
||||
zfcp_erp_port_shutdown(port, 0, 122, req);
|
||||
break;
|
||||
}
|
||||
zfcp_erp_port_reopen(port, 0, "fssrpc1", req);
|
||||
return;
|
||||
}
|
||||
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
|
||||
}
|
||||
|
||||
static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, u8 id,
|
||||
static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id,
|
||||
struct fsf_link_down_info *link_down)
|
||||
{
|
||||
struct zfcp_adapter *adapter = req->adapter;
|
||||
@ -181,6 +177,7 @@ static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, u8 id,
|
||||
return;
|
||||
|
||||
atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
|
||||
zfcp_scsi_schedule_rports_block(adapter);
|
||||
|
||||
if (!link_down)
|
||||
goto out;
|
||||
@ -261,13 +258,13 @@ static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req)
|
||||
|
||||
switch (sr_buf->status_subtype) {
|
||||
case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
|
||||
zfcp_fsf_link_down_info_eval(req, 38, ldi);
|
||||
zfcp_fsf_link_down_info_eval(req, "fssrld1", ldi);
|
||||
break;
|
||||
case FSF_STATUS_READ_SUB_FDISC_FAILED:
|
||||
zfcp_fsf_link_down_info_eval(req, 39, ldi);
|
||||
zfcp_fsf_link_down_info_eval(req, "fssrld2", ldi);
|
||||
break;
|
||||
case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE:
|
||||
zfcp_fsf_link_down_info_eval(req, 40, NULL);
|
||||
zfcp_fsf_link_down_info_eval(req, "fssrld3", NULL);
|
||||
};
|
||||
}
|
||||
|
||||
@ -307,22 +304,23 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
|
||||
dev_info(&adapter->ccw_device->dev,
|
||||
"The local link has been restored\n");
|
||||
/* All ports should be marked as ready to run again */
|
||||
zfcp_erp_modify_adapter_status(adapter, 30, NULL,
|
||||
zfcp_erp_modify_adapter_status(adapter, "fssrh_1", NULL,
|
||||
ZFCP_STATUS_COMMON_RUNNING,
|
||||
ZFCP_SET);
|
||||
zfcp_erp_adapter_reopen(adapter,
|
||||
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
|
||||
ZFCP_STATUS_COMMON_ERP_FAILED,
|
||||
102, req);
|
||||
"fssrh_2", req);
|
||||
break;
|
||||
case FSF_STATUS_READ_NOTIFICATION_LOST:
|
||||
if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED)
|
||||
zfcp_erp_adapter_access_changed(adapter, 135, req);
|
||||
zfcp_erp_adapter_access_changed(adapter, "fssrh_3",
|
||||
req);
|
||||
if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS)
|
||||
schedule_work(&adapter->scan_work);
|
||||
break;
|
||||
case FSF_STATUS_READ_CFDC_UPDATED:
|
||||
zfcp_erp_adapter_access_changed(adapter, 136, req);
|
||||
zfcp_erp_adapter_access_changed(adapter, "fssrh_4", req);
|
||||
break;
|
||||
case FSF_STATUS_READ_FEATURE_UPDATE_ALERT:
|
||||
adapter->adapter_features = sr_buf->payload.word[0];
|
||||
@ -351,7 +349,7 @@ static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req)
|
||||
dev_err(&req->adapter->ccw_device->dev,
|
||||
"The FCP adapter reported a problem "
|
||||
"that cannot be recovered\n");
|
||||
zfcp_erp_adapter_shutdown(req->adapter, 0, 121, req);
|
||||
zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1", req);
|
||||
break;
|
||||
}
|
||||
/* all non-return stats set FSFREQ_ERROR*/
|
||||
@ -368,7 +366,7 @@ static void zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *req)
|
||||
dev_err(&req->adapter->ccw_device->dev,
|
||||
"The FCP adapter does not recognize the command 0x%x\n",
|
||||
req->qtcb->header.fsf_command);
|
||||
zfcp_erp_adapter_shutdown(req->adapter, 0, 120, req);
|
||||
zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfse_1", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
case FSF_ADAPTER_STATUS_AVAILABLE:
|
||||
@ -400,17 +398,17 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
|
||||
"QTCB version 0x%x not supported by FCP adapter "
|
||||
"(0x%x to 0x%x)\n", FSF_QTCB_CURRENT_VERSION,
|
||||
psq->word[0], psq->word[1]);
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, 117, req);
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, "fspse_1", req);
|
||||
break;
|
||||
case FSF_PROT_ERROR_STATE:
|
||||
case FSF_PROT_SEQ_NUMB_ERROR:
|
||||
zfcp_erp_adapter_reopen(adapter, 0, 98, req);
|
||||
zfcp_erp_adapter_reopen(adapter, 0, "fspse_2", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_RETRY;
|
||||
break;
|
||||
case FSF_PROT_UNSUPP_QTCB_TYPE:
|
||||
dev_err(&adapter->ccw_device->dev,
|
||||
"The QTCB type is not supported by the FCP adapter\n");
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, 118, req);
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, "fspse_3", req);
|
||||
break;
|
||||
case FSF_PROT_HOST_CONNECTION_INITIALIZING:
|
||||
atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
|
||||
@ -420,27 +418,29 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
|
||||
dev_err(&adapter->ccw_device->dev,
|
||||
"0x%Lx is an ambiguous request identifier\n",
|
||||
(unsigned long long)qtcb->bottom.support.req_handle);
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, 78, req);
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, "fspse_4", req);
|
||||
break;
|
||||
case FSF_PROT_LINK_DOWN:
|
||||
zfcp_fsf_link_down_info_eval(req, 37, &psq->link_down_info);
|
||||
zfcp_fsf_link_down_info_eval(req, "fspse_5",
|
||||
&psq->link_down_info);
|
||||
/* FIXME: reopening adapter now? better wait for link up */
|
||||
zfcp_erp_adapter_reopen(adapter, 0, 79, req);
|
||||
zfcp_erp_adapter_reopen(adapter, 0, "fspse_6", req);
|
||||
break;
|
||||
case FSF_PROT_REEST_QUEUE:
|
||||
/* All ports should be marked as ready to run again */
|
||||
zfcp_erp_modify_adapter_status(adapter, 28, NULL,
|
||||
zfcp_erp_modify_adapter_status(adapter, "fspse_7", NULL,
|
||||
ZFCP_STATUS_COMMON_RUNNING,
|
||||
ZFCP_SET);
|
||||
zfcp_erp_adapter_reopen(adapter,
|
||||
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
|
||||
ZFCP_STATUS_COMMON_ERP_FAILED, 99, req);
|
||||
ZFCP_STATUS_COMMON_ERP_FAILED,
|
||||
"fspse_8", req);
|
||||
break;
|
||||
default:
|
||||
dev_err(&adapter->ccw_device->dev,
|
||||
"0x%x is not a valid transfer protocol status\n",
|
||||
qtcb->prefix.prot_status);
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, 119, req);
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9", req);
|
||||
}
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
}
|
||||
@ -526,7 +526,7 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
|
||||
dev_err(&adapter->ccw_device->dev,
|
||||
"Unknown or unsupported arbitrated loop "
|
||||
"fibre channel topology detected\n");
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, 127, req);
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, "fsece_1", req);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -560,7 +560,7 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
|
||||
"FCP adapter maximum QTCB size (%d bytes) "
|
||||
"is too small\n",
|
||||
bottom->max_qtcb_size);
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, 129, req);
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh1", req);
|
||||
return;
|
||||
}
|
||||
atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
|
||||
@ -577,11 +577,11 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
|
||||
atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
|
||||
&adapter->status);
|
||||
|
||||
zfcp_fsf_link_down_info_eval(req, 42,
|
||||
zfcp_fsf_link_down_info_eval(req, "fsecdh2",
|
||||
&qtcb->header.fsf_status_qual.link_down_info);
|
||||
break;
|
||||
default:
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, 130, req);
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh3", req);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -597,14 +597,14 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
|
||||
dev_err(&adapter->ccw_device->dev,
|
||||
"The FCP adapter only supports newer "
|
||||
"control block versions\n");
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, 125, req);
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh4", req);
|
||||
return;
|
||||
}
|
||||
if (FSF_QTCB_CURRENT_VERSION > bottom->high_qtcb_version) {
|
||||
dev_err(&adapter->ccw_device->dev,
|
||||
"The FCP adapter only supports older "
|
||||
"control block versions\n");
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, 126, req);
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh5", req);
|
||||
}
|
||||
}
|
||||
|
||||
@ -617,9 +617,10 @@ static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req)
|
||||
if (req->data)
|
||||
memcpy(req->data, bottom, sizeof(*bottom));
|
||||
|
||||
if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
|
||||
if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) {
|
||||
fc_host_permanent_port_name(shost) = bottom->wwpn;
|
||||
else
|
||||
fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
|
||||
} else
|
||||
fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
|
||||
fc_host_maxframe_size(shost) = bottom->maximum_frame_size;
|
||||
fc_host_supported_speeds(shost) = bottom->supported_speed;
|
||||
@ -638,20 +639,12 @@ static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)
|
||||
break;
|
||||
case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
|
||||
zfcp_fsf_exchange_port_evaluate(req);
|
||||
zfcp_fsf_link_down_info_eval(req, 43,
|
||||
zfcp_fsf_link_down_info_eval(req, "fsepdh1",
|
||||
&qtcb->header.fsf_status_qual.link_down_info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int zfcp_fsf_sbal_available(struct zfcp_adapter *adapter)
|
||||
{
|
||||
if (atomic_read(&adapter->req_q.count) > 0)
|
||||
return 1;
|
||||
atomic_inc(&adapter->qdio_outb_full);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter)
|
||||
__releases(&adapter->req_q_lock)
|
||||
__acquires(&adapter->req_q_lock)
|
||||
@ -735,7 +728,7 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter,
|
||||
|
||||
req->adapter = adapter;
|
||||
req->fsf_command = fsf_cmd;
|
||||
req->req_id = adapter->req_no++;
|
||||
req->req_id = adapter->req_no;
|
||||
req->sbal_number = 1;
|
||||
req->sbal_first = req_q->first;
|
||||
req->sbal_last = req_q->first;
|
||||
@ -791,13 +784,14 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *req)
|
||||
if (zfcp_reqlist_find_safe(adapter, req))
|
||||
zfcp_reqlist_remove(adapter, req);
|
||||
spin_unlock_irqrestore(&adapter->req_list_lock, flags);
|
||||
zfcp_erp_adapter_reopen(adapter, 0, 116, req);
|
||||
zfcp_erp_adapter_reopen(adapter, 0, "fsrs__1", req);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Don't increase for unsolicited status */
|
||||
if (req->qtcb)
|
||||
adapter->fsf_req_seq_no++;
|
||||
adapter->req_no++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -870,14 +864,14 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
|
||||
switch (req->qtcb->header.fsf_status) {
|
||||
case FSF_PORT_HANDLE_NOT_VALID:
|
||||
if (fsq->word[0] == fsq->word[1]) {
|
||||
zfcp_erp_adapter_reopen(unit->port->adapter, 0, 104,
|
||||
req);
|
||||
zfcp_erp_adapter_reopen(unit->port->adapter, 0,
|
||||
"fsafch1", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
}
|
||||
break;
|
||||
case FSF_LUN_HANDLE_NOT_VALID:
|
||||
if (fsq->word[0] == fsq->word[1]) {
|
||||
zfcp_erp_port_reopen(unit->port, 0, 105, req);
|
||||
zfcp_erp_port_reopen(unit->port, 0, "fsafch2", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
}
|
||||
break;
|
||||
@ -885,12 +879,12 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED;
|
||||
break;
|
||||
case FSF_PORT_BOXED:
|
||||
zfcp_erp_port_boxed(unit->port, 47, req);
|
||||
zfcp_erp_port_boxed(unit->port, "fsafch3", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR |
|
||||
ZFCP_STATUS_FSFREQ_RETRY;
|
||||
break;
|
||||
case FSF_LUN_BOXED:
|
||||
zfcp_erp_unit_boxed(unit, 48, req);
|
||||
zfcp_erp_unit_boxed(unit, "fsafch4", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR |
|
||||
ZFCP_STATUS_FSFREQ_RETRY;
|
||||
break;
|
||||
@ -912,27 +906,22 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
|
||||
/**
|
||||
* zfcp_fsf_abort_fcp_command - abort running SCSI command
|
||||
* @old_req_id: unsigned long
|
||||
* @adapter: pointer to struct zfcp_adapter
|
||||
* @unit: pointer to struct zfcp_unit
|
||||
* @req_flags: integer specifying the request flags
|
||||
* Returns: pointer to struct zfcp_fsf_req
|
||||
*
|
||||
* FIXME(design): should be watched by a timeout !!!
|
||||
*/
|
||||
|
||||
struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
|
||||
struct zfcp_adapter *adapter,
|
||||
struct zfcp_unit *unit,
|
||||
int req_flags)
|
||||
struct zfcp_unit *unit)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_fsf_req *req = NULL;
|
||||
struct zfcp_adapter *adapter = unit->port->adapter;
|
||||
|
||||
spin_lock(&adapter->req_q_lock);
|
||||
if (!zfcp_fsf_sbal_available(adapter))
|
||||
spin_lock_bh(&adapter->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(adapter))
|
||||
goto out;
|
||||
req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND,
|
||||
req_flags, adapter->pool.fsf_req_abort);
|
||||
0, adapter->pool.fsf_req_abort);
|
||||
if (IS_ERR(req)) {
|
||||
req = NULL;
|
||||
goto out;
|
||||
@ -960,7 +949,7 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
|
||||
zfcp_fsf_req_free(req);
|
||||
req = NULL;
|
||||
out:
|
||||
spin_unlock(&adapter->req_q_lock);
|
||||
spin_unlock_bh(&adapter->req_q_lock);
|
||||
return req;
|
||||
}
|
||||
|
||||
@ -998,7 +987,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
|
||||
ZFCP_STATUS_FSFREQ_RETRY;
|
||||
break;
|
||||
case FSF_PORT_HANDLE_NOT_VALID:
|
||||
zfcp_erp_adapter_reopen(adapter, 0, 106, req);
|
||||
zfcp_erp_adapter_reopen(adapter, 0, "fsscth1", req);
|
||||
case FSF_GENERIC_COMMAND_REJECTED:
|
||||
case FSF_PAYLOAD_SIZE_MISMATCH:
|
||||
case FSF_REQUEST_SIZE_TOO_LARGE:
|
||||
@ -1174,12 +1163,8 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els)
|
||||
struct fsf_qtcb_bottom_support *bottom;
|
||||
int ret = -EIO;
|
||||
|
||||
if (unlikely(!(atomic_read(&els->port->status) &
|
||||
ZFCP_STATUS_COMMON_UNBLOCKED)))
|
||||
return -EBUSY;
|
||||
|
||||
spin_lock(&adapter->req_q_lock);
|
||||
if (!zfcp_fsf_sbal_available(adapter))
|
||||
spin_lock_bh(&adapter->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(adapter))
|
||||
goto out;
|
||||
req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS,
|
||||
ZFCP_REQ_AUTO_CLEANUP, NULL);
|
||||
@ -1212,7 +1197,7 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els)
|
||||
failed_send:
|
||||
zfcp_fsf_req_free(req);
|
||||
out:
|
||||
spin_unlock(&adapter->req_q_lock);
|
||||
spin_unlock_bh(&adapter->req_q_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1224,7 +1209,7 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
|
||||
int retval = -EIO;
|
||||
|
||||
spin_lock_bh(&adapter->req_q_lock);
|
||||
if (!zfcp_fsf_sbal_available(adapter))
|
||||
if (zfcp_fsf_req_sbal_get(adapter))
|
||||
goto out;
|
||||
req = zfcp_fsf_req_create(adapter,
|
||||
FSF_QTCB_EXCHANGE_CONFIG_DATA,
|
||||
@ -1320,7 +1305,7 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
spin_lock_bh(&adapter->req_q_lock);
|
||||
if (!zfcp_fsf_sbal_available(adapter))
|
||||
if (zfcp_fsf_req_sbal_get(adapter))
|
||||
goto out;
|
||||
req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
|
||||
ZFCP_REQ_AUTO_CLEANUP,
|
||||
@ -1366,7 +1351,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter,
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
spin_lock_bh(&adapter->req_q_lock);
|
||||
if (!zfcp_fsf_sbal_available(adapter))
|
||||
if (zfcp_fsf_req_sbal_get(adapter))
|
||||
goto out;
|
||||
|
||||
req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, 0,
|
||||
@ -1416,7 +1401,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
|
||||
"Not enough FCP adapter resources to open "
|
||||
"remote port 0x%016Lx\n",
|
||||
(unsigned long long)port->wwpn);
|
||||
zfcp_erp_port_failed(port, 31, req);
|
||||
zfcp_erp_port_failed(port, "fsoph_1", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
case FSF_ADAPTER_STATUS_AVAILABLE:
|
||||
@ -1522,13 +1507,13 @@ static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req)
|
||||
|
||||
switch (req->qtcb->header.fsf_status) {
|
||||
case FSF_PORT_HANDLE_NOT_VALID:
|
||||
zfcp_erp_adapter_reopen(port->adapter, 0, 107, req);
|
||||
zfcp_erp_adapter_reopen(port->adapter, 0, "fscph_1", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
case FSF_ADAPTER_STATUS_AVAILABLE:
|
||||
break;
|
||||
case FSF_GOOD:
|
||||
zfcp_erp_modify_port_status(port, 33, req,
|
||||
zfcp_erp_modify_port_status(port, "fscph_2", req,
|
||||
ZFCP_STATUS_COMMON_OPEN,
|
||||
ZFCP_CLEAR);
|
||||
break;
|
||||
@ -1657,7 +1642,7 @@ static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req)
|
||||
|
||||
if (req->qtcb->header.fsf_status == FSF_PORT_HANDLE_NOT_VALID) {
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
zfcp_erp_adapter_reopen(wka_port->adapter, 0, 84, req);
|
||||
zfcp_erp_adapter_reopen(wka_port->adapter, 0, "fscwph1", req);
|
||||
}
|
||||
|
||||
wka_port->status = ZFCP_WKA_PORT_OFFLINE;
|
||||
@ -1712,18 +1697,18 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
|
||||
struct zfcp_unit *unit;
|
||||
|
||||
if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
|
||||
goto skip_fsfstatus;
|
||||
return;
|
||||
|
||||
switch (header->fsf_status) {
|
||||
case FSF_PORT_HANDLE_NOT_VALID:
|
||||
zfcp_erp_adapter_reopen(port->adapter, 0, 108, req);
|
||||
zfcp_erp_adapter_reopen(port->adapter, 0, "fscpph1", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
case FSF_ACCESS_DENIED:
|
||||
zfcp_fsf_access_denied_port(req, port);
|
||||
break;
|
||||
case FSF_PORT_BOXED:
|
||||
zfcp_erp_port_boxed(port, 50, req);
|
||||
zfcp_erp_port_boxed(port, "fscpph2", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR |
|
||||
ZFCP_STATUS_FSFREQ_RETRY;
|
||||
/* can't use generic zfcp_erp_modify_port_status because
|
||||
@ -1752,8 +1737,6 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
|
||||
&unit->status);
|
||||
break;
|
||||
}
|
||||
skip_fsfstatus:
|
||||
atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, &port->status);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1789,8 +1772,6 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
|
||||
req->erp_action = erp_action;
|
||||
req->handler = zfcp_fsf_close_physical_port_handler;
|
||||
erp_action->fsf_req = req;
|
||||
atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING,
|
||||
&erp_action->port->status);
|
||||
|
||||
zfcp_fsf_start_erp_timer(req);
|
||||
retval = zfcp_fsf_req_send(req);
|
||||
@ -1825,7 +1806,7 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
|
||||
switch (header->fsf_status) {
|
||||
|
||||
case FSF_PORT_HANDLE_NOT_VALID:
|
||||
zfcp_erp_adapter_reopen(unit->port->adapter, 0, 109, req);
|
||||
zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fsouh_1", req);
|
||||
/* fall through */
|
||||
case FSF_LUN_ALREADY_OPEN:
|
||||
break;
|
||||
@ -1835,7 +1816,7 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
|
||||
atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
|
||||
break;
|
||||
case FSF_PORT_BOXED:
|
||||
zfcp_erp_port_boxed(unit->port, 51, req);
|
||||
zfcp_erp_port_boxed(unit->port, "fsouh_2", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR |
|
||||
ZFCP_STATUS_FSFREQ_RETRY;
|
||||
break;
|
||||
@ -1851,7 +1832,7 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
|
||||
else
|
||||
zfcp_act_eval_err(adapter,
|
||||
header->fsf_status_qual.word[2]);
|
||||
zfcp_erp_unit_access_denied(unit, 60, req);
|
||||
zfcp_erp_unit_access_denied(unit, "fsouh_3", req);
|
||||
atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
|
||||
atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
@ -1862,7 +1843,7 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
|
||||
"0x%016Lx on port 0x%016Lx\n",
|
||||
(unsigned long long)unit->fcp_lun,
|
||||
(unsigned long long)unit->port->wwpn);
|
||||
zfcp_erp_unit_failed(unit, 34, req);
|
||||
zfcp_erp_unit_failed(unit, "fsouh_4", req);
|
||||
/* fall through */
|
||||
case FSF_INVALID_COMMAND_OPTION:
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
@ -1911,9 +1892,9 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
|
||||
"port 0x%016Lx)\n",
|
||||
(unsigned long long)unit->fcp_lun,
|
||||
(unsigned long long)unit->port->wwpn);
|
||||
zfcp_erp_unit_failed(unit, 35, req);
|
||||
zfcp_erp_unit_failed(unit, "fsouh_5", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
zfcp_erp_unit_shutdown(unit, 0, 80, req);
|
||||
zfcp_erp_unit_shutdown(unit, 0, "fsouh_6", req);
|
||||
} else if (!exclusive && readwrite) {
|
||||
dev_err(&adapter->ccw_device->dev,
|
||||
"Shared read-write access not "
|
||||
@ -1921,9 +1902,9 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
|
||||
"0x%016Lx)\n",
|
||||
(unsigned long long)unit->fcp_lun,
|
||||
(unsigned long long)unit->port->wwpn);
|
||||
zfcp_erp_unit_failed(unit, 36, req);
|
||||
zfcp_erp_unit_failed(unit, "fsouh_7", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
zfcp_erp_unit_shutdown(unit, 0, 81, req);
|
||||
zfcp_erp_unit_shutdown(unit, 0, "fsouh_8", req);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1988,15 +1969,15 @@ static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req)
|
||||
|
||||
switch (req->qtcb->header.fsf_status) {
|
||||
case FSF_PORT_HANDLE_NOT_VALID:
|
||||
zfcp_erp_adapter_reopen(unit->port->adapter, 0, 110, req);
|
||||
zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fscuh_1", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
case FSF_LUN_HANDLE_NOT_VALID:
|
||||
zfcp_erp_port_reopen(unit->port, 0, 111, req);
|
||||
zfcp_erp_port_reopen(unit->port, 0, "fscuh_2", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
case FSF_PORT_BOXED:
|
||||
zfcp_erp_port_boxed(unit->port, 52, req);
|
||||
zfcp_erp_port_boxed(unit->port, "fscuh_3", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR |
|
||||
ZFCP_STATUS_FSFREQ_RETRY;
|
||||
break;
|
||||
@ -2073,7 +2054,6 @@ static void zfcp_fsf_req_latency(struct zfcp_fsf_req *req)
|
||||
struct fsf_qual_latency_info *lat_inf;
|
||||
struct latency_cont *lat;
|
||||
struct zfcp_unit *unit = req->unit;
|
||||
unsigned long flags;
|
||||
|
||||
lat_inf = &req->qtcb->prefix.prot_status_qual.latency_info;
|
||||
|
||||
@ -2091,11 +2071,11 @@ static void zfcp_fsf_req_latency(struct zfcp_fsf_req *req)
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&unit->latencies.lock, flags);
|
||||
spin_lock(&unit->latencies.lock);
|
||||
zfcp_fsf_update_lat(&lat->channel, lat_inf->channel_lat);
|
||||
zfcp_fsf_update_lat(&lat->fabric, lat_inf->fabric_lat);
|
||||
lat->counter++;
|
||||
spin_unlock_irqrestore(&unit->latencies.lock, flags);
|
||||
spin_unlock(&unit->latencies.lock);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_IO_TRACE
|
||||
@ -2147,7 +2127,6 @@ static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req)
|
||||
|
||||
if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ABORTED)) {
|
||||
set_host_byte(scpnt, DID_SOFT_ERROR);
|
||||
set_driver_byte(scpnt, SUGGEST_RETRY);
|
||||
goto skip_fsfstatus;
|
||||
}
|
||||
|
||||
@ -2237,12 +2216,12 @@ static void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req)
|
||||
switch (header->fsf_status) {
|
||||
case FSF_HANDLE_MISMATCH:
|
||||
case FSF_PORT_HANDLE_NOT_VALID:
|
||||
zfcp_erp_adapter_reopen(unit->port->adapter, 0, 112, req);
|
||||
zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fssfch1", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
case FSF_FCPLUN_NOT_VALID:
|
||||
case FSF_LUN_HANDLE_NOT_VALID:
|
||||
zfcp_erp_port_reopen(unit->port, 0, 113, req);
|
||||
zfcp_erp_port_reopen(unit->port, 0, "fssfch2", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
case FSF_SERVICE_CLASS_NOT_SUPPORTED:
|
||||
@ -2258,7 +2237,8 @@ static void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req)
|
||||
req->qtcb->bottom.io.data_direction,
|
||||
(unsigned long long)unit->fcp_lun,
|
||||
(unsigned long long)unit->port->wwpn);
|
||||
zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 133, req);
|
||||
zfcp_erp_adapter_shutdown(unit->port->adapter, 0, "fssfch3",
|
||||
req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
case FSF_CMND_LENGTH_NOT_VALID:
|
||||
@ -2268,16 +2248,17 @@ static void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req)
|
||||
req->qtcb->bottom.io.fcp_cmnd_length,
|
||||
(unsigned long long)unit->fcp_lun,
|
||||
(unsigned long long)unit->port->wwpn);
|
||||
zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 134, req);
|
||||
zfcp_erp_adapter_shutdown(unit->port->adapter, 0, "fssfch4",
|
||||
req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
case FSF_PORT_BOXED:
|
||||
zfcp_erp_port_boxed(unit->port, 53, req);
|
||||
zfcp_erp_port_boxed(unit->port, "fssfch5", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR |
|
||||
ZFCP_STATUS_FSFREQ_RETRY;
|
||||
break;
|
||||
case FSF_LUN_BOXED:
|
||||
zfcp_erp_unit_boxed(unit, 54, req);
|
||||
zfcp_erp_unit_boxed(unit, "fssfch6", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR |
|
||||
ZFCP_STATUS_FSFREQ_RETRY;
|
||||
break;
|
||||
@ -2314,30 +2295,29 @@ static void zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, u32 fcp_dl)
|
||||
|
||||
/**
|
||||
* zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
|
||||
* @adapter: adapter where scsi command is issued
|
||||
* @unit: unit where command is sent to
|
||||
* @scsi_cmnd: scsi command to be sent
|
||||
* @timer: timer to be started when request is initiated
|
||||
* @req_flags: flags for fsf_request
|
||||
*/
|
||||
int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
|
||||
struct zfcp_unit *unit,
|
||||
struct scsi_cmnd *scsi_cmnd,
|
||||
int use_timer, int req_flags)
|
||||
int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
|
||||
struct scsi_cmnd *scsi_cmnd)
|
||||
{
|
||||
struct zfcp_fsf_req *req;
|
||||
struct fcp_cmnd_iu *fcp_cmnd_iu;
|
||||
unsigned int sbtype;
|
||||
int real_bytes, retval = -EIO;
|
||||
struct zfcp_adapter *adapter = unit->port->adapter;
|
||||
|
||||
if (unlikely(!(atomic_read(&unit->status) &
|
||||
ZFCP_STATUS_COMMON_UNBLOCKED)))
|
||||
return -EBUSY;
|
||||
|
||||
spin_lock(&adapter->req_q_lock);
|
||||
if (!zfcp_fsf_sbal_available(adapter))
|
||||
if (atomic_read(&adapter->req_q.count) <= 0) {
|
||||
atomic_inc(&adapter->qdio_outb_full);
|
||||
goto out;
|
||||
req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
|
||||
}
|
||||
req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND,
|
||||
ZFCP_REQ_AUTO_CLEANUP,
|
||||
adapter->pool.fsf_req_scsi);
|
||||
if (IS_ERR(req)) {
|
||||
retval = PTR_ERR(req);
|
||||
@ -2411,7 +2391,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
|
||||
"on port 0x%016Lx closed\n",
|
||||
(unsigned long long)unit->fcp_lun,
|
||||
(unsigned long long)unit->port->wwpn);
|
||||
zfcp_erp_unit_shutdown(unit, 0, 131, req);
|
||||
zfcp_erp_unit_shutdown(unit, 0, "fssfct1", req);
|
||||
retval = -EINVAL;
|
||||
}
|
||||
goto failed_scsi_cmnd;
|
||||
@ -2419,9 +2399,6 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
|
||||
|
||||
zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes);
|
||||
|
||||
if (use_timer)
|
||||
zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
|
||||
|
||||
retval = zfcp_fsf_req_send(req);
|
||||
if (unlikely(retval))
|
||||
goto failed_scsi_cmnd;
|
||||
@ -2439,28 +2416,25 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
|
||||
|
||||
/**
|
||||
* zfcp_fsf_send_fcp_ctm - send SCSI task management command
|
||||
* @adapter: pointer to struct zfcp-adapter
|
||||
* @unit: pointer to struct zfcp_unit
|
||||
* @tm_flags: unsigned byte for task management flags
|
||||
* @req_flags: int request flags
|
||||
* Returns: on success pointer to struct fsf_req, NULL otherwise
|
||||
*/
|
||||
struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *adapter,
|
||||
struct zfcp_unit *unit,
|
||||
u8 tm_flags, int req_flags)
|
||||
struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_fsf_req *req = NULL;
|
||||
struct fcp_cmnd_iu *fcp_cmnd_iu;
|
||||
struct zfcp_adapter *adapter = unit->port->adapter;
|
||||
|
||||
if (unlikely(!(atomic_read(&unit->status) &
|
||||
ZFCP_STATUS_COMMON_UNBLOCKED)))
|
||||
return NULL;
|
||||
|
||||
spin_lock(&adapter->req_q_lock);
|
||||
if (!zfcp_fsf_sbal_available(adapter))
|
||||
spin_lock_bh(&adapter->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(adapter))
|
||||
goto out;
|
||||
req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
|
||||
req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, 0,
|
||||
adapter->pool.fsf_req_scsi);
|
||||
if (IS_ERR(req)) {
|
||||
req = NULL;
|
||||
@ -2492,7 +2466,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *adapter,
|
||||
zfcp_fsf_req_free(req);
|
||||
req = NULL;
|
||||
out:
|
||||
spin_unlock(&adapter->req_q_lock);
|
||||
spin_unlock_bh(&adapter->req_q_lock);
|
||||
return req;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
int retry = 3;
|
||||
|
||||
/* 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;
|
||||
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:
|
||||
|
@ -38,6 +38,28 @@
|
||||
#include <scsi/scsi_transport_iscsi.h>
|
||||
#include <scsi/libiscsi.h>
|
||||
|
||||
static int iscsi_dbg_lib;
|
||||
module_param_named(debug_libiscsi, iscsi_dbg_lib, int, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(debug_libiscsi, "Turn on debugging for libiscsi module. "
|
||||
"Set to 1 to turn on, and zero to turn off. Default "
|
||||
"is off.");
|
||||
|
||||
#define ISCSI_DBG_CONN(_conn, dbg_fmt, arg...) \
|
||||
do { \
|
||||
if (iscsi_dbg_lib) \
|
||||
iscsi_conn_printk(KERN_INFO, _conn, \
|
||||
"%s " dbg_fmt, \
|
||||
__func__, ##arg); \
|
||||
} while (0);
|
||||
|
||||
#define ISCSI_DBG_SESSION(_session, dbg_fmt, arg...) \
|
||||
do { \
|
||||
if (iscsi_dbg_lib) \
|
||||
iscsi_session_printk(KERN_INFO, _session, \
|
||||
"%s " dbg_fmt, \
|
||||
__func__, ##arg); \
|
||||
} while (0);
|
||||
|
||||
/* Serial Number Arithmetic, 32 bits, less than, RFC1982 */
|
||||
#define SNA32_CHECK 2147483648UL
|
||||
|
||||
@ -54,6 +76,15 @@ static int iscsi_sna_lte(u32 n1, u32 n2)
|
||||
(n1 > n2 && (n2 - n1 < SNA32_CHECK)));
|
||||
}
|
||||
|
||||
inline void iscsi_conn_queue_work(struct iscsi_conn *conn)
|
||||
{
|
||||
struct Scsi_Host *shost = conn->session->host;
|
||||
struct iscsi_host *ihost = shost_priv(shost);
|
||||
|
||||
queue_work(ihost->workq, &conn->xmitwork);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iscsi_conn_queue_work);
|
||||
|
||||
void
|
||||
iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
|
||||
{
|
||||
@ -81,8 +112,7 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
|
||||
if (!list_empty(&session->leadconn->xmitqueue) ||
|
||||
!list_empty(&session->leadconn->mgmtqueue)) {
|
||||
if (!(session->tt->caps & CAP_DATA_PATH_OFFLOAD))
|
||||
scsi_queue_work(session->host,
|
||||
&session->leadconn->xmitwork);
|
||||
iscsi_conn_queue_work(session->leadconn);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -176,10 +206,11 @@ static int iscsi_prep_ecdb_ahs(struct iscsi_task *task)
|
||||
ecdb_ahdr->reserved = 0;
|
||||
memcpy(ecdb_ahdr->ecdb, cmd->cmnd + ISCSI_CDB_SIZE, rlen);
|
||||
|
||||
debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d "
|
||||
"rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n",
|
||||
cmd->cmd_len, rlen, pad_len, ahslength, task->hdr_len);
|
||||
|
||||
ISCSI_DBG_SESSION(task->conn->session,
|
||||
"iscsi_prep_ecdb_ahs: varlen_cdb_len %d "
|
||||
"rlen %d pad_len %d ahs_length %d iscsi_headers_size "
|
||||
"%u\n", cmd->cmd_len, rlen, pad_len, ahslength,
|
||||
task->hdr_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -201,10 +232,11 @@ static int iscsi_prep_bidi_ahs(struct iscsi_task *task)
|
||||
rlen_ahdr->reserved = 0;
|
||||
rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
|
||||
|
||||
debug_scsi("bidi-in rlen_ahdr->read_length(%d) "
|
||||
"rlen_ahdr->ahslength(%d)\n",
|
||||
be32_to_cpu(rlen_ahdr->read_length),
|
||||
be16_to_cpu(rlen_ahdr->ahslength));
|
||||
ISCSI_DBG_SESSION(task->conn->session,
|
||||
"bidi-in rlen_ahdr->read_length(%d) "
|
||||
"rlen_ahdr->ahslength(%d)\n",
|
||||
be32_to_cpu(rlen_ahdr->read_length),
|
||||
be16_to_cpu(rlen_ahdr->ahslength));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -335,13 +367,15 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
|
||||
list_move_tail(&task->running, &conn->run_list);
|
||||
|
||||
conn->scsicmd_pdus_cnt++;
|
||||
debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
|
||||
"bidi_len %d cmdsn %d win %d]\n", scsi_bidi_cmnd(sc) ?
|
||||
"bidirectional" : sc->sc_data_direction == DMA_TO_DEVICE ?
|
||||
"write" : "read", conn->id, sc, sc->cmnd[0], task->itt,
|
||||
scsi_bufflen(sc),
|
||||
scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
|
||||
session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
|
||||
ISCSI_DBG_SESSION(session, "iscsi prep [%s cid %d sc %p cdb 0x%x "
|
||||
"itt 0x%x len %d bidi_len %d cmdsn %d win %d]\n",
|
||||
scsi_bidi_cmnd(sc) ? "bidirectional" :
|
||||
sc->sc_data_direction == DMA_TO_DEVICE ?
|
||||
"write" : "read", conn->id, sc, sc->cmnd[0],
|
||||
task->itt, scsi_bufflen(sc),
|
||||
scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
|
||||
session->cmdsn,
|
||||
session->max_cmdsn - session->exp_cmdsn + 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -483,9 +517,9 @@ static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
|
||||
|
||||
task->state = ISCSI_TASK_RUNNING;
|
||||
list_move_tail(&task->running, &conn->mgmt_run_list);
|
||||
debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n",
|
||||
hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt,
|
||||
task->data_count);
|
||||
ISCSI_DBG_SESSION(session, "mgmtpdu [op 0x%x hdr->itt 0x%x "
|
||||
"datalen %d]\n", hdr->opcode & ISCSI_OPCODE_MASK,
|
||||
hdr->itt, task->data_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -560,7 +594,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
|
||||
goto free_task;
|
||||
|
||||
} else
|
||||
scsi_queue_work(conn->session->host, &conn->xmitwork);
|
||||
iscsi_conn_queue_work(conn);
|
||||
|
||||
return task;
|
||||
|
||||
@ -637,8 +671,9 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
|
||||
|
||||
memcpy(sc->sense_buffer, data + 2,
|
||||
min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
|
||||
debug_scsi("copied %d bytes of sense\n",
|
||||
min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
|
||||
ISCSI_DBG_SESSION(session, "copied %d bytes of sense\n",
|
||||
min_t(uint16_t, senselen,
|
||||
SCSI_SENSE_BUFFERSIZE));
|
||||
}
|
||||
|
||||
if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
|
||||
@ -666,8 +701,8 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
|
||||
sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
|
||||
}
|
||||
out:
|
||||
debug_scsi("done [sc %lx res %d itt 0x%x]\n",
|
||||
(long)sc, sc->result, task->itt);
|
||||
ISCSI_DBG_SESSION(session, "done [sc %p res %d itt 0x%x]\n",
|
||||
sc, sc->result, task->itt);
|
||||
conn->scsirsp_pdus_cnt++;
|
||||
|
||||
__iscsi_put_task(task);
|
||||
@ -835,8 +870,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
|
||||
else
|
||||
itt = ~0U;
|
||||
|
||||
debug_scsi("[op 0x%x cid %d itt 0x%x len %d]\n",
|
||||
opcode, conn->id, itt, datalen);
|
||||
ISCSI_DBG_SESSION(session, "[op 0x%x cid %d itt 0x%x len %d]\n",
|
||||
opcode, conn->id, itt, datalen);
|
||||
|
||||
if (itt == ~0U) {
|
||||
iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
|
||||
@ -1034,10 +1069,9 @@ struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iscsi_itt_to_ctask);
|
||||
|
||||
void iscsi_session_failure(struct iscsi_cls_session *cls_session,
|
||||
void iscsi_session_failure(struct iscsi_session *session,
|
||||
enum iscsi_err err)
|
||||
{
|
||||
struct iscsi_session *session = cls_session->dd_data;
|
||||
struct iscsi_conn *conn;
|
||||
struct device *dev;
|
||||
unsigned long flags;
|
||||
@ -1095,10 +1129,10 @@ static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn)
|
||||
* Check for iSCSI window and take care of CmdSN wrap-around
|
||||
*/
|
||||
if (!iscsi_sna_lte(session->queued_cmdsn, session->max_cmdsn)) {
|
||||
debug_scsi("iSCSI CmdSN closed. ExpCmdSn %u MaxCmdSN %u "
|
||||
"CmdSN %u/%u\n", session->exp_cmdsn,
|
||||
session->max_cmdsn, session->cmdsn,
|
||||
session->queued_cmdsn);
|
||||
ISCSI_DBG_SESSION(session, "iSCSI CmdSN closed. ExpCmdSn "
|
||||
"%u MaxCmdSN %u CmdSN %u/%u\n",
|
||||
session->exp_cmdsn, session->max_cmdsn,
|
||||
session->cmdsn, session->queued_cmdsn);
|
||||
return -ENOSPC;
|
||||
}
|
||||
return 0;
|
||||
@ -1133,7 +1167,7 @@ void iscsi_requeue_task(struct iscsi_task *task)
|
||||
struct iscsi_conn *conn = task->conn;
|
||||
|
||||
list_move_tail(&task->running, &conn->requeue);
|
||||
scsi_queue_work(conn->session->host, &conn->xmitwork);
|
||||
iscsi_conn_queue_work(conn);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iscsi_requeue_task);
|
||||
|
||||
@ -1152,7 +1186,7 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
|
||||
|
||||
spin_lock_bh(&conn->session->lock);
|
||||
if (unlikely(conn->suspend_tx)) {
|
||||
debug_scsi("conn %d Tx suspended!\n", conn->id);
|
||||
ISCSI_DBG_SESSION(conn->session, "Tx suspended!\n");
|
||||
spin_unlock_bh(&conn->session->lock);
|
||||
return -ENODATA;
|
||||
}
|
||||
@ -1386,7 +1420,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
|
||||
goto prepd_reject;
|
||||
}
|
||||
} else
|
||||
scsi_queue_work(session->host, &conn->xmitwork);
|
||||
iscsi_conn_queue_work(conn);
|
||||
|
||||
session->queued_cmdsn++;
|
||||
spin_unlock(&session->lock);
|
||||
@ -1398,7 +1432,8 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
|
||||
iscsi_complete_command(task);
|
||||
reject:
|
||||
spin_unlock(&session->lock);
|
||||
debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason);
|
||||
ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n",
|
||||
sc->cmnd[0], reason);
|
||||
spin_lock(host->host_lock);
|
||||
return SCSI_MLQUEUE_TARGET_BUSY;
|
||||
|
||||
@ -1407,7 +1442,8 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
|
||||
iscsi_complete_command(task);
|
||||
fault:
|
||||
spin_unlock(&session->lock);
|
||||
debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason);
|
||||
ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n",
|
||||
sc->cmnd[0], reason);
|
||||
if (!scsi_bidi_cmnd(sc))
|
||||
scsi_set_resid(sc, scsi_bufflen(sc));
|
||||
else {
|
||||
@ -1422,8 +1458,6 @@ EXPORT_SYMBOL_GPL(iscsi_queuecommand);
|
||||
|
||||
int iscsi_change_queue_depth(struct scsi_device *sdev, int depth)
|
||||
{
|
||||
if (depth > ISCSI_MAX_CMD_PER_LUN)
|
||||
depth = ISCSI_MAX_CMD_PER_LUN;
|
||||
scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
|
||||
return sdev->queue_depth;
|
||||
}
|
||||
@ -1457,8 +1491,10 @@ int iscsi_eh_target_reset(struct scsi_cmnd *sc)
|
||||
spin_lock_bh(&session->lock);
|
||||
if (session->state == ISCSI_STATE_TERMINATE) {
|
||||
failed:
|
||||
debug_scsi("failing target reset: session terminated "
|
||||
"[CID %d age %d]\n", conn->id, session->age);
|
||||
iscsi_session_printk(KERN_INFO, session,
|
||||
"failing target reset: Could not log "
|
||||
"back into target [age %d]\n",
|
||||
session->age);
|
||||
spin_unlock_bh(&session->lock);
|
||||
mutex_unlock(&session->eh_mutex);
|
||||
return FAILED;
|
||||
@ -1472,7 +1508,7 @@ int iscsi_eh_target_reset(struct scsi_cmnd *sc)
|
||||
*/
|
||||
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
|
||||
|
||||
debug_scsi("iscsi_eh_target_reset wait for relogin\n");
|
||||
ISCSI_DBG_SESSION(session, "wait for relogin\n");
|
||||
wait_event_interruptible(conn->ehwait,
|
||||
session->state == ISCSI_STATE_TERMINATE ||
|
||||
session->state == ISCSI_STATE_LOGGED_IN ||
|
||||
@ -1501,7 +1537,7 @@ static void iscsi_tmf_timedout(unsigned long data)
|
||||
spin_lock(&session->lock);
|
||||
if (conn->tmf_state == TMF_QUEUED) {
|
||||
conn->tmf_state = TMF_TIMEDOUT;
|
||||
debug_scsi("tmf timedout\n");
|
||||
ISCSI_DBG_SESSION(session, "tmf timedout\n");
|
||||
/* unblock eh_abort() */
|
||||
wake_up(&conn->ehwait);
|
||||
}
|
||||
@ -1521,7 +1557,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
|
||||
spin_unlock_bh(&session->lock);
|
||||
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
|
||||
spin_lock_bh(&session->lock);
|
||||
debug_scsi("tmf exec failure\n");
|
||||
ISCSI_DBG_SESSION(session, "tmf exec failure\n");
|
||||
return -EPERM;
|
||||
}
|
||||
conn->tmfcmd_pdus_cnt++;
|
||||
@ -1529,7 +1565,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
|
||||
conn->tmf_timer.function = iscsi_tmf_timedout;
|
||||
conn->tmf_timer.data = (unsigned long)conn;
|
||||
add_timer(&conn->tmf_timer);
|
||||
debug_scsi("tmf set timeout\n");
|
||||
ISCSI_DBG_SESSION(session, "tmf set timeout\n");
|
||||
|
||||
spin_unlock_bh(&session->lock);
|
||||
mutex_unlock(&session->eh_mutex);
|
||||
@ -1567,22 +1603,27 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun,
|
||||
{
|
||||
struct iscsi_task *task, *tmp;
|
||||
|
||||
if (conn->task && (conn->task->sc->device->lun == lun || lun == -1))
|
||||
conn->task = NULL;
|
||||
if (conn->task) {
|
||||
if (lun == -1 ||
|
||||
(conn->task->sc && conn->task->sc->device->lun == lun))
|
||||
conn->task = NULL;
|
||||
}
|
||||
|
||||
/* flush pending */
|
||||
list_for_each_entry_safe(task, tmp, &conn->xmitqueue, running) {
|
||||
if (lun == task->sc->device->lun || lun == -1) {
|
||||
debug_scsi("failing pending sc %p itt 0x%x\n",
|
||||
task->sc, task->itt);
|
||||
ISCSI_DBG_SESSION(conn->session,
|
||||
"failing pending sc %p itt 0x%x\n",
|
||||
task->sc, task->itt);
|
||||
fail_command(conn, task, error << 16);
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(task, tmp, &conn->requeue, running) {
|
||||
if (lun == task->sc->device->lun || lun == -1) {
|
||||
debug_scsi("failing requeued sc %p itt 0x%x\n",
|
||||
task->sc, task->itt);
|
||||
ISCSI_DBG_SESSION(conn->session,
|
||||
"failing requeued sc %p itt 0x%x\n",
|
||||
task->sc, task->itt);
|
||||
fail_command(conn, task, error << 16);
|
||||
}
|
||||
}
|
||||
@ -1590,8 +1631,9 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun,
|
||||
/* fail all other running */
|
||||
list_for_each_entry_safe(task, tmp, &conn->run_list, running) {
|
||||
if (lun == task->sc->device->lun || lun == -1) {
|
||||
debug_scsi("failing in progress sc %p itt 0x%x\n",
|
||||
task->sc, task->itt);
|
||||
ISCSI_DBG_SESSION(conn->session,
|
||||
"failing in progress sc %p itt 0x%x\n",
|
||||
task->sc, task->itt);
|
||||
fail_command(conn, task, error << 16);
|
||||
}
|
||||
}
|
||||
@ -1599,9 +1641,12 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun,
|
||||
|
||||
void iscsi_suspend_tx(struct iscsi_conn *conn)
|
||||
{
|
||||
struct Scsi_Host *shost = conn->session->host;
|
||||
struct iscsi_host *ihost = shost_priv(shost);
|
||||
|
||||
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
|
||||
if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
|
||||
scsi_flush_work(conn->session->host);
|
||||
flush_workqueue(ihost->workq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iscsi_suspend_tx);
|
||||
|
||||
@ -1609,7 +1654,7 @@ static void iscsi_start_tx(struct iscsi_conn *conn)
|
||||
{
|
||||
clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
|
||||
if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
|
||||
scsi_queue_work(conn->session->host, &conn->xmitwork);
|
||||
iscsi_conn_queue_work(conn);
|
||||
}
|
||||
|
||||
static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
|
||||
@ -1622,7 +1667,7 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
|
||||
cls_session = starget_to_session(scsi_target(scmd->device));
|
||||
session = cls_session->dd_data;
|
||||
|
||||
debug_scsi("scsi cmd %p timedout\n", scmd);
|
||||
ISCSI_DBG_SESSION(session, "scsi cmd %p timedout\n", scmd);
|
||||
|
||||
spin_lock(&session->lock);
|
||||
if (session->state != ISCSI_STATE_LOGGED_IN) {
|
||||
@ -1662,8 +1707,8 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
|
||||
rc = BLK_EH_RESET_TIMER;
|
||||
done:
|
||||
spin_unlock(&session->lock);
|
||||
debug_scsi("return %s\n", rc == BLK_EH_RESET_TIMER ?
|
||||
"timer reset" : "nh");
|
||||
ISCSI_DBG_SESSION(session, "return %s\n", rc == BLK_EH_RESET_TIMER ?
|
||||
"timer reset" : "nh");
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1697,13 +1742,13 @@ static void iscsi_check_transport_timeouts(unsigned long data)
|
||||
|
||||
if (time_before_eq(last_recv + recv_timeout, jiffies)) {
|
||||
/* send a ping to try to provoke some traffic */
|
||||
debug_scsi("Sending nopout as ping on conn %p\n", conn);
|
||||
ISCSI_DBG_CONN(conn, "Sending nopout as ping\n");
|
||||
iscsi_send_nopout(conn, NULL);
|
||||
next_timeout = conn->last_ping + (conn->ping_timeout * HZ);
|
||||
} else
|
||||
next_timeout = last_recv + recv_timeout;
|
||||
|
||||
debug_scsi("Setting next tmo %lu\n", next_timeout);
|
||||
ISCSI_DBG_CONN(conn, "Setting next tmo %lu\n", next_timeout);
|
||||
mod_timer(&conn->transport_timer, next_timeout);
|
||||
done:
|
||||
spin_unlock(&session->lock);
|
||||
@ -1740,7 +1785,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
|
||||
* got the command.
|
||||
*/
|
||||
if (!sc->SCp.ptr) {
|
||||
debug_scsi("sc never reached iscsi layer or it completed.\n");
|
||||
ISCSI_DBG_SESSION(session, "sc never reached iscsi layer or "
|
||||
"it completed.\n");
|
||||
spin_unlock_bh(&session->lock);
|
||||
mutex_unlock(&session->eh_mutex);
|
||||
return SUCCESS;
|
||||
@ -1762,11 +1808,13 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
|
||||
age = session->age;
|
||||
|
||||
task = (struct iscsi_task *)sc->SCp.ptr;
|
||||
debug_scsi("aborting [sc %p itt 0x%x]\n", sc, task->itt);
|
||||
ISCSI_DBG_SESSION(session, "aborting [sc %p itt 0x%x]\n",
|
||||
sc, task->itt);
|
||||
|
||||
/* task completed before time out */
|
||||
if (!task->sc) {
|
||||
debug_scsi("sc completed while abort in progress\n");
|
||||
ISCSI_DBG_SESSION(session, "sc completed while abort in "
|
||||
"progress\n");
|
||||
goto success;
|
||||
}
|
||||
|
||||
@ -1815,7 +1863,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
|
||||
if (!sc->SCp.ptr) {
|
||||
conn->tmf_state = TMF_INITIAL;
|
||||
/* task completed before tmf abort response */
|
||||
debug_scsi("sc completed while abort in progress\n");
|
||||
ISCSI_DBG_SESSION(session, "sc completed while abort "
|
||||
"in progress\n");
|
||||
goto success;
|
||||
}
|
||||
/* fall through */
|
||||
@ -1827,15 +1876,16 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
|
||||
success:
|
||||
spin_unlock_bh(&session->lock);
|
||||
success_unlocked:
|
||||
debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, task->itt);
|
||||
ISCSI_DBG_SESSION(session, "abort success [sc %p itt 0x%x]\n",
|
||||
sc, task->itt);
|
||||
mutex_unlock(&session->eh_mutex);
|
||||
return SUCCESS;
|
||||
|
||||
failed:
|
||||
spin_unlock_bh(&session->lock);
|
||||
failed_unlocked:
|
||||
debug_scsi("abort failed [sc %p itt 0x%x]\n", sc,
|
||||
task ? task->itt : 0);
|
||||
ISCSI_DBG_SESSION(session, "abort failed [sc %p itt 0x%x]\n", sc,
|
||||
task ? task->itt : 0);
|
||||
mutex_unlock(&session->eh_mutex);
|
||||
return FAILED;
|
||||
}
|
||||
@ -1862,7 +1912,8 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
|
||||
cls_session = starget_to_session(scsi_target(sc->device));
|
||||
session = cls_session->dd_data;
|
||||
|
||||
debug_scsi("LU Reset [sc %p lun %u]\n", sc, sc->device->lun);
|
||||
ISCSI_DBG_SESSION(session, "LU Reset [sc %p lun %u]\n",
|
||||
sc, sc->device->lun);
|
||||
|
||||
mutex_lock(&session->eh_mutex);
|
||||
spin_lock_bh(&session->lock);
|
||||
@ -1916,8 +1967,8 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
|
||||
unlock:
|
||||
spin_unlock_bh(&session->lock);
|
||||
done:
|
||||
debug_scsi("iscsi_eh_device_reset %s\n",
|
||||
rc == SUCCESS ? "SUCCESS" : "FAILED");
|
||||
ISCSI_DBG_SESSION(session, "dev reset result = %s\n",
|
||||
rc == SUCCESS ? "SUCCESS" : "FAILED");
|
||||
mutex_unlock(&session->eh_mutex);
|
||||
return rc;
|
||||
}
|
||||
@ -1944,7 +1995,7 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
|
||||
num_arrays++;
|
||||
q->pool = kzalloc(num_arrays * max * sizeof(void*), GFP_KERNEL);
|
||||
if (q->pool == NULL)
|
||||
goto enomem;
|
||||
return -ENOMEM;
|
||||
|
||||
q->queue = kfifo_init((void*)q->pool, max * sizeof(void*),
|
||||
GFP_KERNEL, NULL);
|
||||
@ -1979,8 +2030,7 @@ void iscsi_pool_free(struct iscsi_pool *q)
|
||||
|
||||
for (i = 0; i < q->max; i++)
|
||||
kfree(q->pool[i]);
|
||||
if (q->pool)
|
||||
kfree(q->pool);
|
||||
kfree(q->pool);
|
||||
kfree(q->queue);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iscsi_pool_free);
|
||||
@ -1998,6 +2048,9 @@ int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev)
|
||||
if (!shost->can_queue)
|
||||
shost->can_queue = ISCSI_DEF_XMIT_CMDS_MAX;
|
||||
|
||||
if (!shost->cmd_per_lun)
|
||||
shost->cmd_per_lun = ISCSI_DEF_CMD_PER_LUN;
|
||||
|
||||
if (!shost->transportt->eh_timed_out)
|
||||
shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
|
||||
return scsi_add_host(shost, pdev);
|
||||
@ -2008,13 +2061,13 @@ EXPORT_SYMBOL_GPL(iscsi_host_add);
|
||||
* iscsi_host_alloc - allocate a host and driver data
|
||||
* @sht: scsi host template
|
||||
* @dd_data_size: driver host data size
|
||||
* @qdepth: default device queue depth
|
||||
* @xmit_can_sleep: bool indicating if LLD will queue IO from a work queue
|
||||
*
|
||||
* This should be called by partial offload and software iscsi drivers.
|
||||
* To access the driver specific memory use the iscsi_host_priv() macro.
|
||||
*/
|
||||
struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
|
||||
int dd_data_size, uint16_t qdepth)
|
||||
int dd_data_size, bool xmit_can_sleep)
|
||||
{
|
||||
struct Scsi_Host *shost;
|
||||
struct iscsi_host *ihost;
|
||||
@ -2022,28 +2075,31 @@ struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
|
||||
shost = scsi_host_alloc(sht, sizeof(struct iscsi_host) + dd_data_size);
|
||||
if (!shost)
|
||||
return NULL;
|
||||
|
||||
if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) {
|
||||
if (qdepth != 0)
|
||||
printk(KERN_ERR "iscsi: invalid queue depth of %d. "
|
||||
"Queue depth must be between 1 and %d.\n",
|
||||
qdepth, ISCSI_MAX_CMD_PER_LUN);
|
||||
qdepth = ISCSI_DEF_CMD_PER_LUN;
|
||||
}
|
||||
shost->cmd_per_lun = qdepth;
|
||||
|
||||
ihost = shost_priv(shost);
|
||||
|
||||
if (xmit_can_sleep) {
|
||||
snprintf(ihost->workq_name, sizeof(ihost->workq_name),
|
||||
"iscsi_q_%d", shost->host_no);
|
||||
ihost->workq = create_singlethread_workqueue(ihost->workq_name);
|
||||
if (!ihost->workq)
|
||||
goto free_host;
|
||||
}
|
||||
|
||||
spin_lock_init(&ihost->lock);
|
||||
ihost->state = ISCSI_HOST_SETUP;
|
||||
ihost->num_sessions = 0;
|
||||
init_waitqueue_head(&ihost->session_removal_wq);
|
||||
return shost;
|
||||
|
||||
free_host:
|
||||
scsi_host_put(shost);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iscsi_host_alloc);
|
||||
|
||||
static void iscsi_notify_host_removed(struct iscsi_cls_session *cls_session)
|
||||
{
|
||||
iscsi_session_failure(cls_session, ISCSI_ERR_INVALID_HOST);
|
||||
iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_INVALID_HOST);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2069,6 +2125,8 @@ void iscsi_host_remove(struct Scsi_Host *shost)
|
||||
flush_signals(current);
|
||||
|
||||
scsi_remove_host(shost);
|
||||
if (ihost->workq)
|
||||
destroy_workqueue(ihost->workq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iscsi_host_remove);
|
||||
|
||||
@ -2467,14 +2525,16 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn)
|
||||
|
||||
/* handle pending */
|
||||
list_for_each_entry_safe(task, tmp, &conn->mgmtqueue, running) {
|
||||
debug_scsi("flushing pending mgmt task itt 0x%x\n", task->itt);
|
||||
ISCSI_DBG_SESSION(session, "flushing pending mgmt task "
|
||||
"itt 0x%x\n", task->itt);
|
||||
/* release ref from prep task */
|
||||
__iscsi_put_task(task);
|
||||
}
|
||||
|
||||
/* handle running */
|
||||
list_for_each_entry_safe(task, tmp, &conn->mgmt_run_list, running) {
|
||||
debug_scsi("flushing running mgmt task itt 0x%x\n", task->itt);
|
||||
ISCSI_DBG_SESSION(session, "flushing running mgmt task "
|
||||
"itt 0x%x\n", task->itt);
|
||||
/* release ref from prep task */
|
||||
__iscsi_put_task(task);
|
||||
}
|
||||
@ -2524,7 +2584,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
|
||||
conn->datadgst_en = 0;
|
||||
if (session->state == ISCSI_STATE_IN_RECOVERY &&
|
||||
old_stop_stage != STOP_CONN_RECOVER) {
|
||||
debug_scsi("blocking session\n");
|
||||
ISCSI_DBG_SESSION(session, "blocking session\n");
|
||||
iscsi_block_session(session->cls_session);
|
||||
}
|
||||
}
|
||||
|
@ -49,13 +49,21 @@ 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 int iscsi_dbg_libtcp;
|
||||
module_param_named(debug_libiscsi_tcp, iscsi_dbg_libtcp, int,
|
||||
S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(debug_libiscsi_tcp, "Turn on debugging for libiscsi_tcp "
|
||||
"module. Set to 1 to turn on, and zero to turn off. Default "
|
||||
"is off.");
|
||||
|
||||
#define ISCSI_DBG_TCP(_conn, dbg_fmt, arg...) \
|
||||
do { \
|
||||
if (iscsi_dbg_libtcp) \
|
||||
iscsi_conn_printk(KERN_INFO, _conn, \
|
||||
"%s " dbg_fmt, \
|
||||
__func__, ##arg); \
|
||||
} while (0);
|
||||
|
||||
static int iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn,
|
||||
struct iscsi_segment *segment);
|
||||
@ -123,18 +131,13 @@ static void iscsi_tcp_segment_map(struct iscsi_segment *segment, int recv)
|
||||
if (page_count(sg_page(sg)) >= 1 && !recv)
|
||||
return;
|
||||
|
||||
debug_tcp("iscsi_tcp_segment_map %s %p\n", recv ? "recv" : "xmit",
|
||||
segment);
|
||||
segment->sg_mapped = kmap_atomic(sg_page(sg), KM_SOFTIRQ0);
|
||||
segment->data = segment->sg_mapped + sg->offset + segment->sg_offset;
|
||||
}
|
||||
|
||||
void iscsi_tcp_segment_unmap(struct iscsi_segment *segment)
|
||||
{
|
||||
debug_tcp("iscsi_tcp_segment_unmap %p\n", segment);
|
||||
|
||||
if (segment->sg_mapped) {
|
||||
debug_tcp("iscsi_tcp_segment_unmap valid\n");
|
||||
kunmap_atomic(segment->sg_mapped, KM_SOFTIRQ0);
|
||||
segment->sg_mapped = NULL;
|
||||
segment->data = NULL;
|
||||
@ -180,8 +183,9 @@ int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn,
|
||||
struct scatterlist sg;
|
||||
unsigned int pad;
|
||||
|
||||
debug_tcp("copied %u %u size %u %s\n", segment->copied, copied,
|
||||
segment->size, recv ? "recv" : "xmit");
|
||||
ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "copied %u %u size %u %s\n",
|
||||
segment->copied, copied, segment->size,
|
||||
recv ? "recv" : "xmit");
|
||||
if (segment->hash && copied) {
|
||||
/*
|
||||
* If a segment is kmapd we must unmap it before sending
|
||||
@ -214,8 +218,8 @@ int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn,
|
||||
iscsi_tcp_segment_unmap(segment);
|
||||
|
||||
/* Do we have more scatterlist entries? */
|
||||
debug_tcp("total copied %u total size %u\n", segment->total_copied,
|
||||
segment->total_size);
|
||||
ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "total copied %u total size %u\n",
|
||||
segment->total_copied, segment->total_size);
|
||||
if (segment->total_copied < segment->total_size) {
|
||||
/* Proceed to the next entry in the scatterlist. */
|
||||
iscsi_tcp_segment_init_sg(segment, sg_next(segment->sg),
|
||||
@ -229,7 +233,8 @@ int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn,
|
||||
if (!(tcp_conn->iscsi_conn->session->tt->caps & CAP_PADDING_OFFLOAD)) {
|
||||
pad = iscsi_padding(segment->total_copied);
|
||||
if (pad != 0) {
|
||||
debug_tcp("consume %d pad bytes\n", pad);
|
||||
ISCSI_DBG_TCP(tcp_conn->iscsi_conn,
|
||||
"consume %d pad bytes\n", pad);
|
||||
segment->total_size += pad;
|
||||
segment->size = pad;
|
||||
segment->data = segment->padbuf;
|
||||
@ -278,13 +283,13 @@ iscsi_tcp_segment_recv(struct iscsi_tcp_conn *tcp_conn,
|
||||
|
||||
while (!iscsi_tcp_segment_done(tcp_conn, segment, 1, copy)) {
|
||||
if (copied == len) {
|
||||
debug_tcp("iscsi_tcp_segment_recv copied %d bytes\n",
|
||||
len);
|
||||
ISCSI_DBG_TCP(tcp_conn->iscsi_conn,
|
||||
"copied %d bytes\n", len);
|
||||
break;
|
||||
}
|
||||
|
||||
copy = min(len - copied, segment->size - segment->copied);
|
||||
debug_tcp("iscsi_tcp_segment_recv copying %d\n", copy);
|
||||
ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "copying %d\n", copy);
|
||||
memcpy(segment->data + segment->copied, ptr + copied, copy);
|
||||
copied += copy;
|
||||
}
|
||||
@ -311,7 +316,7 @@ iscsi_tcp_dgst_verify(struct iscsi_tcp_conn *tcp_conn,
|
||||
|
||||
if (memcmp(segment->recv_digest, segment->digest,
|
||||
segment->digest_len)) {
|
||||
debug_scsi("digest mismatch\n");
|
||||
ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "digest mismatch\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -355,12 +360,8 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment,
|
||||
struct scatterlist *sg;
|
||||
unsigned int i;
|
||||
|
||||
debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n",
|
||||
offset, size);
|
||||
__iscsi_segment_init(segment, size, done, hash);
|
||||
for_each_sg(sg_list, sg, sg_count, i) {
|
||||
debug_scsi("sg %d, len %u offset %u\n", i, sg->length,
|
||||
sg->offset);
|
||||
if (offset < sg->length) {
|
||||
iscsi_tcp_segment_init_sg(segment, sg, offset);
|
||||
return 0;
|
||||
@ -382,8 +383,9 @@ EXPORT_SYMBOL_GPL(iscsi_segment_seek_sg);
|
||||
*/
|
||||
void iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn)
|
||||
{
|
||||
debug_tcp("iscsi_tcp_hdr_recv_prep(%p%s)\n", tcp_conn,
|
||||
tcp_conn->iscsi_conn->hdrdgst_en ? ", digest enabled" : "");
|
||||
ISCSI_DBG_TCP(tcp_conn->iscsi_conn,
|
||||
"(%s)\n", tcp_conn->iscsi_conn->hdrdgst_en ?
|
||||
"digest enabled" : "digest disabled");
|
||||
iscsi_segment_init_linear(&tcp_conn->in.segment,
|
||||
tcp_conn->in.hdr_buf, sizeof(struct iscsi_hdr),
|
||||
iscsi_tcp_hdr_recv_done, NULL);
|
||||
@ -446,7 +448,7 @@ void iscsi_tcp_cleanup_task(struct iscsi_task *task)
|
||||
while (__kfifo_get(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
|
||||
__kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
|
||||
sizeof(void*));
|
||||
debug_scsi("iscsi_tcp_cleanup_task pending r2t dropped\n");
|
||||
ISCSI_DBG_TCP(task->conn, "pending r2t dropped\n");
|
||||
}
|
||||
|
||||
r2t = tcp_task->r2t;
|
||||
@ -476,8 +478,8 @@ static int iscsi_tcp_data_in(struct iscsi_conn *conn, struct iscsi_task *task)
|
||||
return 0;
|
||||
|
||||
if (tcp_task->exp_datasn != datasn) {
|
||||
debug_tcp("%s: task->exp_datasn(%d) != rhdr->datasn(%d)\n",
|
||||
__func__, tcp_task->exp_datasn, datasn);
|
||||
ISCSI_DBG_TCP(conn, "task->exp_datasn(%d) != rhdr->datasn(%d)"
|
||||
"\n", tcp_task->exp_datasn, datasn);
|
||||
return ISCSI_ERR_DATASN;
|
||||
}
|
||||
|
||||
@ -485,9 +487,9 @@ static int iscsi_tcp_data_in(struct iscsi_conn *conn, struct iscsi_task *task)
|
||||
|
||||
tcp_task->data_offset = be32_to_cpu(rhdr->offset);
|
||||
if (tcp_task->data_offset + tcp_conn->in.datalen > total_in_length) {
|
||||
debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n",
|
||||
__func__, tcp_task->data_offset,
|
||||
tcp_conn->in.datalen, total_in_length);
|
||||
ISCSI_DBG_TCP(conn, "data_offset(%d) + data_len(%d) > "
|
||||
"total_length_in(%d)\n", tcp_task->data_offset,
|
||||
tcp_conn->in.datalen, total_in_length);
|
||||
return ISCSI_ERR_DATA_OFFSET;
|
||||
}
|
||||
|
||||
@ -518,8 +520,8 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
|
||||
}
|
||||
|
||||
if (tcp_task->exp_datasn != r2tsn){
|
||||
debug_tcp("%s: task->exp_datasn(%d) != rhdr->r2tsn(%d)\n",
|
||||
__func__, tcp_task->exp_datasn, r2tsn);
|
||||
ISCSI_DBG_TCP(conn, "task->exp_datasn(%d) != rhdr->r2tsn(%d)\n",
|
||||
tcp_task->exp_datasn, r2tsn);
|
||||
return ISCSI_ERR_R2TSN;
|
||||
}
|
||||
|
||||
@ -552,9 +554,9 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
|
||||
}
|
||||
|
||||
if (r2t->data_length > session->max_burst)
|
||||
debug_scsi("invalid R2T with data len %u and max burst %u."
|
||||
"Attempting to execute request.\n",
|
||||
r2t->data_length, session->max_burst);
|
||||
ISCSI_DBG_TCP(conn, "invalid R2T with data len %u and max "
|
||||
"burst %u. Attempting to execute request.\n",
|
||||
r2t->data_length, session->max_burst);
|
||||
|
||||
r2t->data_offset = be32_to_cpu(rhdr->data_offset);
|
||||
if (r2t->data_offset + r2t->data_length > scsi_out(task->sc)->length) {
|
||||
@ -641,8 +643,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
debug_tcp("opcode 0x%x ahslen %d datalen %d\n",
|
||||
opcode, ahslen, tcp_conn->in.datalen);
|
||||
ISCSI_DBG_TCP(conn, "opcode 0x%x ahslen %d datalen %d\n",
|
||||
opcode, ahslen, tcp_conn->in.datalen);
|
||||
|
||||
switch(opcode) {
|
||||
case ISCSI_OP_SCSI_DATA_IN:
|
||||
@ -674,10 +676,10 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
|
||||
!(conn->session->tt->caps & CAP_DIGEST_OFFLOAD))
|
||||
rx_hash = tcp_conn->rx_hash;
|
||||
|
||||
debug_tcp("iscsi_tcp_begin_data_in(%p, offset=%d, "
|
||||
"datalen=%d)\n", tcp_conn,
|
||||
tcp_task->data_offset,
|
||||
tcp_conn->in.datalen);
|
||||
ISCSI_DBG_TCP(conn, "iscsi_tcp_begin_data_in( "
|
||||
"offset=%d, datalen=%d)\n",
|
||||
tcp_task->data_offset,
|
||||
tcp_conn->in.datalen);
|
||||
rc = iscsi_segment_seek_sg(&tcp_conn->in.segment,
|
||||
sdb->table.sgl,
|
||||
sdb->table.nents,
|
||||
@ -854,10 +856,10 @@ int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb,
|
||||
unsigned int consumed = 0;
|
||||
int rc = 0;
|
||||
|
||||
debug_tcp("in %d bytes\n", skb->len - offset);
|
||||
ISCSI_DBG_TCP(conn, "in %d bytes\n", skb->len - offset);
|
||||
|
||||
if (unlikely(conn->suspend_rx)) {
|
||||
debug_tcp("conn %d Rx suspended!\n", conn->id);
|
||||
ISCSI_DBG_TCP(conn, "Rx suspended!\n");
|
||||
*status = ISCSI_TCP_SUSPENDED;
|
||||
return 0;
|
||||
}
|
||||
@ -874,15 +876,16 @@ int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb,
|
||||
|
||||
avail = skb_seq_read(consumed, &ptr, &seq);
|
||||
if (avail == 0) {
|
||||
debug_tcp("no more data avail. Consumed %d\n",
|
||||
consumed);
|
||||
ISCSI_DBG_TCP(conn, "no more data avail. Consumed %d\n",
|
||||
consumed);
|
||||
*status = ISCSI_TCP_SKB_DONE;
|
||||
skb_abort_seq_read(&seq);
|
||||
goto skb_done;
|
||||
}
|
||||
BUG_ON(segment->copied >= segment->size);
|
||||
|
||||
debug_tcp("skb %p ptr=%p avail=%u\n", skb, ptr, avail);
|
||||
ISCSI_DBG_TCP(conn, "skb %p ptr=%p avail=%u\n", skb, ptr,
|
||||
avail);
|
||||
rc = iscsi_tcp_segment_recv(tcp_conn, segment, ptr, avail);
|
||||
BUG_ON(rc == 0);
|
||||
consumed += rc;
|
||||
@ -895,11 +898,11 @@ int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb,
|
||||
|
||||
segment_done:
|
||||
*status = ISCSI_TCP_SEGMENT_DONE;
|
||||
debug_tcp("segment done\n");
|
||||
ISCSI_DBG_TCP(conn, "segment done\n");
|
||||
rc = segment->done(tcp_conn, segment);
|
||||
if (rc != 0) {
|
||||
*status = ISCSI_TCP_CONN_ERR;
|
||||
debug_tcp("Error receiving PDU, errno=%d\n", rc);
|
||||
ISCSI_DBG_TCP(conn, "Error receiving PDU, errno=%d\n", rc);
|
||||
iscsi_conn_failure(conn, rc);
|
||||
return 0;
|
||||
}
|
||||
@ -929,8 +932,7 @@ int iscsi_tcp_task_init(struct iscsi_task *task)
|
||||
* mgmt tasks do not have a scatterlist since they come
|
||||
* in from the iscsi interface.
|
||||
*/
|
||||
debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id,
|
||||
task->itt);
|
||||
ISCSI_DBG_TCP(conn, "mtask deq [itt 0x%x]\n", task->itt);
|
||||
|
||||
return conn->session->tt->init_pdu(task, 0, task->data_count);
|
||||
}
|
||||
@ -939,9 +941,8 @@ int iscsi_tcp_task_init(struct iscsi_task *task)
|
||||
tcp_task->exp_datasn = 0;
|
||||
|
||||
/* Prepare PDU, optionally w/ immediate data */
|
||||
debug_scsi("task deq [cid %d itt 0x%x imm %d unsol %d]\n",
|
||||
conn->id, task->itt, task->imm_count,
|
||||
task->unsol_r2t.data_length);
|
||||
ISCSI_DBG_TCP(conn, "task deq [itt 0x%x imm %d unsol %d]\n",
|
||||
task->itt, task->imm_count, task->unsol_r2t.data_length);
|
||||
|
||||
err = conn->session->tt->init_pdu(task, 0, task->imm_count);
|
||||
if (err)
|
||||
@ -965,7 +966,8 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
|
||||
r2t = tcp_task->r2t;
|
||||
/* Continue with this R2T? */
|
||||
if (r2t->data_length <= r2t->sent) {
|
||||
debug_scsi(" done with r2t %p\n", r2t);
|
||||
ISCSI_DBG_TCP(task->conn,
|
||||
" done with r2t %p\n", r2t);
|
||||
__kfifo_put(tcp_task->r2tpool.queue,
|
||||
(void *)&tcp_task->r2t,
|
||||
sizeof(void *));
|
||||
@ -1019,7 +1021,7 @@ int iscsi_tcp_task_xmit(struct iscsi_task *task)
|
||||
r2t = iscsi_tcp_get_curr_r2t(task);
|
||||
if (r2t == NULL) {
|
||||
/* Waiting for more R2Ts to arrive. */
|
||||
debug_tcp("no R2Ts yet\n");
|
||||
ISCSI_DBG_TCP(conn, "no R2Ts yet\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1028,9 +1030,9 @@ int iscsi_tcp_task_xmit(struct iscsi_task *task)
|
||||
return rc;
|
||||
iscsi_prep_data_out_pdu(task, r2t, (struct iscsi_data *) task->hdr);
|
||||
|
||||
debug_scsi("sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n",
|
||||
r2t, r2t->datasn - 1, task->hdr->itt,
|
||||
r2t->data_offset + r2t->sent, r2t->data_count);
|
||||
ISCSI_DBG_TCP(conn, "sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n",
|
||||
r2t, r2t->datasn - 1, task->hdr->itt,
|
||||
r2t->data_offset + r2t->sent, r2t->data_count);
|
||||
|
||||
rc = conn->session->tt->init_pdu(task, r2t->data_offset + r2t->sent,
|
||||
r2t->data_count);
|
||||
|
@ -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++;
|
||||
|
66
drivers/scsi/mpt2sas/Kconfig
Normal file
66
drivers/scsi/mpt2sas/Kconfig
Normal file
@ -0,0 +1,66 @@
|
||||
#
|
||||
# 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.
|
7
drivers/scsi/mpt2sas/Makefile
Normal file
7
drivers/scsi/mpt2sas/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
# 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
|
1067
drivers/scsi/mpt2sas/mpi/mpi2.h
Normal file
1067
drivers/scsi/mpt2sas/mpi/mpi2.h
Normal file
File diff suppressed because it is too large
Load Diff
2151
drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
Normal file
2151
drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
Normal file
File diff suppressed because it is too large
Load Diff
420
drivers/scsi/mpt2sas/mpi/mpi2_init.h
Normal file
420
drivers/scsi/mpt2sas/mpi/mpi2_init.h
Normal file
@ -0,0 +1,420 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2008 LSI Corporation.
|
||||
*
|
||||
*
|
||||
* Name: mpi2_init.h
|
||||
* Title: MPI SCSI initiator mode messages and structures
|
||||
* Creation Date: June 23, 2006
|
||||
*
|
||||
* mpi2_init.h Version: 02.00.06
|
||||
*
|
||||
* Version History
|
||||
* ---------------
|
||||
*
|
||||
* Date Version Description
|
||||
* -------- -------- ------------------------------------------------------
|
||||
* 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
|
||||
* 10-31-07 02.00.01 Fixed name for pMpi2SCSITaskManagementRequest_t.
|
||||
* 12-18-07 02.00.02 Modified Task Management Target Reset Method defines.
|
||||
* 02-29-08 02.00.03 Added Query Task Set and Query Unit Attention.
|
||||
* 03-03-08 02.00.04 Fixed name of struct _MPI2_SCSI_TASK_MANAGE_REPLY.
|
||||
* 05-21-08 02.00.05 Fixed typo in name of Mpi2SepRequest_t.
|
||||
* 10-02-08 02.00.06 Removed Untagged and No Disconnect values from SCSI IO
|
||||
* Control field Task Attribute flags.
|
||||
* Moved LUN field defines to mpi2.h becasue they are
|
||||
* common to many structures.
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef MPI2_INIT_H
|
||||
#define MPI2_INIT_H
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* SCSI Initiator Messages
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* SCSI IO messages and associated structures
|
||||
****************************************************************************/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
U8 CDB[20]; /* 0x00 */
|
||||
U32 PrimaryReferenceTag; /* 0x14 */
|
||||
U16 PrimaryApplicationTag; /* 0x18 */
|
||||
U16 PrimaryApplicationTagMask; /* 0x1A */
|
||||
U32 TransferLength; /* 0x1C */
|
||||
} MPI2_SCSI_IO_CDB_EEDP32, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_EEDP32,
|
||||
Mpi2ScsiIoCdbEedp32_t, MPI2_POINTER pMpi2ScsiIoCdbEedp32_t;
|
||||
|
||||
/* TBD: I don't think this is needed for MPI2/Gen2 */
|
||||
#if 0
|
||||
typedef struct
|
||||
{
|
||||
U8 CDB[16]; /* 0x00 */
|
||||
U32 DataLength; /* 0x10 */
|
||||
U32 PrimaryReferenceTag; /* 0x14 */
|
||||
U16 PrimaryApplicationTag; /* 0x18 */
|
||||
U16 PrimaryApplicationTagMask; /* 0x1A */
|
||||
U32 TransferLength; /* 0x1C */
|
||||
} MPI2_SCSI_IO32_CDB_EEDP16, MPI2_POINTER PTR_MPI2_SCSI_IO32_CDB_EEDP16,
|
||||
Mpi2ScsiIo32CdbEedp16_t, MPI2_POINTER pMpi2ScsiIo32CdbEedp16_t;
|
||||
#endif
|
||||
|
||||
typedef union
|
||||
{
|
||||
U8 CDB32[32];
|
||||
MPI2_SCSI_IO_CDB_EEDP32 EEDP32;
|
||||
MPI2_SGE_SIMPLE_UNION SGE;
|
||||
} MPI2_SCSI_IO_CDB_UNION, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_UNION,
|
||||
Mpi2ScsiIoCdb_t, MPI2_POINTER pMpi2ScsiIoCdb_t;
|
||||
|
||||
/* SCSI IO Request Message */
|
||||
typedef struct _MPI2_SCSI_IO_REQUEST
|
||||
{
|
||||
U16 DevHandle; /* 0x00 */
|
||||
U8 ChainOffset; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U16 Reserved1; /* 0x04 */
|
||||
U8 Reserved2; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved3; /* 0x0A */
|
||||
U32 SenseBufferLowAddress; /* 0x0C */
|
||||
U16 SGLFlags; /* 0x10 */
|
||||
U8 SenseBufferLength; /* 0x12 */
|
||||
U8 Reserved4; /* 0x13 */
|
||||
U8 SGLOffset0; /* 0x14 */
|
||||
U8 SGLOffset1; /* 0x15 */
|
||||
U8 SGLOffset2; /* 0x16 */
|
||||
U8 SGLOffset3; /* 0x17 */
|
||||
U32 SkipCount; /* 0x18 */
|
||||
U32 DataLength; /* 0x1C */
|
||||
U32 BidirectionalDataLength; /* 0x20 */
|
||||
U16 IoFlags; /* 0x24 */
|
||||
U16 EEDPFlags; /* 0x26 */
|
||||
U32 EEDPBlockSize; /* 0x28 */
|
||||
U32 SecondaryReferenceTag; /* 0x2C */
|
||||
U16 SecondaryApplicationTag; /* 0x30 */
|
||||
U16 ApplicationTagTranslationMask; /* 0x32 */
|
||||
U8 LUN[8]; /* 0x34 */
|
||||
U32 Control; /* 0x3C */
|
||||
MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */
|
||||
MPI2_SGE_IO_UNION SGL; /* 0x60 */
|
||||
} MPI2_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST,
|
||||
Mpi2SCSIIORequest_t, MPI2_POINTER pMpi2SCSIIORequest_t;
|
||||
|
||||
/* SCSI IO MsgFlags bits */
|
||||
|
||||
/* MsgFlags for SenseBufferAddressSpace */
|
||||
#define MPI2_SCSIIO_MSGFLAGS_MASK_SENSE_ADDR (0x0C)
|
||||
#define MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR (0x00)
|
||||
#define MPI2_SCSIIO_MSGFLAGS_IOCDDR_SENSE_ADDR (0x04)
|
||||
#define MPI2_SCSIIO_MSGFLAGS_IOCPLB_SENSE_ADDR (0x08)
|
||||
#define MPI2_SCSIIO_MSGFLAGS_IOCPLBNTA_SENSE_ADDR (0x0C)
|
||||
|
||||
/* SCSI IO SGLFlags bits */
|
||||
|
||||
/* base values for Data Location Address Space */
|
||||
#define MPI2_SCSIIO_SGLFLAGS_ADDR_MASK (0x0C)
|
||||
#define MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR (0x00)
|
||||
#define MPI2_SCSIIO_SGLFLAGS_IOCDDR_ADDR (0x04)
|
||||
#define MPI2_SCSIIO_SGLFLAGS_IOCPLB_ADDR (0x08)
|
||||
#define MPI2_SCSIIO_SGLFLAGS_IOCPLBNTA_ADDR (0x0C)
|
||||
|
||||
/* base values for Type */
|
||||
#define MPI2_SCSIIO_SGLFLAGS_TYPE_MASK (0x03)
|
||||
#define MPI2_SCSIIO_SGLFLAGS_TYPE_MPI (0x00)
|
||||
#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE32 (0x01)
|
||||
#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE64 (0x02)
|
||||
|
||||
/* shift values for each sub-field */
|
||||
#define MPI2_SCSIIO_SGLFLAGS_SGL3_SHIFT (12)
|
||||
#define MPI2_SCSIIO_SGLFLAGS_SGL2_SHIFT (8)
|
||||
#define MPI2_SCSIIO_SGLFLAGS_SGL1_SHIFT (4)
|
||||
#define MPI2_SCSIIO_SGLFLAGS_SGL0_SHIFT (0)
|
||||
|
||||
/* SCSI IO IoFlags bits */
|
||||
|
||||
/* Large CDB Address Space */
|
||||
#define MPI2_SCSIIO_CDB_ADDR_MASK (0x6000)
|
||||
#define MPI2_SCSIIO_CDB_ADDR_SYSTEM (0x0000)
|
||||
#define MPI2_SCSIIO_CDB_ADDR_IOCDDR (0x2000)
|
||||
#define MPI2_SCSIIO_CDB_ADDR_IOCPLB (0x4000)
|
||||
#define MPI2_SCSIIO_CDB_ADDR_IOCPLBNTA (0x6000)
|
||||
|
||||
#define MPI2_SCSIIO_IOFLAGS_LARGE_CDB (0x1000)
|
||||
#define MPI2_SCSIIO_IOFLAGS_BIDIRECTIONAL (0x0800)
|
||||
#define MPI2_SCSIIO_IOFLAGS_MULTICAST (0x0400)
|
||||
#define MPI2_SCSIIO_IOFLAGS_CMD_DETERMINES_DATA_DIR (0x0200)
|
||||
#define MPI2_SCSIIO_IOFLAGS_CDBLENGTH_MASK (0x01FF)
|
||||
|
||||
/* SCSI IO EEDPFlags bits */
|
||||
|
||||
#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG (0x8000)
|
||||
#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_REFTAG (0x4000)
|
||||
#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG (0x2000)
|
||||
#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_APPTAG (0x1000)
|
||||
|
||||
#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG (0x0400)
|
||||
#define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG (0x0200)
|
||||
#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100)
|
||||
|
||||
#define MPI2_SCSIIO_EEDPFLAGS_PASSTHRU_REFTAG (0x0008)
|
||||
|
||||
#define MPI2_SCSIIO_EEDPFLAGS_MASK_OP (0x0007)
|
||||
#define MPI2_SCSIIO_EEDPFLAGS_NOOP_OP (0x0000)
|
||||
#define MPI2_SCSIIO_EEDPFLAGS_CHECK_OP (0x0001)
|
||||
#define MPI2_SCSIIO_EEDPFLAGS_STRIP_OP (0x0002)
|
||||
#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP (0x0003)
|
||||
#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004)
|
||||
#define MPI2_SCSIIO_EEDPFLAGS_REPLACE_OP (0x0006)
|
||||
#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REGEN_OP (0x0007)
|
||||
|
||||
/* SCSI IO LUN fields: use MPI2_LUN_ from mpi2.h */
|
||||
|
||||
/* SCSI IO Control bits */
|
||||
#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_MASK (0xFC000000)
|
||||
#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT (26)
|
||||
|
||||
#define MPI2_SCSIIO_CONTROL_DATADIRECTION_MASK (0x03000000)
|
||||
#define MPI2_SCSIIO_CONTROL_NODATATRANSFER (0x00000000)
|
||||
#define MPI2_SCSIIO_CONTROL_WRITE (0x01000000)
|
||||
#define MPI2_SCSIIO_CONTROL_READ (0x02000000)
|
||||
#define MPI2_SCSIIO_CONTROL_BIDIRECTIONAL (0x03000000)
|
||||
|
||||
#define MPI2_SCSIIO_CONTROL_TASKPRI_MASK (0x00007800)
|
||||
#define MPI2_SCSIIO_CONTROL_TASKPRI_SHIFT (11)
|
||||
|
||||
#define MPI2_SCSIIO_CONTROL_TASKATTRIBUTE_MASK (0x00000700)
|
||||
#define MPI2_SCSIIO_CONTROL_SIMPLEQ (0x00000000)
|
||||
#define MPI2_SCSIIO_CONTROL_HEADOFQ (0x00000100)
|
||||
#define MPI2_SCSIIO_CONTROL_ORDEREDQ (0x00000200)
|
||||
#define MPI2_SCSIIO_CONTROL_ACAQ (0x00000400)
|
||||
|
||||
#define MPI2_SCSIIO_CONTROL_TLR_MASK (0x000000C0)
|
||||
#define MPI2_SCSIIO_CONTROL_NO_TLR (0x00000000)
|
||||
#define MPI2_SCSIIO_CONTROL_TLR_ON (0x00000040)
|
||||
#define MPI2_SCSIIO_CONTROL_TLR_OFF (0x00000080)
|
||||
|
||||
|
||||
/* SCSI IO Error Reply Message */
|
||||
typedef struct _MPI2_SCSI_IO_REPLY
|
||||
{
|
||||
U16 DevHandle; /* 0x00 */
|
||||
U8 MsgLength; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U16 Reserved1; /* 0x04 */
|
||||
U8 Reserved2; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved3; /* 0x0A */
|
||||
U8 SCSIStatus; /* 0x0C */
|
||||
U8 SCSIState; /* 0x0D */
|
||||
U16 IOCStatus; /* 0x0E */
|
||||
U32 IOCLogInfo; /* 0x10 */
|
||||
U32 TransferCount; /* 0x14 */
|
||||
U32 SenseCount; /* 0x18 */
|
||||
U32 ResponseInfo; /* 0x1C */
|
||||
U16 TaskTag; /* 0x20 */
|
||||
U16 Reserved4; /* 0x22 */
|
||||
U32 BidirectionalTransferCount; /* 0x24 */
|
||||
U32 Reserved5; /* 0x28 */
|
||||
U32 Reserved6; /* 0x2C */
|
||||
} MPI2_SCSI_IO_REPLY, MPI2_POINTER PTR_MPI2_SCSI_IO_REPLY,
|
||||
Mpi2SCSIIOReply_t, MPI2_POINTER pMpi2SCSIIOReply_t;
|
||||
|
||||
/* SCSI IO Reply SCSIStatus values (SAM-4 status codes) */
|
||||
|
||||
#define MPI2_SCSI_STATUS_GOOD (0x00)
|
||||
#define MPI2_SCSI_STATUS_CHECK_CONDITION (0x02)
|
||||
#define MPI2_SCSI_STATUS_CONDITION_MET (0x04)
|
||||
#define MPI2_SCSI_STATUS_BUSY (0x08)
|
||||
#define MPI2_SCSI_STATUS_INTERMEDIATE (0x10)
|
||||
#define MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET (0x14)
|
||||
#define MPI2_SCSI_STATUS_RESERVATION_CONFLICT (0x18)
|
||||
#define MPI2_SCSI_STATUS_COMMAND_TERMINATED (0x22) /* obsolete */
|
||||
#define MPI2_SCSI_STATUS_TASK_SET_FULL (0x28)
|
||||
#define MPI2_SCSI_STATUS_ACA_ACTIVE (0x30)
|
||||
#define MPI2_SCSI_STATUS_TASK_ABORTED (0x40)
|
||||
|
||||
/* SCSI IO Reply SCSIState flags */
|
||||
|
||||
#define MPI2_SCSI_STATE_RESPONSE_INFO_VALID (0x10)
|
||||
#define MPI2_SCSI_STATE_TERMINATED (0x08)
|
||||
#define MPI2_SCSI_STATE_NO_SCSI_STATUS (0x04)
|
||||
#define MPI2_SCSI_STATE_AUTOSENSE_FAILED (0x02)
|
||||
#define MPI2_SCSI_STATE_AUTOSENSE_VALID (0x01)
|
||||
|
||||
#define MPI2_SCSI_TASKTAG_UNKNOWN (0xFFFF)
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* SCSI Task Management messages
|
||||
****************************************************************************/
|
||||
|
||||
/* SCSI Task Management Request Message */
|
||||
typedef struct _MPI2_SCSI_TASK_MANAGE_REQUEST
|
||||
{
|
||||
U16 DevHandle; /* 0x00 */
|
||||
U8 ChainOffset; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U8 Reserved1; /* 0x04 */
|
||||
U8 TaskType; /* 0x05 */
|
||||
U8 Reserved2; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved3; /* 0x0A */
|
||||
U8 LUN[8]; /* 0x0C */
|
||||
U32 Reserved4[7]; /* 0x14 */
|
||||
U16 TaskMID; /* 0x30 */
|
||||
U16 Reserved5; /* 0x32 */
|
||||
} MPI2_SCSI_TASK_MANAGE_REQUEST,
|
||||
MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REQUEST,
|
||||
Mpi2SCSITaskManagementRequest_t,
|
||||
MPI2_POINTER pMpi2SCSITaskManagementRequest_t;
|
||||
|
||||
/* TaskType values */
|
||||
|
||||
#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01)
|
||||
#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x02)
|
||||
#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03)
|
||||
#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05)
|
||||
#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06)
|
||||
#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07)
|
||||
#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08)
|
||||
#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET (0x09)
|
||||
#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION (0x0A)
|
||||
|
||||
/* MsgFlags bits */
|
||||
|
||||
#define MPI2_SCSITASKMGMT_MSGFLAGS_MASK_TARGET_RESET (0x18)
|
||||
#define MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET (0x00)
|
||||
#define MPI2_SCSITASKMGMT_MSGFLAGS_NEXUS_RESET_SRST (0x08)
|
||||
#define MPI2_SCSITASKMGMT_MSGFLAGS_SAS_HARD_LINK_RESET (0x10)
|
||||
|
||||
#define MPI2_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU (0x01)
|
||||
|
||||
|
||||
|
||||
/* SCSI Task Management Reply Message */
|
||||
typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY
|
||||
{
|
||||
U16 DevHandle; /* 0x00 */
|
||||
U8 MsgLength; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U8 ResponseCode; /* 0x04 */
|
||||
U8 TaskType; /* 0x05 */
|
||||
U8 Reserved1; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved2; /* 0x0A */
|
||||
U16 Reserved3; /* 0x0C */
|
||||
U16 IOCStatus; /* 0x0E */
|
||||
U32 IOCLogInfo; /* 0x10 */
|
||||
U32 TerminationCount; /* 0x14 */
|
||||
} MPI2_SCSI_TASK_MANAGE_REPLY,
|
||||
MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REPLY,
|
||||
Mpi2SCSITaskManagementReply_t, MPI2_POINTER pMpi2SCSIManagementReply_t;
|
||||
|
||||
/* ResponseCode values */
|
||||
|
||||
#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE (0x00)
|
||||
#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME (0x02)
|
||||
#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED (0x04)
|
||||
#define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05)
|
||||
#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08)
|
||||
#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09)
|
||||
#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80)
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* SCSI Enclosure Processor messages
|
||||
****************************************************************************/
|
||||
|
||||
/* SCSI Enclosure Processor Request Message */
|
||||
typedef struct _MPI2_SEP_REQUEST
|
||||
{
|
||||
U16 DevHandle; /* 0x00 */
|
||||
U8 ChainOffset; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U8 Action; /* 0x04 */
|
||||
U8 Flags; /* 0x05 */
|
||||
U8 Reserved1; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved2; /* 0x0A */
|
||||
U32 SlotStatus; /* 0x0C */
|
||||
U32 Reserved3; /* 0x10 */
|
||||
U32 Reserved4; /* 0x14 */
|
||||
U32 Reserved5; /* 0x18 */
|
||||
U16 Slot; /* 0x1C */
|
||||
U16 EnclosureHandle; /* 0x1E */
|
||||
} MPI2_SEP_REQUEST, MPI2_POINTER PTR_MPI2_SEP_REQUEST,
|
||||
Mpi2SepRequest_t, MPI2_POINTER pMpi2SepRequest_t;
|
||||
|
||||
/* Action defines */
|
||||
#define MPI2_SEP_REQ_ACTION_WRITE_STATUS (0x00)
|
||||
#define MPI2_SEP_REQ_ACTION_READ_STATUS (0x01)
|
||||
|
||||
/* Flags defines */
|
||||
#define MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS (0x00)
|
||||
#define MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS (0x01)
|
||||
|
||||
/* SlotStatus defines */
|
||||
#define MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE (0x00040000)
|
||||
#define MPI2_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000)
|
||||
#define MPI2_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED (0x00000200)
|
||||
#define MPI2_SEP_REQ_SLOTSTATUS_HOT_SPARE (0x00000100)
|
||||
#define MPI2_SEP_REQ_SLOTSTATUS_UNCONFIGURED (0x00000080)
|
||||
#define MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT (0x00000040)
|
||||
#define MPI2_SEP_REQ_SLOTSTATUS_DEV_REBUILDING (0x00000004)
|
||||
#define MPI2_SEP_REQ_SLOTSTATUS_DEV_FAULTY (0x00000002)
|
||||
#define MPI2_SEP_REQ_SLOTSTATUS_NO_ERROR (0x00000001)
|
||||
|
||||
|
||||
/* SCSI Enclosure Processor Reply Message */
|
||||
typedef struct _MPI2_SEP_REPLY
|
||||
{
|
||||
U16 DevHandle; /* 0x00 */
|
||||
U8 MsgLength; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U8 Action; /* 0x04 */
|
||||
U8 Flags; /* 0x05 */
|
||||
U8 Reserved1; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved2; /* 0x0A */
|
||||
U16 Reserved3; /* 0x0C */
|
||||
U16 IOCStatus; /* 0x0E */
|
||||
U32 IOCLogInfo; /* 0x10 */
|
||||
U32 SlotStatus; /* 0x14 */
|
||||
U32 Reserved4; /* 0x18 */
|
||||
U16 Slot; /* 0x1C */
|
||||
U16 EnclosureHandle; /* 0x1E */
|
||||
} MPI2_SEP_REPLY, MPI2_POINTER PTR_MPI2_SEP_REPLY,
|
||||
Mpi2SepReply_t, MPI2_POINTER pMpi2SepReply_t;
|
||||
|
||||
/* SlotStatus defines */
|
||||
#define MPI2_SEP_REPLY_SLOTSTATUS_REMOVE_READY (0x00040000)
|
||||
#define MPI2_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000)
|
||||
#define MPI2_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED (0x00000200)
|
||||
#define MPI2_SEP_REPLY_SLOTSTATUS_HOT_SPARE (0x00000100)
|
||||
#define MPI2_SEP_REPLY_SLOTSTATUS_UNCONFIGURED (0x00000080)
|
||||
#define MPI2_SEP_REPLY_SLOTSTATUS_PREDICTED_FAULT (0x00000040)
|
||||
#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_REBUILDING (0x00000004)
|
||||
#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_FAULTY (0x00000002)
|
||||
#define MPI2_SEP_REPLY_SLOTSTATUS_NO_ERROR (0x00000001)
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
1295
drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
Normal file
1295
drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
Normal file
File diff suppressed because it is too large
Load Diff
295
drivers/scsi/mpt2sas/mpi/mpi2_raid.h
Normal file
295
drivers/scsi/mpt2sas/mpi/mpi2_raid.h
Normal file
@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2008 LSI Corporation.
|
||||
*
|
||||
*
|
||||
* Name: mpi2_raid.h
|
||||
* Title: MPI Integrated RAID messages and structures
|
||||
* Creation Date: April 26, 2007
|
||||
*
|
||||
* mpi2_raid.h Version: 02.00.03
|
||||
*
|
||||
* Version History
|
||||
* ---------------
|
||||
*
|
||||
* Date Version Description
|
||||
* -------- -------- ------------------------------------------------------
|
||||
* 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
|
||||
* 08-31-07 02.00.01 Modifications to RAID Action request and reply,
|
||||
* including the Actions and ActionData.
|
||||
* 02-29-08 02.00.02 Added MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD.
|
||||
* 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that
|
||||
* the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT
|
||||
* can be sized by the build environment.
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef MPI2_RAID_H
|
||||
#define MPI2_RAID_H
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Integrated RAID Messages
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* RAID Action messages
|
||||
****************************************************************************/
|
||||
|
||||
/* ActionDataWord defines for use with MPI2_RAID_ACTION_DELETE_VOLUME action */
|
||||
#define MPI2_RAID_ACTION_ADATA_KEEP_LBA0 (0x00000000)
|
||||
#define MPI2_RAID_ACTION_ADATA_ZERO_LBA0 (0x00000001)
|
||||
|
||||
/* use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */
|
||||
|
||||
/* ActionDataWord defines for use with MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES action */
|
||||
#define MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD (0x00000001)
|
||||
|
||||
/* ActionDataWord for MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE Action */
|
||||
typedef struct _MPI2_RAID_ACTION_RATE_DATA
|
||||
{
|
||||
U8 RateToChange; /* 0x00 */
|
||||
U8 RateOrMode; /* 0x01 */
|
||||
U16 DataScrubDuration; /* 0x02 */
|
||||
} MPI2_RAID_ACTION_RATE_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_RATE_DATA,
|
||||
Mpi2RaidActionRateData_t, MPI2_POINTER pMpi2RaidActionRateData_t;
|
||||
|
||||
#define MPI2_RAID_ACTION_SET_RATE_RESYNC (0x00)
|
||||
#define MPI2_RAID_ACTION_SET_RATE_DATA_SCRUB (0x01)
|
||||
#define MPI2_RAID_ACTION_SET_RATE_POWERSAVE_MODE (0x02)
|
||||
|
||||
/* ActionDataWord for MPI2_RAID_ACTION_START_RAID_FUNCTION Action */
|
||||
typedef struct _MPI2_RAID_ACTION_START_RAID_FUNCTION
|
||||
{
|
||||
U8 RAIDFunction; /* 0x00 */
|
||||
U8 Flags; /* 0x01 */
|
||||
U16 Reserved1; /* 0x02 */
|
||||
} MPI2_RAID_ACTION_START_RAID_FUNCTION,
|
||||
MPI2_POINTER PTR_MPI2_RAID_ACTION_START_RAID_FUNCTION,
|
||||
Mpi2RaidActionStartRaidFunction_t,
|
||||
MPI2_POINTER pMpi2RaidActionStartRaidFunction_t;
|
||||
|
||||
/* defines for the RAIDFunction field */
|
||||
#define MPI2_RAID_ACTION_START_BACKGROUND_INIT (0x00)
|
||||
#define MPI2_RAID_ACTION_START_ONLINE_CAP_EXPANSION (0x01)
|
||||
#define MPI2_RAID_ACTION_START_CONSISTENCY_CHECK (0x02)
|
||||
|
||||
/* defines for the Flags field */
|
||||
#define MPI2_RAID_ACTION_START_NEW (0x00)
|
||||
#define MPI2_RAID_ACTION_START_RESUME (0x01)
|
||||
|
||||
/* ActionDataWord for MPI2_RAID_ACTION_STOP_RAID_FUNCTION Action */
|
||||
typedef struct _MPI2_RAID_ACTION_STOP_RAID_FUNCTION
|
||||
{
|
||||
U8 RAIDFunction; /* 0x00 */
|
||||
U8 Flags; /* 0x01 */
|
||||
U16 Reserved1; /* 0x02 */
|
||||
} MPI2_RAID_ACTION_STOP_RAID_FUNCTION,
|
||||
MPI2_POINTER PTR_MPI2_RAID_ACTION_STOP_RAID_FUNCTION,
|
||||
Mpi2RaidActionStopRaidFunction_t,
|
||||
MPI2_POINTER pMpi2RaidActionStopRaidFunction_t;
|
||||
|
||||
/* defines for the RAIDFunction field */
|
||||
#define MPI2_RAID_ACTION_STOP_BACKGROUND_INIT (0x00)
|
||||
#define MPI2_RAID_ACTION_STOP_ONLINE_CAP_EXPANSION (0x01)
|
||||
#define MPI2_RAID_ACTION_STOP_CONSISTENCY_CHECK (0x02)
|
||||
|
||||
/* defines for the Flags field */
|
||||
#define MPI2_RAID_ACTION_STOP_ABORT (0x00)
|
||||
#define MPI2_RAID_ACTION_STOP_PAUSE (0x01)
|
||||
|
||||
/* ActionDataWord for MPI2_RAID_ACTION_CREATE_HOT_SPARE Action */
|
||||
typedef struct _MPI2_RAID_ACTION_HOT_SPARE
|
||||
{
|
||||
U8 HotSparePool; /* 0x00 */
|
||||
U8 Reserved1; /* 0x01 */
|
||||
U16 DevHandle; /* 0x02 */
|
||||
} MPI2_RAID_ACTION_HOT_SPARE, MPI2_POINTER PTR_MPI2_RAID_ACTION_HOT_SPARE,
|
||||
Mpi2RaidActionHotSpare_t, MPI2_POINTER pMpi2RaidActionHotSpare_t;
|
||||
|
||||
/* ActionDataWord for MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE Action */
|
||||
typedef struct _MPI2_RAID_ACTION_FW_UPDATE_MODE
|
||||
{
|
||||
U8 Flags; /* 0x00 */
|
||||
U8 DeviceFirmwareUpdateModeTimeout; /* 0x01 */
|
||||
U16 Reserved1; /* 0x02 */
|
||||
} MPI2_RAID_ACTION_FW_UPDATE_MODE,
|
||||
MPI2_POINTER PTR_MPI2_RAID_ACTION_FW_UPDATE_MODE,
|
||||
Mpi2RaidActionFwUpdateMode_t, MPI2_POINTER pMpi2RaidActionFwUpdateMode_t;
|
||||
|
||||
/* ActionDataWord defines for use with MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE action */
|
||||
#define MPI2_RAID_ACTION_ADATA_DISABLE_FW_UPDATE (0x00)
|
||||
#define MPI2_RAID_ACTION_ADATA_ENABLE_FW_UPDATE (0x01)
|
||||
|
||||
typedef union _MPI2_RAID_ACTION_DATA
|
||||
{
|
||||
U32 Word;
|
||||
MPI2_RAID_ACTION_RATE_DATA Rates;
|
||||
MPI2_RAID_ACTION_START_RAID_FUNCTION StartRaidFunction;
|
||||
MPI2_RAID_ACTION_STOP_RAID_FUNCTION StopRaidFunction;
|
||||
MPI2_RAID_ACTION_HOT_SPARE HotSpare;
|
||||
MPI2_RAID_ACTION_FW_UPDATE_MODE FwUpdateMode;
|
||||
} MPI2_RAID_ACTION_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_DATA,
|
||||
Mpi2RaidActionData_t, MPI2_POINTER pMpi2RaidActionData_t;
|
||||
|
||||
|
||||
/* RAID Action Request Message */
|
||||
typedef struct _MPI2_RAID_ACTION_REQUEST
|
||||
{
|
||||
U8 Action; /* 0x00 */
|
||||
U8 Reserved1; /* 0x01 */
|
||||
U8 ChainOffset; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U16 VolDevHandle; /* 0x04 */
|
||||
U8 PhysDiskNum; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved2; /* 0x0A */
|
||||
U32 Reserved3; /* 0x0C */
|
||||
MPI2_RAID_ACTION_DATA ActionDataWord; /* 0x10 */
|
||||
MPI2_SGE_SIMPLE_UNION ActionDataSGE; /* 0x14 */
|
||||
} MPI2_RAID_ACTION_REQUEST, MPI2_POINTER PTR_MPI2_RAID_ACTION_REQUEST,
|
||||
Mpi2RaidActionRequest_t, MPI2_POINTER pMpi2RaidActionRequest_t;
|
||||
|
||||
/* RAID Action request Action values */
|
||||
|
||||
#define MPI2_RAID_ACTION_INDICATOR_STRUCT (0x01)
|
||||
#define MPI2_RAID_ACTION_CREATE_VOLUME (0x02)
|
||||
#define MPI2_RAID_ACTION_DELETE_VOLUME (0x03)
|
||||
#define MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES (0x04)
|
||||
#define MPI2_RAID_ACTION_ENABLE_ALL_VOLUMES (0x05)
|
||||
#define MPI2_RAID_ACTION_PHYSDISK_OFFLINE (0x0A)
|
||||
#define MPI2_RAID_ACTION_PHYSDISK_ONLINE (0x0B)
|
||||
#define MPI2_RAID_ACTION_FAIL_PHYSDISK (0x0F)
|
||||
#define MPI2_RAID_ACTION_ACTIVATE_VOLUME (0x11)
|
||||
#define MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE (0x15)
|
||||
#define MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE (0x17)
|
||||
#define MPI2_RAID_ACTION_SET_VOLUME_NAME (0x18)
|
||||
#define MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE (0x19)
|
||||
#define MPI2_RAID_ACTION_ENABLE_FAILED_VOLUME (0x1C)
|
||||
#define MPI2_RAID_ACTION_CREATE_HOT_SPARE (0x1D)
|
||||
#define MPI2_RAID_ACTION_DELETE_HOT_SPARE (0x1E)
|
||||
#define MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED (0x20)
|
||||
#define MPI2_RAID_ACTION_START_RAID_FUNCTION (0x21)
|
||||
#define MPI2_RAID_ACTION_STOP_RAID_FUNCTION (0x22)
|
||||
|
||||
|
||||
/* RAID Volume Creation Structure */
|
||||
|
||||
/*
|
||||
* The following define can be customized for the targeted product.
|
||||
*/
|
||||
#ifndef MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS
|
||||
#define MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS (1)
|
||||
#endif
|
||||
|
||||
typedef struct _MPI2_RAID_VOLUME_PHYSDISK
|
||||
{
|
||||
U8 RAIDSetNum; /* 0x00 */
|
||||
U8 PhysDiskMap; /* 0x01 */
|
||||
U16 PhysDiskDevHandle; /* 0x02 */
|
||||
} MPI2_RAID_VOLUME_PHYSDISK, MPI2_POINTER PTR_MPI2_RAID_VOLUME_PHYSDISK,
|
||||
Mpi2RaidVolumePhysDisk_t, MPI2_POINTER pMpi2RaidVolumePhysDisk_t;
|
||||
|
||||
/* defines for the PhysDiskMap field */
|
||||
#define MPI2_RAIDACTION_PHYSDISK_PRIMARY (0x01)
|
||||
#define MPI2_RAIDACTION_PHYSDISK_SECONDARY (0x02)
|
||||
|
||||
typedef struct _MPI2_RAID_VOLUME_CREATION_STRUCT
|
||||
{
|
||||
U8 NumPhysDisks; /* 0x00 */
|
||||
U8 VolumeType; /* 0x01 */
|
||||
U16 Reserved1; /* 0x02 */
|
||||
U32 VolumeCreationFlags; /* 0x04 */
|
||||
U32 VolumeSettings; /* 0x08 */
|
||||
U8 Reserved2; /* 0x0C */
|
||||
U8 ResyncRate; /* 0x0D */
|
||||
U16 DataScrubDuration; /* 0x0E */
|
||||
U64 VolumeMaxLBA; /* 0x10 */
|
||||
U32 StripeSize; /* 0x18 */
|
||||
U8 Name[16]; /* 0x1C */
|
||||
MPI2_RAID_VOLUME_PHYSDISK PhysDisk[MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS];/* 0x2C */
|
||||
} MPI2_RAID_VOLUME_CREATION_STRUCT,
|
||||
MPI2_POINTER PTR_MPI2_RAID_VOLUME_CREATION_STRUCT,
|
||||
Mpi2RaidVolumeCreationStruct_t, MPI2_POINTER pMpi2RaidVolumeCreationStruct_t;
|
||||
|
||||
/* use MPI2_RAID_VOL_TYPE_ defines from mpi2_cnfg.h for VolumeType */
|
||||
|
||||
/* defines for the VolumeCreationFlags field */
|
||||
#define MPI2_RAID_VOL_CREATION_USE_DEFAULT_SETTINGS (0x80)
|
||||
#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x04)
|
||||
#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x02)
|
||||
#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x01)
|
||||
|
||||
|
||||
/* RAID Online Capacity Expansion Structure */
|
||||
|
||||
typedef struct _MPI2_RAID_ONLINE_CAPACITY_EXPANSION
|
||||
{
|
||||
U32 Flags; /* 0x00 */
|
||||
U16 DevHandle0; /* 0x04 */
|
||||
U16 Reserved1; /* 0x06 */
|
||||
U16 DevHandle1; /* 0x08 */
|
||||
U16 Reserved2; /* 0x0A */
|
||||
} MPI2_RAID_ONLINE_CAPACITY_EXPANSION,
|
||||
MPI2_POINTER PTR_MPI2_RAID_ONLINE_CAPACITY_EXPANSION,
|
||||
Mpi2RaidOnlineCapacityExpansion_t,
|
||||
MPI2_POINTER pMpi2RaidOnlineCapacityExpansion_t;
|
||||
|
||||
|
||||
/* RAID Volume Indicator Structure */
|
||||
|
||||
typedef struct _MPI2_RAID_VOL_INDICATOR
|
||||
{
|
||||
U64 TotalBlocks; /* 0x00 */
|
||||
U64 BlocksRemaining; /* 0x08 */
|
||||
U32 Flags; /* 0x10 */
|
||||
} MPI2_RAID_VOL_INDICATOR, MPI2_POINTER PTR_MPI2_RAID_VOL_INDICATOR,
|
||||
Mpi2RaidVolIndicator_t, MPI2_POINTER pMpi2RaidVolIndicator_t;
|
||||
|
||||
/* defines for RAID Volume Indicator Flags field */
|
||||
#define MPI2_RAID_VOL_FLAGS_OP_MASK (0x0000000F)
|
||||
#define MPI2_RAID_VOL_FLAGS_OP_BACKGROUND_INIT (0x00000000)
|
||||
#define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001)
|
||||
#define MPI2_RAID_VOL_FLAGS_OP_CONSISTENCY_CHECK (0x00000002)
|
||||
#define MPI2_RAID_VOL_FLAGS_OP_RESYNC (0x00000003)
|
||||
|
||||
|
||||
/* RAID Action Reply ActionData union */
|
||||
typedef union _MPI2_RAID_ACTION_REPLY_DATA
|
||||
{
|
||||
U32 Word[5];
|
||||
MPI2_RAID_VOL_INDICATOR RaidVolumeIndicator;
|
||||
U16 VolDevHandle;
|
||||
U8 VolumeState;
|
||||
U8 PhysDiskNum;
|
||||
} MPI2_RAID_ACTION_REPLY_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY_DATA,
|
||||
Mpi2RaidActionReplyData_t, MPI2_POINTER pMpi2RaidActionReplyData_t;
|
||||
|
||||
/* use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */
|
||||
|
||||
|
||||
/* RAID Action Reply Message */
|
||||
typedef struct _MPI2_RAID_ACTION_REPLY
|
||||
{
|
||||
U8 Action; /* 0x00 */
|
||||
U8 Reserved1; /* 0x01 */
|
||||
U8 MsgLength; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U16 VolDevHandle; /* 0x04 */
|
||||
U8 PhysDiskNum; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved2; /* 0x0A */
|
||||
U16 Reserved3; /* 0x0C */
|
||||
U16 IOCStatus; /* 0x0E */
|
||||
U32 IOCLogInfo; /* 0x10 */
|
||||
MPI2_RAID_ACTION_REPLY_DATA ActionData; /* 0x14 */
|
||||
} MPI2_RAID_ACTION_REPLY, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY,
|
||||
Mpi2RaidActionReply_t, MPI2_POINTER pMpi2RaidActionReply_t;
|
||||
|
||||
|
||||
#endif
|
||||
|
282
drivers/scsi/mpt2sas/mpi/mpi2_sas.h
Normal file
282
drivers/scsi/mpt2sas/mpi/mpi2_sas.h
Normal file
@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2007 LSI Corporation.
|
||||
*
|
||||
*
|
||||
* Name: mpi2_sas.h
|
||||
* Title: MPI Serial Attached SCSI structures and definitions
|
||||
* Creation Date: February 9, 2007
|
||||
*
|
||||
* mpi2.h Version: 02.00.02
|
||||
*
|
||||
* Version History
|
||||
* ---------------
|
||||
*
|
||||
* Date Version Description
|
||||
* -------- -------- ------------------------------------------------------
|
||||
* 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
|
||||
* 06-26-07 02.00.01 Added Clear All Persistent Operation to SAS IO Unit
|
||||
* Control Request.
|
||||
* 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control
|
||||
* Request.
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef MPI2_SAS_H
|
||||
#define MPI2_SAS_H
|
||||
|
||||
/*
|
||||
* Values for SASStatus.
|
||||
*/
|
||||
#define MPI2_SASSTATUS_SUCCESS (0x00)
|
||||
#define MPI2_SASSTATUS_UNKNOWN_ERROR (0x01)
|
||||
#define MPI2_SASSTATUS_INVALID_FRAME (0x02)
|
||||
#define MPI2_SASSTATUS_UTC_BAD_DEST (0x03)
|
||||
#define MPI2_SASSTATUS_UTC_BREAK_RECEIVED (0x04)
|
||||
#define MPI2_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED (0x05)
|
||||
#define MPI2_SASSTATUS_UTC_PORT_LAYER_REQUEST (0x06)
|
||||
#define MPI2_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED (0x07)
|
||||
#define MPI2_SASSTATUS_UTC_STP_RESOURCES_BUSY (0x08)
|
||||
#define MPI2_SASSTATUS_UTC_WRONG_DESTINATION (0x09)
|
||||
#define MPI2_SASSTATUS_SHORT_INFORMATION_UNIT (0x0A)
|
||||
#define MPI2_SASSTATUS_LONG_INFORMATION_UNIT (0x0B)
|
||||
#define MPI2_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA (0x0C)
|
||||
#define MPI2_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR (0x0D)
|
||||
#define MPI2_SASSTATUS_XFER_RDY_NOT_EXPECTED (0x0E)
|
||||
#define MPI2_SASSTATUS_DATA_INCORRECT_DATA_LENGTH (0x0F)
|
||||
#define MPI2_SASSTATUS_DATA_TOO_MUCH_READ_DATA (0x10)
|
||||
#define MPI2_SASSTATUS_DATA_OFFSET_ERROR (0x11)
|
||||
#define MPI2_SASSTATUS_SDSF_NAK_RECEIVED (0x12)
|
||||
#define MPI2_SASSTATUS_SDSF_CONNECTION_FAILED (0x13)
|
||||
#define MPI2_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT (0x14)
|
||||
|
||||
|
||||
/*
|
||||
* Values for the SAS DeviceInfo field used in SAS Device Status Change Event
|
||||
* data and SAS Configuration pages.
|
||||
*/
|
||||
#define MPI2_SAS_DEVICE_INFO_SEP (0x00004000)
|
||||
#define MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE (0x00002000)
|
||||
#define MPI2_SAS_DEVICE_INFO_LSI_DEVICE (0x00001000)
|
||||
#define MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH (0x00000800)
|
||||
#define MPI2_SAS_DEVICE_INFO_SSP_TARGET (0x00000400)
|
||||
#define MPI2_SAS_DEVICE_INFO_STP_TARGET (0x00000200)
|
||||
#define MPI2_SAS_DEVICE_INFO_SMP_TARGET (0x00000100)
|
||||
#define MPI2_SAS_DEVICE_INFO_SATA_DEVICE (0x00000080)
|
||||
#define MPI2_SAS_DEVICE_INFO_SSP_INITIATOR (0x00000040)
|
||||
#define MPI2_SAS_DEVICE_INFO_STP_INITIATOR (0x00000020)
|
||||
#define MPI2_SAS_DEVICE_INFO_SMP_INITIATOR (0x00000010)
|
||||
#define MPI2_SAS_DEVICE_INFO_SATA_HOST (0x00000008)
|
||||
|
||||
#define MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE (0x00000007)
|
||||
#define MPI2_SAS_DEVICE_INFO_NO_DEVICE (0x00000000)
|
||||
#define MPI2_SAS_DEVICE_INFO_END_DEVICE (0x00000001)
|
||||
#define MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER (0x00000002)
|
||||
#define MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER (0x00000003)
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* SAS Messages
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* SMP Passthrough messages
|
||||
****************************************************************************/
|
||||
|
||||
/* SMP Passthrough Request Message */
|
||||
typedef struct _MPI2_SMP_PASSTHROUGH_REQUEST
|
||||
{
|
||||
U8 PassthroughFlags; /* 0x00 */
|
||||
U8 PhysicalPort; /* 0x01 */
|
||||
U8 ChainOffset; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U16 RequestDataLength; /* 0x04 */
|
||||
U8 SGLFlags; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved1; /* 0x0A */
|
||||
U32 Reserved2; /* 0x0C */
|
||||
U64 SASAddress; /* 0x10 */
|
||||
U32 Reserved3; /* 0x18 */
|
||||
U32 Reserved4; /* 0x1C */
|
||||
MPI2_SIMPLE_SGE_UNION SGL; /* 0x20 */
|
||||
} MPI2_SMP_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REQUEST,
|
||||
Mpi2SmpPassthroughRequest_t, MPI2_POINTER pMpi2SmpPassthroughRequest_t;
|
||||
|
||||
/* values for PassthroughFlags field */
|
||||
#define MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE (0x80)
|
||||
|
||||
/* values for SGLFlags field are in the SGL section of mpi2.h */
|
||||
|
||||
|
||||
/* SMP Passthrough Reply Message */
|
||||
typedef struct _MPI2_SMP_PASSTHROUGH_REPLY
|
||||
{
|
||||
U8 PassthroughFlags; /* 0x00 */
|
||||
U8 PhysicalPort; /* 0x01 */
|
||||
U8 MsgLength; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U16 ResponseDataLength; /* 0x04 */
|
||||
U8 SGLFlags; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved1; /* 0x0A */
|
||||
U8 Reserved2; /* 0x0C */
|
||||
U8 SASStatus; /* 0x0D */
|
||||
U16 IOCStatus; /* 0x0E */
|
||||
U32 IOCLogInfo; /* 0x10 */
|
||||
U32 Reserved3; /* 0x14 */
|
||||
U8 ResponseData[4]; /* 0x18 */
|
||||
} MPI2_SMP_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REPLY,
|
||||
Mpi2SmpPassthroughReply_t, MPI2_POINTER pMpi2SmpPassthroughReply_t;
|
||||
|
||||
/* values for PassthroughFlags field */
|
||||
#define MPI2_SMP_PT_REPLY_PT_FLAGS_IMMEDIATE (0x80)
|
||||
|
||||
/* values for SASStatus field are at the top of this file */
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* SATA Passthrough messages
|
||||
****************************************************************************/
|
||||
|
||||
/* SATA Passthrough Request Message */
|
||||
typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST
|
||||
{
|
||||
U16 DevHandle; /* 0x00 */
|
||||
U8 ChainOffset; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U16 PassthroughFlags; /* 0x04 */
|
||||
U8 SGLFlags; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved1; /* 0x0A */
|
||||
U32 Reserved2; /* 0x0C */
|
||||
U32 Reserved3; /* 0x10 */
|
||||
U32 Reserved4; /* 0x14 */
|
||||
U32 DataLength; /* 0x18 */
|
||||
U8 CommandFIS[20]; /* 0x1C */
|
||||
MPI2_SIMPLE_SGE_UNION SGL; /* 0x20 */
|
||||
} MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST,
|
||||
Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t;
|
||||
|
||||
/* values for PassthroughFlags field */
|
||||
#define MPI2_SATA_PT_REQ_PT_FLAGS_EXECUTE_DIAG (0x0100)
|
||||
#define MPI2_SATA_PT_REQ_PT_FLAGS_DMA (0x0020)
|
||||
#define MPI2_SATA_PT_REQ_PT_FLAGS_PIO (0x0010)
|
||||
#define MPI2_SATA_PT_REQ_PT_FLAGS_UNSPECIFIED_VU (0x0004)
|
||||
#define MPI2_SATA_PT_REQ_PT_FLAGS_WRITE (0x0002)
|
||||
#define MPI2_SATA_PT_REQ_PT_FLAGS_READ (0x0001)
|
||||
|
||||
/* values for SGLFlags field are in the SGL section of mpi2.h */
|
||||
|
||||
|
||||
/* SATA Passthrough Reply Message */
|
||||
typedef struct _MPI2_SATA_PASSTHROUGH_REPLY
|
||||
{
|
||||
U16 DevHandle; /* 0x00 */
|
||||
U8 MsgLength; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U16 PassthroughFlags; /* 0x04 */
|
||||
U8 SGLFlags; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved1; /* 0x0A */
|
||||
U8 Reserved2; /* 0x0C */
|
||||
U8 SASStatus; /* 0x0D */
|
||||
U16 IOCStatus; /* 0x0E */
|
||||
U32 IOCLogInfo; /* 0x10 */
|
||||
U8 StatusFIS[20]; /* 0x14 */
|
||||
U32 StatusControlRegisters; /* 0x28 */
|
||||
U32 TransferCount; /* 0x2C */
|
||||
} MPI2_SATA_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REPLY,
|
||||
Mpi2SataPassthroughReply_t, MPI2_POINTER pMpi2SataPassthroughReply_t;
|
||||
|
||||
/* values for SASStatus field are at the top of this file */
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* SAS IO Unit Control messages
|
||||
****************************************************************************/
|
||||
|
||||
/* SAS IO Unit Control Request Message */
|
||||
typedef struct _MPI2_SAS_IOUNIT_CONTROL_REQUEST
|
||||
{
|
||||
U8 Operation; /* 0x00 */
|
||||
U8 Reserved1; /* 0x01 */
|
||||
U8 ChainOffset; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U16 DevHandle; /* 0x04 */
|
||||
U8 IOCParameter; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved3; /* 0x0A */
|
||||
U16 Reserved4; /* 0x0C */
|
||||
U8 PhyNum; /* 0x0E */
|
||||
U8 PrimFlags; /* 0x0F */
|
||||
U32 Primitive; /* 0x10 */
|
||||
U8 LookupMethod; /* 0x14 */
|
||||
U8 Reserved5; /* 0x15 */
|
||||
U16 SlotNumber; /* 0x16 */
|
||||
U64 LookupAddress; /* 0x18 */
|
||||
U32 IOCParameterValue; /* 0x20 */
|
||||
U32 Reserved7; /* 0x24 */
|
||||
U32 Reserved8; /* 0x28 */
|
||||
} MPI2_SAS_IOUNIT_CONTROL_REQUEST,
|
||||
MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REQUEST,
|
||||
Mpi2SasIoUnitControlRequest_t, MPI2_POINTER pMpi2SasIoUnitControlRequest_t;
|
||||
|
||||
/* values for the Operation field */
|
||||
#define MPI2_SAS_OP_CLEAR_ALL_PERSISTENT (0x02)
|
||||
#define MPI2_SAS_OP_PHY_LINK_RESET (0x06)
|
||||
#define MPI2_SAS_OP_PHY_HARD_RESET (0x07)
|
||||
#define MPI2_SAS_OP_PHY_CLEAR_ERROR_LOG (0x08)
|
||||
#define MPI2_SAS_OP_SEND_PRIMITIVE (0x0A)
|
||||
#define MPI2_SAS_OP_FORCE_FULL_DISCOVERY (0x0B)
|
||||
#define MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C)
|
||||
#define MPI2_SAS_OP_REMOVE_DEVICE (0x0D)
|
||||
#define MPI2_SAS_OP_LOOKUP_MAPPING (0x0E)
|
||||
#define MPI2_SAS_OP_SET_IOC_PARAMETER (0x0F)
|
||||
#define MPI2_SAS_OP_PRODUCT_SPECIFIC_MIN (0x80)
|
||||
|
||||
/* values for the PrimFlags field */
|
||||
#define MPI2_SAS_PRIMFLAGS_SINGLE (0x08)
|
||||
#define MPI2_SAS_PRIMFLAGS_TRIPLE (0x02)
|
||||
#define MPI2_SAS_PRIMFLAGS_REDUNDANT (0x01)
|
||||
|
||||
/* values for the LookupMethod field */
|
||||
#define MPI2_SAS_LOOKUP_METHOD_SAS_ADDRESS (0x01)
|
||||
#define MPI2_SAS_LOOKUP_METHOD_SAS_ENCLOSURE_SLOT (0x02)
|
||||
#define MPI2_SAS_LOOKUP_METHOD_SAS_DEVICE_NAME (0x03)
|
||||
|
||||
|
||||
/* SAS IO Unit Control Reply Message */
|
||||
typedef struct _MPI2_SAS_IOUNIT_CONTROL_REPLY
|
||||
{
|
||||
U8 Operation; /* 0x00 */
|
||||
U8 Reserved1; /* 0x01 */
|
||||
U8 MsgLength; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U16 DevHandle; /* 0x04 */
|
||||
U8 IOCParameter; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved3; /* 0x0A */
|
||||
U16 Reserved4; /* 0x0C */
|
||||
U16 IOCStatus; /* 0x0E */
|
||||
U32 IOCLogInfo; /* 0x10 */
|
||||
} MPI2_SAS_IOUNIT_CONTROL_REPLY,
|
||||
MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REPLY,
|
||||
Mpi2SasIoUnitControlReply_t, MPI2_POINTER pMpi2SasIoUnitControlReply_t;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
249
drivers/scsi/mpt2sas/mpi/mpi2_tool.h
Normal file
249
drivers/scsi/mpt2sas/mpi/mpi2_tool.h
Normal file
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2008 LSI Corporation.
|
||||
*
|
||||
*
|
||||
* Name: mpi2_tool.h
|
||||
* Title: MPI diagnostic tool structures and definitions
|
||||
* Creation Date: March 26, 2007
|
||||
*
|
||||
* mpi2_tool.h Version: 02.00.02
|
||||
*
|
||||
* Version History
|
||||
* ---------------
|
||||
*
|
||||
* Date Version Description
|
||||
* -------- -------- ------------------------------------------------------
|
||||
* 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
|
||||
* 12-18-07 02.00.01 Added Diagnostic Buffer Post and Diagnostic Release
|
||||
* structures and defines.
|
||||
* 02-29-08 02.00.02 Modified various names to make them 32-character unique.
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef MPI2_TOOL_H
|
||||
#define MPI2_TOOL_H
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Toolbox Messages
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/* defines for the Tools */
|
||||
#define MPI2_TOOLBOX_CLEAN_TOOL (0x00)
|
||||
#define MPI2_TOOLBOX_MEMORY_MOVE_TOOL (0x01)
|
||||
#define MPI2_TOOLBOX_BEACON_TOOL (0x05)
|
||||
|
||||
/****************************************************************************
|
||||
* Toolbox reply
|
||||
****************************************************************************/
|
||||
|
||||
typedef struct _MPI2_TOOLBOX_REPLY
|
||||
{
|
||||
U8 Tool; /* 0x00 */
|
||||
U8 Reserved1; /* 0x01 */
|
||||
U8 MsgLength; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U16 Reserved2; /* 0x04 */
|
||||
U8 Reserved3; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved4; /* 0x0A */
|
||||
U16 Reserved5; /* 0x0C */
|
||||
U16 IOCStatus; /* 0x0E */
|
||||
U32 IOCLogInfo; /* 0x10 */
|
||||
} MPI2_TOOLBOX_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_REPLY,
|
||||
Mpi2ToolboxReply_t, MPI2_POINTER pMpi2ToolboxReply_t;
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Toolbox Clean Tool request
|
||||
****************************************************************************/
|
||||
|
||||
typedef struct _MPI2_TOOLBOX_CLEAN_REQUEST
|
||||
{
|
||||
U8 Tool; /* 0x00 */
|
||||
U8 Reserved1; /* 0x01 */
|
||||
U8 ChainOffset; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U16 Reserved2; /* 0x04 */
|
||||
U8 Reserved3; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved4; /* 0x0A */
|
||||
U32 Flags; /* 0x0C */
|
||||
} MPI2_TOOLBOX_CLEAN_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_CLEAN_REQUEST,
|
||||
Mpi2ToolboxCleanRequest_t, MPI2_POINTER pMpi2ToolboxCleanRequest_t;
|
||||
|
||||
/* values for the Flags field */
|
||||
#define MPI2_TOOLBOX_CLEAN_BOOT_SERVICES (0x80000000)
|
||||
#define MPI2_TOOLBOX_CLEAN_PERSIST_MANUFACT_PAGES (0x40000000)
|
||||
#define MPI2_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES (0x20000000)
|
||||
#define MPI2_TOOLBOX_CLEAN_FW_CURRENT (0x10000000)
|
||||
#define MPI2_TOOLBOX_CLEAN_FW_BACKUP (0x08000000)
|
||||
#define MPI2_TOOLBOX_CLEAN_MEGARAID (0x02000000)
|
||||
#define MPI2_TOOLBOX_CLEAN_INITIALIZATION (0x01000000)
|
||||
#define MPI2_TOOLBOX_CLEAN_FLASH (0x00000004)
|
||||
#define MPI2_TOOLBOX_CLEAN_SEEPROM (0x00000002)
|
||||
#define MPI2_TOOLBOX_CLEAN_NVSRAM (0x00000001)
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Toolbox Memory Move request
|
||||
****************************************************************************/
|
||||
|
||||
typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST
|
||||
{
|
||||
U8 Tool; /* 0x00 */
|
||||
U8 Reserved1; /* 0x01 */
|
||||
U8 ChainOffset; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U16 Reserved2; /* 0x04 */
|
||||
U8 Reserved3; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved4; /* 0x0A */
|
||||
MPI2_SGE_SIMPLE_UNION SGL; /* 0x0C */
|
||||
} MPI2_TOOLBOX_MEM_MOVE_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_MEM_MOVE_REQUEST,
|
||||
Mpi2ToolboxMemMoveRequest_t, MPI2_POINTER pMpi2ToolboxMemMoveRequest_t;
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Toolbox Beacon Tool request
|
||||
****************************************************************************/
|
||||
|
||||
typedef struct _MPI2_TOOLBOX_BEACON_REQUEST
|
||||
{
|
||||
U8 Tool; /* 0x00 */
|
||||
U8 Reserved1; /* 0x01 */
|
||||
U8 ChainOffset; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U16 Reserved2; /* 0x04 */
|
||||
U8 Reserved3; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved4; /* 0x0A */
|
||||
U8 Reserved5; /* 0x0C */
|
||||
U8 PhysicalPort; /* 0x0D */
|
||||
U8 Reserved6; /* 0x0E */
|
||||
U8 Flags; /* 0x0F */
|
||||
} MPI2_TOOLBOX_BEACON_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_BEACON_REQUEST,
|
||||
Mpi2ToolboxBeaconRequest_t, MPI2_POINTER pMpi2ToolboxBeaconRequest_t;
|
||||
|
||||
/* values for the Flags field */
|
||||
#define MPI2_TOOLBOX_FLAGS_BEACONMODE_OFF (0x00)
|
||||
#define MPI2_TOOLBOX_FLAGS_BEACONMODE_ON (0x01)
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Diagnostic Buffer Messages
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Diagnostic Buffer Post request
|
||||
****************************************************************************/
|
||||
|
||||
typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST
|
||||
{
|
||||
U8 Reserved1; /* 0x00 */
|
||||
U8 BufferType; /* 0x01 */
|
||||
U8 ChainOffset; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U16 Reserved2; /* 0x04 */
|
||||
U8 Reserved3; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved4; /* 0x0A */
|
||||
U64 BufferAddress; /* 0x0C */
|
||||
U32 BufferLength; /* 0x14 */
|
||||
U32 Reserved5; /* 0x18 */
|
||||
U32 Reserved6; /* 0x1C */
|
||||
U32 Flags; /* 0x20 */
|
||||
U32 ProductSpecific[23]; /* 0x24 */
|
||||
} MPI2_DIAG_BUFFER_POST_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REQUEST,
|
||||
Mpi2DiagBufferPostRequest_t, MPI2_POINTER pMpi2DiagBufferPostRequest_t;
|
||||
|
||||
/* values for the BufferType field */
|
||||
#define MPI2_DIAG_BUF_TYPE_TRACE (0x00)
|
||||
#define MPI2_DIAG_BUF_TYPE_SNAPSHOT (0x01)
|
||||
/* count of the number of buffer types */
|
||||
#define MPI2_DIAG_BUF_TYPE_COUNT (0x02)
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Diagnostic Buffer Post reply
|
||||
****************************************************************************/
|
||||
|
||||
typedef struct _MPI2_DIAG_BUFFER_POST_REPLY
|
||||
{
|
||||
U8 Reserved1; /* 0x00 */
|
||||
U8 BufferType; /* 0x01 */
|
||||
U8 MsgLength; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U16 Reserved2; /* 0x04 */
|
||||
U8 Reserved3; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved4; /* 0x0A */
|
||||
U16 Reserved5; /* 0x0C */
|
||||
U16 IOCStatus; /* 0x0E */
|
||||
U32 IOCLogInfo; /* 0x10 */
|
||||
U32 TransferLength; /* 0x14 */
|
||||
} MPI2_DIAG_BUFFER_POST_REPLY, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REPLY,
|
||||
Mpi2DiagBufferPostReply_t, MPI2_POINTER pMpi2DiagBufferPostReply_t;
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Diagnostic Release request
|
||||
****************************************************************************/
|
||||
|
||||
typedef struct _MPI2_DIAG_RELEASE_REQUEST
|
||||
{
|
||||
U8 Reserved1; /* 0x00 */
|
||||
U8 BufferType; /* 0x01 */
|
||||
U8 ChainOffset; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U16 Reserved2; /* 0x04 */
|
||||
U8 Reserved3; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved4; /* 0x0A */
|
||||
} MPI2_DIAG_RELEASE_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REQUEST,
|
||||
Mpi2DiagReleaseRequest_t, MPI2_POINTER pMpi2DiagReleaseRequest_t;
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Diagnostic Buffer Post reply
|
||||
****************************************************************************/
|
||||
|
||||
typedef struct _MPI2_DIAG_RELEASE_REPLY
|
||||
{
|
||||
U8 Reserved1; /* 0x00 */
|
||||
U8 BufferType; /* 0x01 */
|
||||
U8 MsgLength; /* 0x02 */
|
||||
U8 Function; /* 0x03 */
|
||||
U16 Reserved2; /* 0x04 */
|
||||
U8 Reserved3; /* 0x06 */
|
||||
U8 MsgFlags; /* 0x07 */
|
||||
U8 VP_ID; /* 0x08 */
|
||||
U8 VF_ID; /* 0x09 */
|
||||
U16 Reserved4; /* 0x0A */
|
||||
U16 Reserved5; /* 0x0C */
|
||||
U16 IOCStatus; /* 0x0E */
|
||||
U32 IOCLogInfo; /* 0x10 */
|
||||
} MPI2_DIAG_RELEASE_REPLY, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REPLY,
|
||||
Mpi2DiagReleaseReply_t, MPI2_POINTER pMpi2DiagReleaseReply_t;
|
||||
|
||||
|
||||
#endif
|
||||
|
61
drivers/scsi/mpt2sas/mpi/mpi2_type.h
Normal file
61
drivers/scsi/mpt2sas/mpi/mpi2_type.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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
|
||||
|
3435
drivers/scsi/mpt2sas/mpt2sas_base.c
Normal file
3435
drivers/scsi/mpt2sas/mpt2sas_base.c
Normal file
File diff suppressed because it is too large
Load Diff
779
drivers/scsi/mpt2sas/mpt2sas_base.h
Normal file
779
drivers/scsi/mpt2sas/mpt2sas_base.h
Normal file
@ -0,0 +1,779 @@
|
||||
/*
|
||||
* This is the Fusion MPT base driver providing common API layer interface
|
||||
* for access to MPT (Message Passing Technology) firmware.
|
||||
*
|
||||
* This code is based on drivers/scsi/mpt2sas/mpt2_base.h
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MPT2SAS_BASE_H_INCLUDED
|
||||
#define MPT2SAS_BASE_H_INCLUDED
|
||||
|
||||
#include "mpi/mpi2_type.h"
|
||||
#include "mpi/mpi2.h"
|
||||
#include "mpi/mpi2_ioc.h"
|
||||
#include "mpi/mpi2_cnfg.h"
|
||||
#include "mpi/mpi2_init.h"
|
||||
#include "mpi/mpi2_raid.h"
|
||||
#include "mpi/mpi2_tool.h"
|
||||
#include "mpi/mpi2_sas.h"
|
||||
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <scsi/scsi_tcq.h>
|
||||
#include <scsi/scsi_transport_sas.h>
|
||||
#include <scsi/scsi_dbg.h>
|
||||
|
||||
#include "mpt2sas_debug.h"
|
||||
|
||||
/* driver versioning info */
|
||||
#define MPT2SAS_DRIVER_NAME "mpt2sas"
|
||||
#define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
|
||||
#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
|
||||
#define MPT2SAS_DRIVER_VERSION "00.100.11.16"
|
||||
#define MPT2SAS_MAJOR_VERSION 00
|
||||
#define MPT2SAS_MINOR_VERSION 100
|
||||
#define MPT2SAS_BUILD_VERSION 11
|
||||
#define MPT2SAS_RELEASE_VERSION 16
|
||||
|
||||
/*
|
||||
* Set MPT2SAS_SG_DEPTH value based on user input.
|
||||
*/
|
||||
#ifdef CONFIG_SCSI_MPT2SAS_MAX_SGE
|
||||
#if CONFIG_SCSI_MPT2SAS_MAX_SGE < 16
|
||||
#define MPT2SAS_SG_DEPTH 16
|
||||
#elif CONFIG_SCSI_MPT2SAS_MAX_SGE > 128
|
||||
#define MPT2SAS_SG_DEPTH 128
|
||||
#else
|
||||
#define MPT2SAS_SG_DEPTH CONFIG_SCSI_MPT2SAS_MAX_SGE
|
||||
#endif
|
||||
#else
|
||||
#define MPT2SAS_SG_DEPTH 128 /* MAX_HW_SEGMENTS */
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Generic Defines
|
||||
*/
|
||||
#define MPT2SAS_SATA_QUEUE_DEPTH 32
|
||||
#define MPT2SAS_SAS_QUEUE_DEPTH 254
|
||||
#define MPT2SAS_RAID_QUEUE_DEPTH 128
|
||||
|
||||
#define MPT_NAME_LENGTH 32 /* generic length of strings */
|
||||
#define MPT_STRING_LENGTH 64
|
||||
|
||||
#define MPT_MAX_CALLBACKS 16
|
||||
|
||||
#define CAN_SLEEP 1
|
||||
#define NO_SLEEP 0
|
||||
|
||||
#define INTERNAL_CMDS_COUNT 10 /* reserved cmds */
|
||||
|
||||
#define MPI2_HIM_MASK 0xFFFFFFFF /* mask every bit*/
|
||||
|
||||
#define MPT2SAS_INVALID_DEVICE_HANDLE 0xFFFF
|
||||
|
||||
|
||||
/*
|
||||
* reset phases
|
||||
*/
|
||||
#define MPT2_IOC_PRE_RESET 1 /* prior to host reset */
|
||||
#define MPT2_IOC_AFTER_RESET 2 /* just after host reset */
|
||||
#define MPT2_IOC_DONE_RESET 3 /* links re-initialized */
|
||||
|
||||
/*
|
||||
* logging format
|
||||
*/
|
||||
#define MPT2SAS_FMT "%s: "
|
||||
#define MPT2SAS_DEBUG_FMT KERN_DEBUG MPT2SAS_FMT
|
||||
#define MPT2SAS_INFO_FMT KERN_INFO MPT2SAS_FMT
|
||||
#define MPT2SAS_NOTE_FMT KERN_NOTICE MPT2SAS_FMT
|
||||
#define MPT2SAS_WARN_FMT KERN_WARNING MPT2SAS_FMT
|
||||
#define MPT2SAS_ERR_FMT KERN_ERR MPT2SAS_FMT
|
||||
|
||||
/*
|
||||
* per target private data
|
||||
*/
|
||||
#define MPT_TARGET_FLAGS_RAID_COMPONENT 0x01
|
||||
#define MPT_TARGET_FLAGS_VOLUME 0x02
|
||||
#define MPT_TARGET_FLAGS_DELETED 0x04
|
||||
|
||||
/**
|
||||
* struct MPT2SAS_TARGET - starget private hostdata
|
||||
* @starget: starget object
|
||||
* @sas_address: target sas address
|
||||
* @handle: device handle
|
||||
* @num_luns: number luns
|
||||
* @flags: MPT_TARGET_FLAGS_XXX flags
|
||||
* @deleted: target flaged for deletion
|
||||
* @tm_busy: target is busy with TM request.
|
||||
*/
|
||||
struct MPT2SAS_TARGET {
|
||||
struct scsi_target *starget;
|
||||
u64 sas_address;
|
||||
u16 handle;
|
||||
int num_luns;
|
||||
u32 flags;
|
||||
u8 deleted;
|
||||
u8 tm_busy;
|
||||
};
|
||||
|
||||
/*
|
||||
* per device private data
|
||||
*/
|
||||
#define MPT_DEVICE_FLAGS_INIT 0x01
|
||||
#define MPT_DEVICE_TLR_ON 0x02
|
||||
|
||||
/**
|
||||
* struct MPT2SAS_DEVICE - sdev private hostdata
|
||||
* @sas_target: starget private hostdata
|
||||
* @lun: lun number
|
||||
* @flags: MPT_DEVICE_XXX flags
|
||||
* @configured_lun: lun is configured
|
||||
* @block: device is in SDEV_BLOCK state
|
||||
* @tlr_snoop_check: flag used in determining whether to disable TLR
|
||||
*/
|
||||
struct MPT2SAS_DEVICE {
|
||||
struct MPT2SAS_TARGET *sas_target;
|
||||
unsigned int lun;
|
||||
u32 flags;
|
||||
u8 configured_lun;
|
||||
u8 block;
|
||||
u8 tlr_snoop_check;
|
||||
};
|
||||
|
||||
#define MPT2_CMD_NOT_USED 0x8000 /* free */
|
||||
#define MPT2_CMD_COMPLETE 0x0001 /* completed */
|
||||
#define MPT2_CMD_PENDING 0x0002 /* pending */
|
||||
#define MPT2_CMD_REPLY_VALID 0x0004 /* reply is valid */
|
||||
#define MPT2_CMD_RESET 0x0008 /* host reset dropped the command */
|
||||
|
||||
/**
|
||||
* struct _internal_cmd - internal commands struct
|
||||
* @mutex: mutex
|
||||
* @done: completion
|
||||
* @reply: reply message pointer
|
||||
* @status: MPT2_CMD_XXX status
|
||||
* @smid: system message id
|
||||
*/
|
||||
struct _internal_cmd {
|
||||
struct mutex mutex;
|
||||
struct completion done;
|
||||
void *reply;
|
||||
u16 status;
|
||||
u16 smid;
|
||||
};
|
||||
|
||||
/*
|
||||
* SAS Topology Structures
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct _sas_device - attached device information
|
||||
* @list: sas device list
|
||||
* @starget: starget object
|
||||
* @sas_address: device sas address
|
||||
* @device_name: retrieved from the SAS IDENTIFY frame.
|
||||
* @handle: device handle
|
||||
* @parent_handle: handle to parent device
|
||||
* @enclosure_handle: enclosure handle
|
||||
* @enclosure_logical_id: enclosure logical identifier
|
||||
* @volume_handle: volume handle (valid when hidden raid member)
|
||||
* @volume_wwid: volume unique identifier
|
||||
* @device_info: bitfield provides detailed info about the device
|
||||
* @id: target id
|
||||
* @channel: target channel
|
||||
* @slot: number number
|
||||
* @hidden_raid_component: set to 1 when this is a raid member
|
||||
* @responding: used in _scsih_sas_device_mark_responding
|
||||
*/
|
||||
struct _sas_device {
|
||||
struct list_head list;
|
||||
struct scsi_target *starget;
|
||||
u64 sas_address;
|
||||
u64 device_name;
|
||||
u16 handle;
|
||||
u16 parent_handle;
|
||||
u16 enclosure_handle;
|
||||
u64 enclosure_logical_id;
|
||||
u16 volume_handle;
|
||||
u64 volume_wwid;
|
||||
u32 device_info;
|
||||
int id;
|
||||
int channel;
|
||||
u16 slot;
|
||||
u8 hidden_raid_component;
|
||||
u8 responding;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct _raid_device - raid volume link list
|
||||
* @list: sas device list
|
||||
* @starget: starget object
|
||||
* @sdev: scsi device struct (volumes are single lun)
|
||||
* @wwid: unique identifier for the volume
|
||||
* @handle: device handle
|
||||
* @id: target id
|
||||
* @channel: target channel
|
||||
* @volume_type: the raid level
|
||||
* @device_info: bitfield provides detailed info about the hidden components
|
||||
* @num_pds: number of hidden raid components
|
||||
* @responding: used in _scsih_raid_device_mark_responding
|
||||
*/
|
||||
struct _raid_device {
|
||||
struct list_head list;
|
||||
struct scsi_target *starget;
|
||||
struct scsi_device *sdev;
|
||||
u64 wwid;
|
||||
u16 handle;
|
||||
int id;
|
||||
int channel;
|
||||
u8 volume_type;
|
||||
u32 device_info;
|
||||
u8 num_pds;
|
||||
u8 responding;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct _boot_device - boot device info
|
||||
* @is_raid: flag to indicate whether this is volume
|
||||
* @device: holds pointer for either struct _sas_device or
|
||||
* struct _raid_device
|
||||
*/
|
||||
struct _boot_device {
|
||||
u8 is_raid;
|
||||
void *device;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct _sas_port - wide/narrow sas port information
|
||||
* @port_list: list of ports belonging to expander
|
||||
* @handle: device handle for this port
|
||||
* @sas_address: sas address of this port
|
||||
* @num_phys: number of phys belonging to this port
|
||||
* @remote_identify: attached device identification
|
||||
* @rphy: sas transport rphy object
|
||||
* @port: sas transport wide/narrow port object
|
||||
* @phy_list: _sas_phy list objects belonging to this port
|
||||
*/
|
||||
struct _sas_port {
|
||||
struct list_head port_list;
|
||||
u16 handle;
|
||||
u64 sas_address;
|
||||
u8 num_phys;
|
||||
struct sas_identify remote_identify;
|
||||
struct sas_rphy *rphy;
|
||||
struct sas_port *port;
|
||||
struct list_head phy_list;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct _sas_phy - phy information
|
||||
* @port_siblings: list of phys belonging to a port
|
||||
* @identify: phy identification
|
||||
* @remote_identify: attached device identification
|
||||
* @phy: sas transport phy object
|
||||
* @phy_id: unique phy id
|
||||
* @handle: device handle for this phy
|
||||
* @attached_handle: device handle for attached device
|
||||
*/
|
||||
struct _sas_phy {
|
||||
struct list_head port_siblings;
|
||||
struct sas_identify identify;
|
||||
struct sas_identify remote_identify;
|
||||
struct sas_phy *phy;
|
||||
u8 phy_id;
|
||||
u16 handle;
|
||||
u16 attached_handle;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct _sas_node - sas_host/expander information
|
||||
* @list: list of expanders
|
||||
* @parent_dev: parent device class
|
||||
* @num_phys: number phys belonging to this sas_host/expander
|
||||
* @sas_address: sas address of this sas_host/expander
|
||||
* @handle: handle for this sas_host/expander
|
||||
* @parent_handle: parent handle
|
||||
* @enclosure_handle: handle for this a member of an enclosure
|
||||
* @device_info: bitwise defining capabilities of this sas_host/expander
|
||||
* @responding: used in _scsih_expander_device_mark_responding
|
||||
* @phy: a list of phys that make up this sas_host/expander
|
||||
* @sas_port_list: list of ports attached to this sas_host/expander
|
||||
*/
|
||||
struct _sas_node {
|
||||
struct list_head list;
|
||||
struct device *parent_dev;
|
||||
u8 num_phys;
|
||||
u64 sas_address;
|
||||
u16 handle;
|
||||
u16 parent_handle;
|
||||
u16 enclosure_handle;
|
||||
u64 enclosure_logical_id;
|
||||
u8 responding;
|
||||
struct _sas_phy *phy;
|
||||
struct list_head sas_port_list;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum reset_type - reset state
|
||||
* @FORCE_BIG_HAMMER: issue diagnostic reset
|
||||
* @SOFT_RESET: issue message_unit_reset, if fails to to big hammer
|
||||
*/
|
||||
enum reset_type {
|
||||
FORCE_BIG_HAMMER,
|
||||
SOFT_RESET,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct request_tracker - firmware request tracker
|
||||
* @smid: system message id
|
||||
* @scmd: scsi request pointer
|
||||
* @cb_idx: callback index
|
||||
* @chain_list: list of chains associated to this IO
|
||||
* @tracker_list: list of free request (ioc->free_list)
|
||||
*/
|
||||
struct request_tracker {
|
||||
u16 smid;
|
||||
struct scsi_cmnd *scmd;
|
||||
u8 cb_idx;
|
||||
struct list_head tracker_list;
|
||||
};
|
||||
|
||||
typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
|
||||
|
||||
/**
|
||||
* struct MPT2SAS_ADAPTER - per adapter struct
|
||||
* @list: ioc_list
|
||||
* @shost: shost object
|
||||
* @id: unique adapter id
|
||||
* @pci_irq: irq number
|
||||
* @name: generic ioc string
|
||||
* @tmp_string: tmp string used for logging
|
||||
* @pdev: pci pdev object
|
||||
* @chip: memory mapped register space
|
||||
* @chip_phys: physical addrss prior to mapping
|
||||
* @pio_chip: I/O mapped register space
|
||||
* @logging_level: see mpt2sas_debug.h
|
||||
* @ir_firmware: IR firmware present
|
||||
* @bars: bitmask of BAR's that must be configured
|
||||
* @mask_interrupts: ignore interrupt
|
||||
* @fault_reset_work_q_name: fw fault work queue
|
||||
* @fault_reset_work_q: ""
|
||||
* @fault_reset_work: ""
|
||||
* @firmware_event_name: fw event work queue
|
||||
* @firmware_event_thread: ""
|
||||
* @fw_events_off: flag to turn off fw event handling
|
||||
* @fw_event_lock:
|
||||
* @fw_event_list: list of fw events
|
||||
* @aen_event_read_flag: event log was read
|
||||
* @broadcast_aen_busy: broadcast aen waiting to be serviced
|
||||
* @ioc_reset_in_progress: host reset in progress
|
||||
* @ioc_reset_in_progress_lock:
|
||||
* @ioc_link_reset_in_progress: phy/hard reset in progress
|
||||
* @ignore_loginfos: ignore loginfos during task managment
|
||||
* @remove_host: flag for when driver unloads, to avoid sending dev resets
|
||||
* @wait_for_port_enable_to_complete:
|
||||
* @msix_enable: flag indicating msix is enabled
|
||||
* @msix_vector_count: number msix vectors
|
||||
* @msix_table: virt address to the msix table
|
||||
* @msix_table_backup: backup msix table
|
||||
* @scsi_io_cb_idx: shost generated commands
|
||||
* @tm_cb_idx: task management commands
|
||||
* @transport_cb_idx: transport internal commands
|
||||
* @ctl_cb_idx: clt internal commands
|
||||
* @base_cb_idx: base internal commands
|
||||
* @config_cb_idx: base internal commands
|
||||
* @base_cmds:
|
||||
* @transport_cmds:
|
||||
* @tm_cmds:
|
||||
* @ctl_cmds:
|
||||
* @config_cmds:
|
||||
* @base_add_sg_single: handler for either 32/64 bit sgl's
|
||||
* @event_type: bits indicating which events to log
|
||||
* @event_context: unique id for each logged event
|
||||
* @event_log: event log pointer
|
||||
* @event_masks: events that are masked
|
||||
* @facts: static facts data
|
||||
* @pfacts: static port facts data
|
||||
* @manu_pg0: static manufacturing page 0
|
||||
* @bios_pg2: static bios page 2
|
||||
* @bios_pg3: static bios page 3
|
||||
* @ioc_pg8: static ioc page 8
|
||||
* @iounit_pg0: static iounit page 0
|
||||
* @iounit_pg1: static iounit page 1
|
||||
* @sas_hba: sas host object
|
||||
* @sas_expander_list: expander object list
|
||||
* @sas_node_lock:
|
||||
* @sas_device_list: sas device object list
|
||||
* @sas_device_init_list: sas device object list (used only at init time)
|
||||
* @sas_device_lock:
|
||||
* @io_missing_delay: time for IO completed by fw when PDR enabled
|
||||
* @device_missing_delay: time for device missing by fw when PDR enabled
|
||||
* @config_page_sz: config page size
|
||||
* @config_page: reserve memory for config page payload
|
||||
* @config_page_dma:
|
||||
* @sge_size: sg element size for either 32/64 bit
|
||||
* @request_depth: hba request queue depth
|
||||
* @request_sz: per request frame size
|
||||
* @request: pool of request frames
|
||||
* @request_dma:
|
||||
* @request_dma_sz:
|
||||
* @scsi_lookup: firmware request tracker list
|
||||
* @scsi_lookup_lock:
|
||||
* @free_list: free list of request
|
||||
* @chain: pool of chains
|
||||
* @pending_io_count:
|
||||
* @reset_wq:
|
||||
* @chain_dma:
|
||||
* @max_sges_in_main_message: number sg elements in main message
|
||||
* @max_sges_in_chain_message: number sg elements per chain
|
||||
* @chains_needed_per_io: max chains per io
|
||||
* @chain_offset_value_for_main_message: location 1st sg in main
|
||||
* @chain_depth: total chains allocated
|
||||
* @sense: pool of sense
|
||||
* @sense_dma:
|
||||
* @sense_dma_pool:
|
||||
* @reply_depth: hba reply queue depth:
|
||||
* @reply_sz: per reply frame size:
|
||||
* @reply: pool of replys:
|
||||
* @reply_dma:
|
||||
* @reply_dma_pool:
|
||||
* @reply_free_queue_depth: reply free depth
|
||||
* @reply_free: pool for reply free queue (32 bit addr)
|
||||
* @reply_free_dma:
|
||||
* @reply_free_dma_pool:
|
||||
* @reply_free_host_index: tail index in pool to insert free replys
|
||||
* @reply_post_queue_depth: reply post queue depth
|
||||
* @reply_post_free: pool for reply post (64bit descriptor)
|
||||
* @reply_post_free_dma:
|
||||
* @reply_post_free_dma_pool:
|
||||
* @reply_post_host_index: head index in the pool where FW completes IO
|
||||
*/
|
||||
struct MPT2SAS_ADAPTER {
|
||||
struct list_head list;
|
||||
struct Scsi_Host *shost;
|
||||
u8 id;
|
||||
u32 pci_irq;
|
||||
char name[MPT_NAME_LENGTH];
|
||||
char tmp_string[MPT_STRING_LENGTH];
|
||||
struct pci_dev *pdev;
|
||||
Mpi2SystemInterfaceRegs_t __iomem *chip;
|
||||
unsigned long chip_phys;
|
||||
unsigned long pio_chip;
|
||||
int logging_level;
|
||||
u8 ir_firmware;
|
||||
int bars;
|
||||
u8 mask_interrupts;
|
||||
|
||||
/* fw fault handler */
|
||||
char fault_reset_work_q_name[20];
|
||||
struct workqueue_struct *fault_reset_work_q;
|
||||
struct delayed_work fault_reset_work;
|
||||
|
||||
/* fw event handler */
|
||||
char firmware_event_name[20];
|
||||
struct workqueue_struct *firmware_event_thread;
|
||||
u8 fw_events_off;
|
||||
spinlock_t fw_event_lock;
|
||||
struct list_head fw_event_list;
|
||||
|
||||
/* misc flags */
|
||||
int aen_event_read_flag;
|
||||
u8 broadcast_aen_busy;
|
||||
u8 ioc_reset_in_progress;
|
||||
u8 shost_recovery;
|
||||
spinlock_t ioc_reset_in_progress_lock;
|
||||
u8 ioc_link_reset_in_progress;
|
||||
u8 ignore_loginfos;
|
||||
u8 remove_host;
|
||||
u8 wait_for_port_enable_to_complete;
|
||||
|
||||
u8 msix_enable;
|
||||
u16 msix_vector_count;
|
||||
u32 *msix_table;
|
||||
u32 *msix_table_backup;
|
||||
|
||||
/* internal commands, callback index */
|
||||
u8 scsi_io_cb_idx;
|
||||
u8 tm_cb_idx;
|
||||
u8 transport_cb_idx;
|
||||
u8 ctl_cb_idx;
|
||||
u8 base_cb_idx;
|
||||
u8 config_cb_idx;
|
||||
struct _internal_cmd base_cmds;
|
||||
struct _internal_cmd transport_cmds;
|
||||
struct _internal_cmd tm_cmds;
|
||||
struct _internal_cmd ctl_cmds;
|
||||
struct _internal_cmd config_cmds;
|
||||
|
||||
MPT_ADD_SGE base_add_sg_single;
|
||||
|
||||
/* event log */
|
||||
u32 event_type[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];
|
||||
u32 event_context;
|
||||
void *event_log;
|
||||
u32 event_masks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];
|
||||
|
||||
/* static config pages */
|
||||
Mpi2IOCFactsReply_t facts;
|
||||
Mpi2PortFactsReply_t *pfacts;
|
||||
Mpi2ManufacturingPage0_t manu_pg0;
|
||||
Mpi2BiosPage2_t bios_pg2;
|
||||
Mpi2BiosPage3_t bios_pg3;
|
||||
Mpi2IOCPage8_t ioc_pg8;
|
||||
Mpi2IOUnitPage0_t iounit_pg0;
|
||||
Mpi2IOUnitPage1_t iounit_pg1;
|
||||
|
||||
struct _boot_device req_boot_device;
|
||||
struct _boot_device req_alt_boot_device;
|
||||
struct _boot_device current_boot_device;
|
||||
|
||||
/* sas hba, expander, and device list */
|
||||
struct _sas_node sas_hba;
|
||||
struct list_head sas_expander_list;
|
||||
spinlock_t sas_node_lock;
|
||||
struct list_head sas_device_list;
|
||||
struct list_head sas_device_init_list;
|
||||
spinlock_t sas_device_lock;
|
||||
struct list_head raid_device_list;
|
||||
spinlock_t raid_device_lock;
|
||||
u8 io_missing_delay;
|
||||
u16 device_missing_delay;
|
||||
int sas_id;
|
||||
|
||||
/* config page */
|
||||
u16 config_page_sz;
|
||||
void *config_page;
|
||||
dma_addr_t config_page_dma;
|
||||
|
||||
/* request */
|
||||
u16 sge_size;
|
||||
u16 request_depth;
|
||||
u16 request_sz;
|
||||
u8 *request;
|
||||
dma_addr_t request_dma;
|
||||
u32 request_dma_sz;
|
||||
struct request_tracker *scsi_lookup;
|
||||
spinlock_t scsi_lookup_lock;
|
||||
struct list_head free_list;
|
||||
int pending_io_count;
|
||||
wait_queue_head_t reset_wq;
|
||||
|
||||
/* chain */
|
||||
u8 *chain;
|
||||
dma_addr_t chain_dma;
|
||||
u16 max_sges_in_main_message;
|
||||
u16 max_sges_in_chain_message;
|
||||
u16 chains_needed_per_io;
|
||||
u16 chain_offset_value_for_main_message;
|
||||
u16 chain_depth;
|
||||
|
||||
/* sense */
|
||||
u8 *sense;
|
||||
dma_addr_t sense_dma;
|
||||
struct dma_pool *sense_dma_pool;
|
||||
|
||||
/* reply */
|
||||
u16 reply_sz;
|
||||
u8 *reply;
|
||||
dma_addr_t reply_dma;
|
||||
struct dma_pool *reply_dma_pool;
|
||||
|
||||
/* reply free queue */
|
||||
u16 reply_free_queue_depth;
|
||||
u32 *reply_free;
|
||||
dma_addr_t reply_free_dma;
|
||||
struct dma_pool *reply_free_dma_pool;
|
||||
u32 reply_free_host_index;
|
||||
|
||||
/* reply post queue */
|
||||
u16 reply_post_queue_depth;
|
||||
Mpi2ReplyDescriptorsUnion_t *reply_post_free;
|
||||
dma_addr_t reply_post_free_dma;
|
||||
struct dma_pool *reply_post_free_dma_pool;
|
||||
u32 reply_post_host_index;
|
||||
|
||||
/* diag buffer support */
|
||||
u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT];
|
||||
u32 diag_buffer_sz[MPI2_DIAG_BUF_TYPE_COUNT];
|
||||
dma_addr_t diag_buffer_dma[MPI2_DIAG_BUF_TYPE_COUNT];
|
||||
u8 diag_buffer_status[MPI2_DIAG_BUF_TYPE_COUNT];
|
||||
u32 unique_id[MPI2_DIAG_BUF_TYPE_COUNT];
|
||||
u32 product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23];
|
||||
u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT];
|
||||
};
|
||||
|
||||
typedef void (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
|
||||
u32 reply);
|
||||
|
||||
|
||||
/* base shared API */
|
||||
extern struct list_head mpt2sas_ioc_list;
|
||||
|
||||
int mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc);
|
||||
void mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc);
|
||||
int mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc);
|
||||
void mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc);
|
||||
int mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
|
||||
enum reset_type type);
|
||||
|
||||
void *mpt2sas_base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid);
|
||||
void *mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid);
|
||||
void mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr);
|
||||
dma_addr_t mpt2sas_base_get_msg_frame_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid);
|
||||
dma_addr_t mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid);
|
||||
|
||||
u16 mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx);
|
||||
void mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid);
|
||||
void mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id,
|
||||
u16 handle);
|
||||
void mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id);
|
||||
void mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid,
|
||||
u8 vf_id, u16 io_index);
|
||||
void mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id);
|
||||
void mpt2sas_base_initialize_callback_handler(void);
|
||||
u8 mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func);
|
||||
void mpt2sas_base_release_callback_handler(u8 cb_idx);
|
||||
|
||||
void mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
|
||||
void *mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr);
|
||||
|
||||
u32 mpt2sas_base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked);
|
||||
|
||||
void mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code);
|
||||
int mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc,
|
||||
Mpi2SasIoUnitControlReply_t *mpi_reply, Mpi2SasIoUnitControlRequest_t
|
||||
*mpi_request);
|
||||
int mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc,
|
||||
Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request);
|
||||
void mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type);
|
||||
|
||||
/* scsih shared API */
|
||||
void mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
|
||||
u8 type, u16 smid_task, ulong timeout);
|
||||
void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
|
||||
void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
|
||||
struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc,
|
||||
u16 handle);
|
||||
struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER
|
||||
*ioc, u64 sas_address);
|
||||
struct _sas_device *mpt2sas_scsih_sas_device_find_by_sas_address(
|
||||
struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
|
||||
|
||||
void mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply);
|
||||
void mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase);
|
||||
|
||||
/* config shared API */
|
||||
void mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
|
||||
int mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys);
|
||||
int mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc,
|
||||
Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page);
|
||||
int mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2BiosPage2_t *config_page);
|
||||
int mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2BiosPage3_t *config_page);
|
||||
int mpt2sas_config_get_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2IOUnitPage0_t *config_page);
|
||||
int mpt2sas_config_get_sas_device_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u32 handle);
|
||||
int mpt2sas_config_get_sas_device_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2SasDevicePage1_t *config_page, u32 form, u32 handle);
|
||||
int mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2SasIOUnitPage0_t *config_page, u16 sz);
|
||||
int mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2IOUnitPage1_t *config_page);
|
||||
int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2IOUnitPage1_t config_page);
|
||||
int mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz);
|
||||
int mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2IOCPage8_t *config_page);
|
||||
int mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2ExpanderPage0_t *config_page, u32 form, u32 handle);
|
||||
int mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2ExpanderPage1_t *config_page, u32 phy_number, u16 handle);
|
||||
int mpt2sas_config_get_enclosure_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2SasEnclosurePage0_t *config_page, u32 form, u32 handle);
|
||||
int mpt2sas_config_get_phy_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number);
|
||||
int mpt2sas_config_get_phy_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number);
|
||||
int mpt2sas_config_get_raid_volume_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, u32 handle);
|
||||
int mpt2sas_config_get_number_pds(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 *num_pds);
|
||||
int mpt2sas_config_get_raid_volume_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form, u32 handle, u16 sz);
|
||||
int mpt2sas_config_get_phys_disk_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, u32 form,
|
||||
u32 form_specific);
|
||||
int mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle,
|
||||
u16 *volume_handle);
|
||||
int mpt2sas_config_get_volume_wwid(struct MPT2SAS_ADAPTER *ioc, u16 volume_handle,
|
||||
u64 *wwid);
|
||||
|
||||
/* ctl shared API */
|
||||
extern struct device_attribute *mpt2sas_host_attrs[];
|
||||
extern struct device_attribute *mpt2sas_dev_attrs[];
|
||||
void mpt2sas_ctl_init(void);
|
||||
void mpt2sas_ctl_exit(void);
|
||||
void mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
|
||||
void mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase);
|
||||
void mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply);
|
||||
void mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,
|
||||
Mpi2EventNotificationReply_t *mpi_reply);
|
||||
|
||||
/* transport shared API */
|
||||
void mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
|
||||
struct _sas_port *mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc,
|
||||
u16 handle, u16 parent_handle);
|
||||
void mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
|
||||
u16 parent_handle);
|
||||
int mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
|
||||
*mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev);
|
||||
int mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
|
||||
*mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev);
|
||||
void mpt2sas_transport_update_phy_link_change(struct MPT2SAS_ADAPTER *ioc, u16 handle,
|
||||
u16 attached_handle, u8 phy_number, u8 link_rate);
|
||||
extern struct sas_function_template mpt2sas_transport_functions;
|
||||
extern struct scsi_transport_template *mpt2sas_transport_template;
|
||||
|
||||
#endif /* MPT2SAS_BASE_H_INCLUDED */
|
1873
drivers/scsi/mpt2sas/mpt2sas_config.c
Normal file
1873
drivers/scsi/mpt2sas/mpt2sas_config.c
Normal file
File diff suppressed because it is too large
Load Diff
2516
drivers/scsi/mpt2sas/mpt2sas_ctl.c
Normal file
2516
drivers/scsi/mpt2sas/mpt2sas_ctl.c
Normal file
File diff suppressed because it is too large
Load Diff
416
drivers/scsi/mpt2sas/mpt2sas_ctl.h
Normal file
416
drivers/scsi/mpt2sas/mpt2sas_ctl.h
Normal file
@ -0,0 +1,416 @@
|
||||
/*
|
||||
* Management Module Support for MPT (Message Passing Technology) based
|
||||
* controllers
|
||||
*
|
||||
* This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MPT2SAS_CTL_H_INCLUDED
|
||||
#define MPT2SAS_CTL_H_INCLUDED
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/miscdevice.h>
|
||||
#endif
|
||||
|
||||
#define MPT2SAS_DEV_NAME "mpt2ctl"
|
||||
#define MPT2_MAGIC_NUMBER 'm'
|
||||
#define MPT2_IOCTL_DEFAULT_TIMEOUT (10) /* in seconds */
|
||||
|
||||
/**
|
||||
* IOCTL opcodes
|
||||
*/
|
||||
#define MPT2IOCINFO _IOWR(MPT2_MAGIC_NUMBER, 17, \
|
||||
struct mpt2_ioctl_iocinfo)
|
||||
#define MPT2COMMAND _IOWR(MPT2_MAGIC_NUMBER, 20, \
|
||||
struct mpt2_ioctl_command)
|
||||
#ifdef CONFIG_COMPAT
|
||||
#define MPT2COMMAND32 _IOWR(MPT2_MAGIC_NUMBER, 20, \
|
||||
struct mpt2_ioctl_command32)
|
||||
#endif
|
||||
#define MPT2EVENTQUERY _IOWR(MPT2_MAGIC_NUMBER, 21, \
|
||||
struct mpt2_ioctl_eventquery)
|
||||
#define MPT2EVENTENABLE _IOWR(MPT2_MAGIC_NUMBER, 22, \
|
||||
struct mpt2_ioctl_eventenable)
|
||||
#define MPT2EVENTREPORT _IOWR(MPT2_MAGIC_NUMBER, 23, \
|
||||
struct mpt2_ioctl_eventreport)
|
||||
#define MPT2HARDRESET _IOWR(MPT2_MAGIC_NUMBER, 24, \
|
||||
struct mpt2_ioctl_diag_reset)
|
||||
#define MPT2BTDHMAPPING _IOWR(MPT2_MAGIC_NUMBER, 31, \
|
||||
struct mpt2_ioctl_btdh_mapping)
|
||||
|
||||
/* diag buffer support */
|
||||
#define MPT2DIAGREGISTER _IOWR(MPT2_MAGIC_NUMBER, 26, \
|
||||
struct mpt2_diag_register)
|
||||
#define MPT2DIAGRELEASE _IOWR(MPT2_MAGIC_NUMBER, 27, \
|
||||
struct mpt2_diag_release)
|
||||
#define MPT2DIAGUNREGISTER _IOWR(MPT2_MAGIC_NUMBER, 28, \
|
||||
struct mpt2_diag_unregister)
|
||||
#define MPT2DIAGQUERY _IOWR(MPT2_MAGIC_NUMBER, 29, \
|
||||
struct mpt2_diag_query)
|
||||
#define MPT2DIAGREADBUFFER _IOWR(MPT2_MAGIC_NUMBER, 30, \
|
||||
struct mpt2_diag_read_buffer)
|
||||
|
||||
/**
|
||||
* struct mpt2_ioctl_header - main header structure
|
||||
* @ioc_number - IOC unit number
|
||||
* @port_number - IOC port number
|
||||
* @max_data_size - maximum number bytes to transfer on read
|
||||
*/
|
||||
struct mpt2_ioctl_header {
|
||||
uint32_t ioc_number;
|
||||
uint32_t port_number;
|
||||
uint32_t max_data_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mpt2_ioctl_diag_reset - diagnostic reset
|
||||
* @hdr - generic header
|
||||
*/
|
||||
struct mpt2_ioctl_diag_reset {
|
||||
struct mpt2_ioctl_header hdr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* struct mpt2_ioctl_pci_info - pci device info
|
||||
* @device - pci device id
|
||||
* @function - pci function id
|
||||
* @bus - pci bus id
|
||||
* @segment_id - pci segment id
|
||||
*/
|
||||
struct mpt2_ioctl_pci_info {
|
||||
union {
|
||||
struct {
|
||||
uint32_t device:5;
|
||||
uint32_t function:3;
|
||||
uint32_t bus:24;
|
||||
} bits;
|
||||
uint32_t word;
|
||||
} u;
|
||||
uint32_t segment_id;
|
||||
};
|
||||
|
||||
|
||||
#define MPT2_IOCTL_INTERFACE_SCSI (0x00)
|
||||
#define MPT2_IOCTL_INTERFACE_FC (0x01)
|
||||
#define MPT2_IOCTL_INTERFACE_FC_IP (0x02)
|
||||
#define MPT2_IOCTL_INTERFACE_SAS (0x03)
|
||||
#define MPT2_IOCTL_INTERFACE_SAS2 (0x04)
|
||||
#define MPT2_IOCTL_VERSION_LENGTH (32)
|
||||
|
||||
/**
|
||||
* struct mpt2_ioctl_iocinfo - generic controller info
|
||||
* @hdr - generic header
|
||||
* @adapter_type - type of adapter (spi, fc, sas)
|
||||
* @port_number - port number
|
||||
* @pci_id - PCI Id
|
||||
* @hw_rev - hardware revision
|
||||
* @sub_system_device - PCI subsystem Device ID
|
||||
* @sub_system_vendor - PCI subsystem Vendor ID
|
||||
* @rsvd0 - reserved
|
||||
* @firmware_version - firmware version
|
||||
* @bios_version - BIOS version
|
||||
* @driver_version - driver version - 32 ASCII characters
|
||||
* @rsvd1 - reserved
|
||||
* @scsi_id - scsi id of adapter 0
|
||||
* @rsvd2 - reserved
|
||||
* @pci_information - pci info (2nd revision)
|
||||
*/
|
||||
struct mpt2_ioctl_iocinfo {
|
||||
struct mpt2_ioctl_header hdr;
|
||||
uint32_t adapter_type;
|
||||
uint32_t port_number;
|
||||
uint32_t pci_id;
|
||||
uint32_t hw_rev;
|
||||
uint32_t subsystem_device;
|
||||
uint32_t subsystem_vendor;
|
||||
uint32_t rsvd0;
|
||||
uint32_t firmware_version;
|
||||
uint32_t bios_version;
|
||||
uint8_t driver_version[MPT2_IOCTL_VERSION_LENGTH];
|
||||
uint8_t rsvd1;
|
||||
uint8_t scsi_id;
|
||||
uint16_t rsvd2;
|
||||
struct mpt2_ioctl_pci_info pci_information;
|
||||
};
|
||||
|
||||
|
||||
/* number of event log entries */
|
||||
#define MPT2SAS_CTL_EVENT_LOG_SIZE (50)
|
||||
|
||||
/**
|
||||
* struct mpt2_ioctl_eventquery - query event count and type
|
||||
* @hdr - generic header
|
||||
* @event_entries - number of events returned by get_event_report
|
||||
* @rsvd - reserved
|
||||
* @event_types - type of events currently being captured
|
||||
*/
|
||||
struct mpt2_ioctl_eventquery {
|
||||
struct mpt2_ioctl_header hdr;
|
||||
uint16_t event_entries;
|
||||
uint16_t rsvd;
|
||||
uint32_t event_types[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mpt2_ioctl_eventenable - enable/disable event capturing
|
||||
* @hdr - generic header
|
||||
* @event_types - toggle off/on type of events to be captured
|
||||
*/
|
||||
struct mpt2_ioctl_eventenable {
|
||||
struct mpt2_ioctl_header hdr;
|
||||
uint32_t event_types[4];
|
||||
};
|
||||
|
||||
#define MPT2_EVENT_DATA_SIZE (192)
|
||||
/**
|
||||
* struct MPT2_IOCTL_EVENTS -
|
||||
* @event - the event that was reported
|
||||
* @context - unique value for each event assigned by driver
|
||||
* @data - event data returned in fw reply message
|
||||
*/
|
||||
struct MPT2_IOCTL_EVENTS {
|
||||
uint32_t event;
|
||||
uint32_t context;
|
||||
uint8_t data[MPT2_EVENT_DATA_SIZE];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mpt2_ioctl_eventreport - returing event log
|
||||
* @hdr - generic header
|
||||
* @event_data - (see struct MPT2_IOCTL_EVENTS)
|
||||
*/
|
||||
struct mpt2_ioctl_eventreport {
|
||||
struct mpt2_ioctl_header hdr;
|
||||
struct MPT2_IOCTL_EVENTS event_data[1];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mpt2_ioctl_command - generic mpt firmware passthru ioclt
|
||||
* @hdr - generic header
|
||||
* @timeout - command timeout in seconds. (if zero then use driver default
|
||||
* value).
|
||||
* @reply_frame_buf_ptr - reply location
|
||||
* @data_in_buf_ptr - destination for read
|
||||
* @data_out_buf_ptr - data source for write
|
||||
* @sense_data_ptr - sense data location
|
||||
* @max_reply_bytes - maximum number of reply bytes to be sent to app.
|
||||
* @data_in_size - number bytes for data transfer in (read)
|
||||
* @data_out_size - number bytes for data transfer out (write)
|
||||
* @max_sense_bytes - maximum number of bytes for auto sense buffers
|
||||
* @data_sge_offset - offset in words from the start of the request message to
|
||||
* the first SGL
|
||||
* @mf[1];
|
||||
*/
|
||||
struct mpt2_ioctl_command {
|
||||
struct mpt2_ioctl_header hdr;
|
||||
uint32_t timeout;
|
||||
void __user *reply_frame_buf_ptr;
|
||||
void __user *data_in_buf_ptr;
|
||||
void __user *data_out_buf_ptr;
|
||||
void __user *sense_data_ptr;
|
||||
uint32_t max_reply_bytes;
|
||||
uint32_t data_in_size;
|
||||
uint32_t data_out_size;
|
||||
uint32_t max_sense_bytes;
|
||||
uint32_t data_sge_offset;
|
||||
uint8_t mf[1];
|
||||
};
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
struct mpt2_ioctl_command32 {
|
||||
struct mpt2_ioctl_header hdr;
|
||||
uint32_t timeout;
|
||||
uint32_t reply_frame_buf_ptr;
|
||||
uint32_t data_in_buf_ptr;
|
||||
uint32_t data_out_buf_ptr;
|
||||
uint32_t sense_data_ptr;
|
||||
uint32_t max_reply_bytes;
|
||||
uint32_t data_in_size;
|
||||
uint32_t data_out_size;
|
||||
uint32_t max_sense_bytes;
|
||||
uint32_t data_sge_offset;
|
||||
uint8_t mf[1];
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* struct mpt2_ioctl_btdh_mapping - mapping info
|
||||
* @hdr - generic header
|
||||
* @id - target device identification number
|
||||
* @bus - SCSI bus number that the target device exists on
|
||||
* @handle - device handle for the target device
|
||||
* @rsvd - reserved
|
||||
*
|
||||
* To obtain a bus/id the application sets
|
||||
* handle to valid handle, and bus/id to 0xFFFF.
|
||||
*
|
||||
* To obtain the device handle the application sets
|
||||
* bus/id valid value, and the handle to 0xFFFF.
|
||||
*/
|
||||
struct mpt2_ioctl_btdh_mapping {
|
||||
struct mpt2_ioctl_header hdr;
|
||||
uint32_t id;
|
||||
uint32_t bus;
|
||||
uint16_t handle;
|
||||
uint16_t rsvd;
|
||||
};
|
||||
|
||||
|
||||
/* status bits for ioc->diag_buffer_status */
|
||||
#define MPT2_DIAG_BUFFER_IS_REGISTERED (0x01)
|
||||
#define MPT2_DIAG_BUFFER_IS_RELEASED (0x02)
|
||||
|
||||
/* application flags for mpt2_diag_register, mpt2_diag_query */
|
||||
#define MPT2_APP_FLAGS_APP_OWNED (0x0001)
|
||||
#define MPT2_APP_FLAGS_BUFFER_VALID (0x0002)
|
||||
#define MPT2_APP_FLAGS_FW_BUFFER_ACCESS (0x0004)
|
||||
|
||||
/* flags for mpt2_diag_read_buffer */
|
||||
#define MPT2_FLAGS_REREGISTER (0x0001)
|
||||
|
||||
#define MPT2_PRODUCT_SPECIFIC_DWORDS 23
|
||||
|
||||
/**
|
||||
* struct mpt2_diag_register - application register with driver
|
||||
* @hdr - generic header
|
||||
* @reserved -
|
||||
* @buffer_type - specifies either TRACE or SNAPSHOT
|
||||
* @application_flags - misc flags
|
||||
* @diagnostic_flags - specifies flags affecting command processing
|
||||
* @product_specific - product specific information
|
||||
* @requested_buffer_size - buffers size in bytes
|
||||
* @unique_id - tag specified by application that is used to signal ownership
|
||||
* of the buffer.
|
||||
*
|
||||
* This will allow the driver to setup any required buffers that will be
|
||||
* needed by firmware to communicate with the driver.
|
||||
*/
|
||||
struct mpt2_diag_register {
|
||||
struct mpt2_ioctl_header hdr;
|
||||
uint8_t reserved;
|
||||
uint8_t buffer_type;
|
||||
uint16_t application_flags;
|
||||
uint32_t diagnostic_flags;
|
||||
uint32_t product_specific[MPT2_PRODUCT_SPECIFIC_DWORDS];
|
||||
uint32_t requested_buffer_size;
|
||||
uint32_t unique_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mpt2_diag_unregister - application unregister with driver
|
||||
* @hdr - generic header
|
||||
* @unique_id - tag uniquely identifies the buffer to be unregistered
|
||||
*
|
||||
* This will allow the driver to cleanup any memory allocated for diag
|
||||
* messages and to free up any resources.
|
||||
*/
|
||||
struct mpt2_diag_unregister {
|
||||
struct mpt2_ioctl_header hdr;
|
||||
uint32_t unique_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mpt2_diag_query - query relevant info associated with diag buffers
|
||||
* @hdr - generic header
|
||||
* @reserved -
|
||||
* @buffer_type - specifies either TRACE or SNAPSHOT
|
||||
* @application_flags - misc flags
|
||||
* @diagnostic_flags - specifies flags affecting command processing
|
||||
* @product_specific - product specific information
|
||||
* @total_buffer_size - diag buffer size in bytes
|
||||
* @driver_added_buffer_size - size of extra space appended to end of buffer
|
||||
* @unique_id - unique id associated with this buffer.
|
||||
*
|
||||
* The application will send only buffer_type and unique_id. Driver will
|
||||
* inspect unique_id first, if valid, fill in all the info. If unique_id is
|
||||
* 0x00, the driver will return info specified by Buffer Type.
|
||||
*/
|
||||
struct mpt2_diag_query {
|
||||
struct mpt2_ioctl_header hdr;
|
||||
uint8_t reserved;
|
||||
uint8_t buffer_type;
|
||||
uint16_t application_flags;
|
||||
uint32_t diagnostic_flags;
|
||||
uint32_t product_specific[MPT2_PRODUCT_SPECIFIC_DWORDS];
|
||||
uint32_t total_buffer_size;
|
||||
uint32_t driver_added_buffer_size;
|
||||
uint32_t unique_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mpt2_diag_release - request to send Diag Release Message to firmware
|
||||
* @hdr - generic header
|
||||
* @unique_id - tag uniquely identifies the buffer to be released
|
||||
*
|
||||
* This allows ownership of the specified buffer to returned to the driver,
|
||||
* allowing an application to read the buffer without fear that firmware is
|
||||
* overwritting information in the buffer.
|
||||
*/
|
||||
struct mpt2_diag_release {
|
||||
struct mpt2_ioctl_header hdr;
|
||||
uint32_t unique_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mpt2_diag_read_buffer - request for copy of the diag buffer
|
||||
* @hdr - generic header
|
||||
* @status -
|
||||
* @reserved -
|
||||
* @flags - misc flags
|
||||
* @starting_offset - starting offset within drivers buffer where to start
|
||||
* reading data at into the specified application buffer
|
||||
* @bytes_to_read - number of bytes to copy from the drivers buffer into the
|
||||
* application buffer starting at starting_offset.
|
||||
* @unique_id - unique id associated with this buffer.
|
||||
* @diagnostic_data - data payload
|
||||
*/
|
||||
struct mpt2_diag_read_buffer {
|
||||
struct mpt2_ioctl_header hdr;
|
||||
uint8_t status;
|
||||
uint8_t reserved;
|
||||
uint16_t flags;
|
||||
uint32_t starting_offset;
|
||||
uint32_t bytes_to_read;
|
||||
uint32_t unique_id;
|
||||
uint32_t diagnostic_data[1];
|
||||
};
|
||||
|
||||
#endif /* MPT2SAS_CTL_H_INCLUDED */
|
181
drivers/scsi/mpt2sas/mpt2sas_debug.h
Normal file
181
drivers/scsi/mpt2sas/mpt2sas_debug.h
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Logging Support for MPT (Message Passing Technology) based controllers
|
||||
*
|
||||
* This code is based on drivers/scsi/mpt2sas/mpt2_debug.c
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MPT2SAS_DEBUG_H_INCLUDED
|
||||
#define MPT2SAS_DEBUG_H_INCLUDED
|
||||
|
||||
#define MPT_DEBUG 0x00000001
|
||||
#define MPT_DEBUG_MSG_FRAME 0x00000002
|
||||
#define MPT_DEBUG_SG 0x00000004
|
||||
#define MPT_DEBUG_EVENTS 0x00000008
|
||||
#define MPT_DEBUG_EVENT_WORK_TASK 0x00000010
|
||||
#define MPT_DEBUG_INIT 0x00000020
|
||||
#define MPT_DEBUG_EXIT 0x00000040
|
||||
#define MPT_DEBUG_FAIL 0x00000080
|
||||
#define MPT_DEBUG_TM 0x00000100
|
||||
#define MPT_DEBUG_REPLY 0x00000200
|
||||
#define MPT_DEBUG_HANDSHAKE 0x00000400
|
||||
#define MPT_DEBUG_CONFIG 0x00000800
|
||||
#define MPT_DEBUG_DL 0x00001000
|
||||
#define MPT_DEBUG_RESET 0x00002000
|
||||
#define MPT_DEBUG_SCSI 0x00004000
|
||||
#define MPT_DEBUG_IOCTL 0x00008000
|
||||
#define MPT_DEBUG_CSMISAS 0x00010000
|
||||
#define MPT_DEBUG_SAS 0x00020000
|
||||
#define MPT_DEBUG_TRANSPORT 0x00040000
|
||||
#define MPT_DEBUG_TASK_SET_FULL 0x00080000
|
||||
|
||||
#define MPT_DEBUG_TARGET_MODE 0x00100000
|
||||
|
||||
|
||||
/*
|
||||
* CONFIG_SCSI_MPT2SAS_LOGGING - enabled in Kconfig
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
|
||||
#define MPT_CHECK_LOGGING(IOC, CMD, BITS) \
|
||||
{ \
|
||||
if (IOC->logging_level & BITS) \
|
||||
CMD; \
|
||||
}
|
||||
#else
|
||||
#define MPT_CHECK_LOGGING(IOC, CMD, BITS)
|
||||
#endif /* CONFIG_SCSI_MPT2SAS_LOGGING */
|
||||
|
||||
|
||||
/*
|
||||
* debug macros
|
||||
*/
|
||||
|
||||
#define dprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG)
|
||||
|
||||
#define dsgprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SG)
|
||||
|
||||
#define devtprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENTS)
|
||||
|
||||
#define dewtprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENT_WORK_TASK)
|
||||
|
||||
#define dinitprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_INIT)
|
||||
|
||||
#define dexitprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EXIT)
|
||||
|
||||
#define dfailprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_FAIL)
|
||||
|
||||
#define dtmprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TM)
|
||||
|
||||
#define dreplyprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_REPLY)
|
||||
|
||||
#define dhsprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_HANDSHAKE)
|
||||
|
||||
#define dcprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CONFIG)
|
||||
|
||||
#define ddlprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_DL)
|
||||
|
||||
#define drsprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_RESET)
|
||||
|
||||
#define dsprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SCSI)
|
||||
|
||||
#define dctlprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_IOCTL)
|
||||
|
||||
#define dcsmisasprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CSMISAS)
|
||||
|
||||
#define dsasprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS)
|
||||
|
||||
#define dsastransport(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE)
|
||||
|
||||
#define dmfprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_MSG_FRAME)
|
||||
|
||||
#define dtsfprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TASK_SET_FULL)
|
||||
|
||||
#define dtransportprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TRANSPORT)
|
||||
|
||||
#define dTMprintk(IOC, CMD) \
|
||||
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TARGET_MODE)
|
||||
|
||||
/* inline functions for dumping debug data*/
|
||||
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
|
||||
/**
|
||||
* _debug_dump_mf - print message frame contents
|
||||
* @mpi_request: pointer to message frame
|
||||
* @sz: number of dwords
|
||||
*/
|
||||
static inline void
|
||||
_debug_dump_mf(void *mpi_request, int sz)
|
||||
{
|
||||
int i;
|
||||
u32 *mfp = (u32 *)mpi_request;
|
||||
|
||||
printk(KERN_INFO "mf:\n\t");
|
||||
for (i = 0; i < sz; i++) {
|
||||
if (i && ((i % 8) == 0))
|
||||
printk("\n\t");
|
||||
printk("%08x ", le32_to_cpu(mfp[i]));
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
#else
|
||||
#define _debug_dump_mf(mpi_request, sz)
|
||||
#endif /* CONFIG_SCSI_MPT2SAS_LOGGING */
|
||||
|
||||
#endif /* MPT2SAS_DEBUG_H_INCLUDED */
|
5687
drivers/scsi/mpt2sas/mpt2sas_scsih.c
Normal file
5687
drivers/scsi/mpt2sas/mpt2sas_scsih.c
Normal file
File diff suppressed because it is too large
Load Diff
1211
drivers/scsi/mpt2sas/mpt2sas_transport.c
Normal file
1211
drivers/scsi/mpt2sas/mpt2sas_transport.c
Normal file
File diff suppressed because it is too large
Load Diff
45
drivers/scsi/osd/Kbuild
Normal file
45
drivers/scsi/osd/Kbuild
Normal file
@ -0,0 +1,45 @@
|
||||
#
|
||||
# Kbuild for the OSD modules
|
||||
#
|
||||
# Copyright (C) 2008 Panasas Inc. All rights reserved.
|
||||
#
|
||||
# Authors:
|
||||
# Boaz Harrosh <bharrosh@panasas.com>
|
||||
# Benny Halevy <bhalevy@panasas.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2
|
||||
#
|
||||
|
||||
ifneq ($(OSD_INC),)
|
||||
# we are built out-of-tree Kconfigure everything as on
|
||||
|
||||
CONFIG_SCSI_OSD_INITIATOR=m
|
||||
ccflags-y += -DCONFIG_SCSI_OSD_INITIATOR -DCONFIG_SCSI_OSD_INITIATOR_MODULE
|
||||
|
||||
CONFIG_SCSI_OSD_ULD=m
|
||||
ccflags-y += -DCONFIG_SCSI_OSD_ULD -DCONFIG_SCSI_OSD_ULD_MODULE
|
||||
|
||||
# CONFIG_SCSI_OSD_DPRINT_SENSE =
|
||||
# 0 - no print of errors
|
||||
# 1 - print errors
|
||||
# 2 - errors + warrnings
|
||||
ccflags-y += -DCONFIG_SCSI_OSD_DPRINT_SENSE=1
|
||||
|
||||
# Uncomment to turn debug on
|
||||
# ccflags-y += -DCONFIG_SCSI_OSD_DEBUG
|
||||
|
||||
# if we are built out-of-tree and the hosting kernel has OSD headers
|
||||
# then "ccflags-y +=" will not pick the out-off-tree headers. Only by doing
|
||||
# this it will work. This might break in future kernels
|
||||
LINUXINCLUDE := -I$(OSD_INC) $(LINUXINCLUDE)
|
||||
|
||||
endif
|
||||
|
||||
# libosd.ko - osd-initiator library
|
||||
libosd-y := osd_initiator.o
|
||||
obj-$(CONFIG_SCSI_OSD_INITIATOR) += libosd.o
|
||||
|
||||
# osd.ko - SCSI ULD and char-device
|
||||
osd-y := osd_uld.o
|
||||
obj-$(CONFIG_SCSI_OSD_ULD) += osd.o
|
53
drivers/scsi/osd/Kconfig
Normal file
53
drivers/scsi/osd/Kconfig
Normal file
@ -0,0 +1,53 @@
|
||||
#
|
||||
# Kernel configuration file for the OSD scsi protocol
|
||||
#
|
||||
# Copyright (C) 2008 Panasas Inc. All rights reserved.
|
||||
#
|
||||
# Authors:
|
||||
# Boaz Harrosh <bharrosh@panasas.com>
|
||||
# Benny Halevy <bhalevy@panasas.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public version 2 License as
|
||||
# published by the Free Software Foundation
|
||||
#
|
||||
# FIXME: SCSI_OSD_INITIATOR should select CONFIG (HMAC) SHA1 somehow.
|
||||
# How is it done properly?
|
||||
#
|
||||
|
||||
config SCSI_OSD_INITIATOR
|
||||
tristate "OSD-Initiator library"
|
||||
depends on SCSI
|
||||
help
|
||||
Enable the OSD-Initiator library (libosd.ko).
|
||||
NOTE: You must also select CRYPTO_SHA1 + CRYPTO_HMAC and their
|
||||
dependencies
|
||||
|
||||
config SCSI_OSD_ULD
|
||||
tristate "OSD Upper Level driver"
|
||||
depends on SCSI_OSD_INITIATOR
|
||||
help
|
||||
Build a SCSI upper layer driver that exports /dev/osdX devices
|
||||
to user-mode for testing and controlling OSD devices. It is also
|
||||
needed by exofs, for mounting an OSD based file system.
|
||||
|
||||
config SCSI_OSD_DPRINT_SENSE
|
||||
int "(0-2) When sense is returned, DEBUG print all sense descriptors"
|
||||
default 1
|
||||
depends on SCSI_OSD_INITIATOR
|
||||
help
|
||||
When a CHECK_CONDITION status is returned from a target, and a
|
||||
sense-buffer is retrieved, turning this on will dump a full
|
||||
sense-decoding message. Setting to 2 will also print recoverable
|
||||
errors that might be regularly returned for some filesystem
|
||||
operations.
|
||||
|
||||
config SCSI_OSD_DEBUG
|
||||
bool "Compile All OSD modules with lots of DEBUG prints"
|
||||
default n
|
||||
depends on SCSI_OSD_INITIATOR
|
||||
help
|
||||
OSD Code is populated with lots of OSD_DEBUG(..) printouts to
|
||||
dmesg. Enable this if you found a bug and you want to help us
|
||||
track the problem (see also MAINTAINERS). Setting this will also
|
||||
force SCSI_OSD_DPRINT_SENSE=2.
|
37
drivers/scsi/osd/Makefile
Executable file
37
drivers/scsi/osd/Makefile
Executable file
@ -0,0 +1,37 @@
|
||||
#
|
||||
# Makefile for the OSD modules (out of tree)
|
||||
#
|
||||
# Copyright (C) 2008 Panasas Inc. All rights reserved.
|
||||
#
|
||||
# Authors:
|
||||
# Boaz Harrosh <bharrosh@panasas.com>
|
||||
# Benny Halevy <bhalevy@panasas.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2
|
||||
#
|
||||
# This Makefile is used to call the kernel Makefile in case of an out-of-tree
|
||||
# build.
|
||||
# $KSRC should point to a Kernel source tree otherwise host's default is
|
||||
# used. (eg. /lib/modules/`uname -r`/build)
|
||||
|
||||
# include path for out-of-tree Headers
|
||||
OSD_INC ?= `pwd`/../../../include
|
||||
|
||||
# allow users to override these
|
||||
# e.g. to compile for a kernel that you aren't currently running
|
||||
KSRC ?= /lib/modules/$(shell uname -r)/build
|
||||
KBUILD_OUTPUT ?=
|
||||
ARCH ?=
|
||||
V ?= 0
|
||||
|
||||
# this is the basic Kbuild out-of-tree invocation, with the M= option
|
||||
KBUILD_BASE = +$(MAKE) -C $(KSRC) M=`pwd` KBUILD_OUTPUT=$(KBUILD_OUTPUT) ARCH=$(ARCH) V=$(V)
|
||||
|
||||
all: libosd
|
||||
|
||||
libosd: ;
|
||||
$(KBUILD_BASE) OSD_INC=$(OSD_INC) modules
|
||||
|
||||
clean:
|
||||
$(KBUILD_BASE) clean
|
30
drivers/scsi/osd/osd_debug.h
Normal file
30
drivers/scsi/osd/osd_debug.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* osd_debug.h - Some kprintf macros
|
||||
*
|
||||
* Copyright (C) 2008 Panasas Inc. All rights reserved.
|
||||
*
|
||||
* Authors:
|
||||
* Boaz Harrosh <bharrosh@panasas.com>
|
||||
* Benny Halevy <bhalevy@panasas.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
*
|
||||
*/
|
||||
#ifndef __OSD_DEBUG_H__
|
||||
#define __OSD_DEBUG_H__
|
||||
|
||||
#define OSD_ERR(fmt, a...) printk(KERN_ERR "osd: " fmt, ##a)
|
||||
#define OSD_INFO(fmt, a...) printk(KERN_NOTICE "osd: " fmt, ##a)
|
||||
|
||||
#ifdef CONFIG_SCSI_OSD_DEBUG
|
||||
#define OSD_DEBUG(fmt, a...) \
|
||||
printk(KERN_NOTICE "osd @%s:%d: " fmt, __func__, __LINE__, ##a)
|
||||
#else
|
||||
#define OSD_DEBUG(fmt, a...) do {} while (0)
|
||||
#endif
|
||||
|
||||
/* u64 has problems with printk this will cast it to unsigned long long */
|
||||
#define _LLU(x) (unsigned long long)(x)
|
||||
|
||||
#endif /* ndef __OSD_DEBUG_H__ */
|
1657
drivers/scsi/osd/osd_initiator.c
Normal file
1657
drivers/scsi/osd/osd_initiator.c
Normal file
File diff suppressed because it is too large
Load Diff
487
drivers/scsi/osd/osd_uld.c
Normal file
487
drivers/scsi/osd/osd_uld.c
Normal file
@ -0,0 +1,487 @@
|
||||
/*
|
||||
* osd_uld.c - OSD Upper Layer Driver
|
||||
*
|
||||
* A Linux driver module that registers as a SCSI ULD and probes
|
||||
* for OSD type SCSI devices.
|
||||
* It's main function is to export osd devices to in-kernel users like
|
||||
* osdfs and pNFS-objects-LD. It also provides one ioctl for running
|
||||
* in Kernel tests.
|
||||
*
|
||||
* Copyright (C) 2008 Panasas Inc. All rights reserved.
|
||||
*
|
||||
* Authors:
|
||||
* Boaz Harrosh <bharrosh@panasas.com>
|
||||
* Benny Halevy <bhalevy@panasas.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Panasas company nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) 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 OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <linux/namei.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/major.h>
|
||||
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_driver.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi_ioctl.h>
|
||||
|
||||
#include <scsi/osd_initiator.h>
|
||||
#include <scsi/osd_sec.h>
|
||||
|
||||
#include "osd_debug.h"
|
||||
|
||||
#ifndef TYPE_OSD
|
||||
# define TYPE_OSD 0x11
|
||||
#endif
|
||||
|
||||
#ifndef SCSI_OSD_MAJOR
|
||||
# define SCSI_OSD_MAJOR 260
|
||||
#endif
|
||||
#define SCSI_OSD_MAX_MINOR 64
|
||||
|
||||
static const char osd_name[] = "osd";
|
||||
static const char *osd_version_string = "open-osd 0.1.0";
|
||||
const char osd_symlink[] = "scsi_osd";
|
||||
|
||||
MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>");
|
||||
MODULE_DESCRIPTION("open-osd Upper-Layer-Driver osd.ko");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_CHARDEV_MAJOR(SCSI_OSD_MAJOR);
|
||||
MODULE_ALIAS_SCSI_DEVICE(TYPE_OSD);
|
||||
|
||||
struct osd_uld_device {
|
||||
int minor;
|
||||
struct kref kref;
|
||||
struct cdev cdev;
|
||||
struct osd_dev od;
|
||||
struct gendisk *disk;
|
||||
struct device *class_member;
|
||||
};
|
||||
|
||||
static void __uld_get(struct osd_uld_device *oud);
|
||||
static void __uld_put(struct osd_uld_device *oud);
|
||||
|
||||
/*
|
||||
* Char Device operations
|
||||
*/
|
||||
|
||||
static int osd_uld_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct osd_uld_device *oud = container_of(inode->i_cdev,
|
||||
struct osd_uld_device, cdev);
|
||||
|
||||
__uld_get(oud);
|
||||
/* cache osd_uld_device on file handle */
|
||||
file->private_data = oud;
|
||||
OSD_DEBUG("osd_uld_open %p\n", oud);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int osd_uld_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct osd_uld_device *oud = file->private_data;
|
||||
|
||||
OSD_DEBUG("osd_uld_release %p\n", file->private_data);
|
||||
file->private_data = NULL;
|
||||
__uld_put(oud);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: Only one vector for now */
|
||||
unsigned g_test_ioctl;
|
||||
do_test_fn *g_do_test;
|
||||
|
||||
int osduld_register_test(unsigned ioctl, do_test_fn *do_test)
|
||||
{
|
||||
if (g_test_ioctl)
|
||||
return -EINVAL;
|
||||
|
||||
g_test_ioctl = ioctl;
|
||||
g_do_test = do_test;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(osduld_register_test);
|
||||
|
||||
void osduld_unregister_test(unsigned ioctl)
|
||||
{
|
||||
if (ioctl == g_test_ioctl) {
|
||||
g_test_ioctl = 0;
|
||||
g_do_test = NULL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(osduld_unregister_test);
|
||||
|
||||
static do_test_fn *_find_ioctl(unsigned cmd)
|
||||
{
|
||||
if (g_test_ioctl == cmd)
|
||||
return g_do_test;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static long osd_uld_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct osd_uld_device *oud = file->private_data;
|
||||
int ret;
|
||||
do_test_fn *do_test;
|
||||
|
||||
do_test = _find_ioctl(cmd);
|
||||
if (do_test)
|
||||
ret = do_test(&oud->od, cmd, arg);
|
||||
else {
|
||||
OSD_ERR("Unknown ioctl %d: osd_uld_device=%p\n", cmd, oud);
|
||||
ret = -ENOIOCTLCMD;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations osd_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = osd_uld_open,
|
||||
.release = osd_uld_release,
|
||||
.unlocked_ioctl = osd_uld_ioctl,
|
||||
};
|
||||
|
||||
struct osd_dev *osduld_path_lookup(const char *path)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct inode *inode;
|
||||
struct cdev *cdev;
|
||||
struct osd_uld_device *uninitialized_var(oud);
|
||||
int error;
|
||||
|
||||
if (!path || !*path) {
|
||||
OSD_ERR("Mount with !path || !*path\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
error = path_lookup(path, LOOKUP_FOLLOW, &nd);
|
||||
if (error) {
|
||||
OSD_ERR("path_lookup of %s faild=>%d\n", path, error);
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
inode = nd.path.dentry->d_inode;
|
||||
error = -EINVAL; /* Not the right device e.g osd_uld_device */
|
||||
if (!S_ISCHR(inode->i_mode)) {
|
||||
OSD_DEBUG("!S_ISCHR()\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
cdev = inode->i_cdev;
|
||||
if (!cdev) {
|
||||
OSD_ERR("Before mounting an OSD Based filesystem\n");
|
||||
OSD_ERR(" user-mode must open+close the %s device\n", path);
|
||||
OSD_ERR(" Example: bash: echo < %s\n", path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* The Magic wand. Is it our char-dev */
|
||||
/* TODO: Support sg devices */
|
||||
if (cdev->owner != THIS_MODULE) {
|
||||
OSD_ERR("Error mounting %s - is not an OSD device\n", path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
oud = container_of(cdev, struct osd_uld_device, cdev);
|
||||
|
||||
__uld_get(oud);
|
||||
error = 0;
|
||||
|
||||
out:
|
||||
path_put(&nd.path);
|
||||
return error ? ERR_PTR(error) : &oud->od;
|
||||
}
|
||||
EXPORT_SYMBOL(osduld_path_lookup);
|
||||
|
||||
void osduld_put_device(struct osd_dev *od)
|
||||
{
|
||||
if (od) {
|
||||
struct osd_uld_device *oud = container_of(od,
|
||||
struct osd_uld_device, od);
|
||||
|
||||
__uld_put(oud);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(osduld_put_device);
|
||||
|
||||
/*
|
||||
* Scsi Device operations
|
||||
*/
|
||||
|
||||
static int __detect_osd(struct osd_uld_device *oud)
|
||||
{
|
||||
struct scsi_device *scsi_device = oud->od.scsi_device;
|
||||
char caps[OSD_CAP_LEN];
|
||||
int error;
|
||||
|
||||
/* sending a test_unit_ready as first command seems to be needed
|
||||
* by some targets
|
||||
*/
|
||||
OSD_DEBUG("start scsi_test_unit_ready %p %p %p\n",
|
||||
oud, scsi_device, scsi_device->request_queue);
|
||||
error = scsi_test_unit_ready(scsi_device, 10*HZ, 5, NULL);
|
||||
if (error)
|
||||
OSD_ERR("warning: scsi_test_unit_ready failed\n");
|
||||
|
||||
osd_sec_init_nosec_doall_caps(caps, &osd_root_object, false, true);
|
||||
if (osd_auto_detect_ver(&oud->od, caps))
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct class *osd_sysfs_class;
|
||||
static DEFINE_IDA(osd_minor_ida);
|
||||
|
||||
static int osd_probe(struct device *dev)
|
||||
{
|
||||
struct scsi_device *scsi_device = to_scsi_device(dev);
|
||||
struct gendisk *disk;
|
||||
struct osd_uld_device *oud;
|
||||
int minor;
|
||||
int error;
|
||||
|
||||
if (scsi_device->type != TYPE_OSD)
|
||||
return -ENODEV;
|
||||
|
||||
do {
|
||||
if (!ida_pre_get(&osd_minor_ida, GFP_KERNEL))
|
||||
return -ENODEV;
|
||||
|
||||
error = ida_get_new(&osd_minor_ida, &minor);
|
||||
} while (error == -EAGAIN);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
if (minor >= SCSI_OSD_MAX_MINOR) {
|
||||
error = -EBUSY;
|
||||
goto err_retract_minor;
|
||||
}
|
||||
|
||||
error = -ENOMEM;
|
||||
oud = kzalloc(sizeof(*oud), GFP_KERNEL);
|
||||
if (NULL == oud)
|
||||
goto err_retract_minor;
|
||||
|
||||
kref_init(&oud->kref);
|
||||
dev_set_drvdata(dev, oud);
|
||||
oud->minor = minor;
|
||||
|
||||
/* allocate a disk and set it up */
|
||||
/* FIXME: do we need this since sg has already done that */
|
||||
disk = alloc_disk(1);
|
||||
if (!disk) {
|
||||
OSD_ERR("alloc_disk failed\n");
|
||||
goto err_free_osd;
|
||||
}
|
||||
disk->major = SCSI_OSD_MAJOR;
|
||||
disk->first_minor = oud->minor;
|
||||
sprintf(disk->disk_name, "osd%d", oud->minor);
|
||||
oud->disk = disk;
|
||||
|
||||
/* hold one more reference to the scsi_device that will get released
|
||||
* in __release, in case a logout is happening while fs is mounted
|
||||
*/
|
||||
scsi_device_get(scsi_device);
|
||||
osd_dev_init(&oud->od, scsi_device);
|
||||
|
||||
/* Detect the OSD Version */
|
||||
error = __detect_osd(oud);
|
||||
if (error) {
|
||||
OSD_ERR("osd detection failed, non-compatible OSD device\n");
|
||||
goto err_put_disk;
|
||||
}
|
||||
|
||||
/* init the char-device for communication with user-mode */
|
||||
cdev_init(&oud->cdev, &osd_fops);
|
||||
oud->cdev.owner = THIS_MODULE;
|
||||
error = cdev_add(&oud->cdev,
|
||||
MKDEV(SCSI_OSD_MAJOR, oud->minor), 1);
|
||||
if (error) {
|
||||
OSD_ERR("cdev_add failed\n");
|
||||
goto err_put_disk;
|
||||
}
|
||||
kobject_get(&oud->cdev.kobj); /* 2nd ref see osd_remove() */
|
||||
|
||||
/* class_member */
|
||||
oud->class_member = device_create(osd_sysfs_class, dev,
|
||||
MKDEV(SCSI_OSD_MAJOR, oud->minor), "%s", disk->disk_name);
|
||||
if (IS_ERR(oud->class_member)) {
|
||||
OSD_ERR("class_device_create failed\n");
|
||||
error = PTR_ERR(oud->class_member);
|
||||
goto err_put_cdev;
|
||||
}
|
||||
|
||||
dev_set_drvdata(oud->class_member, oud);
|
||||
error = sysfs_create_link(&scsi_device->sdev_gendev.kobj,
|
||||
&oud->class_member->kobj, osd_symlink);
|
||||
if (error)
|
||||
OSD_ERR("warning: unable to make symlink\n");
|
||||
|
||||
OSD_INFO("osd_probe %s\n", disk->disk_name);
|
||||
return 0;
|
||||
|
||||
err_put_cdev:
|
||||
cdev_del(&oud->cdev);
|
||||
err_put_disk:
|
||||
scsi_device_put(scsi_device);
|
||||
put_disk(disk);
|
||||
err_free_osd:
|
||||
dev_set_drvdata(dev, NULL);
|
||||
kfree(oud);
|
||||
err_retract_minor:
|
||||
ida_remove(&osd_minor_ida, minor);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int osd_remove(struct device *dev)
|
||||
{
|
||||
struct scsi_device *scsi_device = to_scsi_device(dev);
|
||||
struct osd_uld_device *oud = dev_get_drvdata(dev);
|
||||
|
||||
if (!oud || (oud->od.scsi_device != scsi_device)) {
|
||||
OSD_ERR("Half cooked osd-device %p,%p || %p!=%p",
|
||||
dev, oud, oud ? oud->od.scsi_device : NULL,
|
||||
scsi_device);
|
||||
}
|
||||
|
||||
sysfs_remove_link(&oud->od.scsi_device->sdev_gendev.kobj, osd_symlink);
|
||||
|
||||
if (oud->class_member)
|
||||
device_destroy(osd_sysfs_class,
|
||||
MKDEV(SCSI_OSD_MAJOR, oud->minor));
|
||||
|
||||
/* We have 2 references to the cdev. One is released here
|
||||
* and also takes down the /dev/osdX mapping. The second
|
||||
* Will be released in __remove() after all users have released
|
||||
* the osd_uld_device.
|
||||
*/
|
||||
if (oud->cdev.owner)
|
||||
cdev_del(&oud->cdev);
|
||||
|
||||
__uld_put(oud);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __remove(struct kref *kref)
|
||||
{
|
||||
struct osd_uld_device *oud = container_of(kref,
|
||||
struct osd_uld_device, kref);
|
||||
struct scsi_device *scsi_device = oud->od.scsi_device;
|
||||
|
||||
/* now let delete the char_dev */
|
||||
kobject_put(&oud->cdev.kobj);
|
||||
|
||||
osd_dev_fini(&oud->od);
|
||||
scsi_device_put(scsi_device);
|
||||
|
||||
OSD_INFO("osd_remove %s\n",
|
||||
oud->disk ? oud->disk->disk_name : NULL);
|
||||
|
||||
if (oud->disk)
|
||||
put_disk(oud->disk);
|
||||
|
||||
ida_remove(&osd_minor_ida, oud->minor);
|
||||
kfree(oud);
|
||||
}
|
||||
|
||||
static void __uld_get(struct osd_uld_device *oud)
|
||||
{
|
||||
kref_get(&oud->kref);
|
||||
}
|
||||
|
||||
static void __uld_put(struct osd_uld_device *oud)
|
||||
{
|
||||
kref_put(&oud->kref, __remove);
|
||||
}
|
||||
|
||||
/*
|
||||
* Global driver and scsi registration
|
||||
*/
|
||||
|
||||
static struct scsi_driver osd_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.gendrv = {
|
||||
.name = osd_name,
|
||||
.probe = osd_probe,
|
||||
.remove = osd_remove,
|
||||
}
|
||||
};
|
||||
|
||||
static int __init osd_uld_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
osd_sysfs_class = class_create(THIS_MODULE, osd_symlink);
|
||||
if (IS_ERR(osd_sysfs_class)) {
|
||||
OSD_ERR("Unable to register sysfs class => %ld\n",
|
||||
PTR_ERR(osd_sysfs_class));
|
||||
return PTR_ERR(osd_sysfs_class);
|
||||
}
|
||||
|
||||
err = register_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0),
|
||||
SCSI_OSD_MAX_MINOR, osd_name);
|
||||
if (err) {
|
||||
OSD_ERR("Unable to register major %d for osd ULD => %d\n",
|
||||
SCSI_OSD_MAJOR, err);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
err = scsi_register_driver(&osd_driver.gendrv);
|
||||
if (err) {
|
||||
OSD_ERR("scsi_register_driver failed => %d\n", err);
|
||||
goto err_out_chrdev;
|
||||
}
|
||||
|
||||
OSD_INFO("LOADED %s\n", osd_version_string);
|
||||
return 0;
|
||||
|
||||
err_out_chrdev:
|
||||
unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR);
|
||||
err_out:
|
||||
class_destroy(osd_sysfs_class);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit osd_uld_exit(void)
|
||||
{
|
||||
scsi_unregister_driver(&osd_driver.gendrv);
|
||||
unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR);
|
||||
class_destroy(osd_sysfs_class);
|
||||
OSD_INFO("UNLOADED %s\n", osd_version_string);
|
||||
}
|
||||
|
||||
module_init(osd_uld_init);
|
||||
module_exit(osd_uld_exit);
|
@ -280,8 +280,8 @@ static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt)
|
||||
static int notyetprinted = 1;
|
||||
|
||||
printk(KERN_WARNING
|
||||
"%s:W: Warning %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
|
||||
name, result, suggestion(result), driver_byte(result) & DRIVER_MASK,
|
||||
"%s:W: Warning %x (driver bt 0x%x, host bt 0x%x).\n",
|
||||
name, result, driver_byte(result),
|
||||
host_byte(result));
|
||||
if (notyetprinted) {
|
||||
notyetprinted = 0;
|
||||
@ -317,18 +317,25 @@ static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt)
|
||||
|
||||
|
||||
/* Wakeup from interrupt */
|
||||
static void osst_sleep_done(void *data, char *sense, int result, int resid)
|
||||
static void osst_end_async(struct request *req, int update)
|
||||
{
|
||||
struct osst_request *SRpnt = data;
|
||||
struct osst_request *SRpnt = req->end_io_data;
|
||||
struct osst_tape *STp = SRpnt->stp;
|
||||
struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
|
||||
|
||||
memcpy(SRpnt->sense, sense, SCSI_SENSE_BUFFERSIZE);
|
||||
STp->buffer->cmdstat.midlevel_result = SRpnt->result = result;
|
||||
STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors;
|
||||
#if DEBUG
|
||||
STp->write_pending = 0;
|
||||
#endif
|
||||
if (SRpnt->waiting)
|
||||
complete(SRpnt->waiting);
|
||||
|
||||
if (SRpnt->bio) {
|
||||
kfree(mdata->pages);
|
||||
blk_rq_unmap_user(SRpnt->bio);
|
||||
}
|
||||
|
||||
__blk_put_request(req->q, req);
|
||||
}
|
||||
|
||||
/* osst_request memory management */
|
||||
@ -342,6 +349,74 @@ static void osst_release_request(struct osst_request *streq)
|
||||
kfree(streq);
|
||||
}
|
||||
|
||||
static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd,
|
||||
int cmd_len, int data_direction, void *buffer, unsigned bufflen,
|
||||
int use_sg, int timeout, int retries)
|
||||
{
|
||||
struct request *req;
|
||||
struct page **pages = NULL;
|
||||
struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
|
||||
|
||||
int err = 0;
|
||||
int write = (data_direction == DMA_TO_DEVICE);
|
||||
|
||||
req = blk_get_request(SRpnt->stp->device->request_queue, write, GFP_KERNEL);
|
||||
if (!req)
|
||||
return DRIVER_ERROR << 24;
|
||||
|
||||
req->cmd_type = REQ_TYPE_BLOCK_PC;
|
||||
req->cmd_flags |= REQ_QUIET;
|
||||
|
||||
SRpnt->bio = NULL;
|
||||
|
||||
if (use_sg) {
|
||||
struct scatterlist *sg, *sgl = (struct scatterlist *)buffer;
|
||||
int i;
|
||||
|
||||
pages = kzalloc(use_sg * sizeof(struct page *), GFP_KERNEL);
|
||||
if (!pages)
|
||||
goto free_req;
|
||||
|
||||
for_each_sg(sgl, sg, use_sg, i)
|
||||
pages[i] = sg_page(sg);
|
||||
|
||||
mdata->null_mapped = 1;
|
||||
|
||||
mdata->page_order = get_order(sgl[0].length);
|
||||
mdata->nr_entries =
|
||||
DIV_ROUND_UP(bufflen, PAGE_SIZE << mdata->page_order);
|
||||
mdata->offset = 0;
|
||||
|
||||
err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, GFP_KERNEL);
|
||||
if (err) {
|
||||
kfree(pages);
|
||||
goto free_req;
|
||||
}
|
||||
SRpnt->bio = req->bio;
|
||||
mdata->pages = pages;
|
||||
|
||||
} else if (bufflen) {
|
||||
err = blk_rq_map_kern(req->q, req, buffer, bufflen, GFP_KERNEL);
|
||||
if (err)
|
||||
goto free_req;
|
||||
}
|
||||
|
||||
req->cmd_len = cmd_len;
|
||||
memset(req->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
|
||||
memcpy(req->cmd, cmd, req->cmd_len);
|
||||
req->sense = SRpnt->sense;
|
||||
req->sense_len = 0;
|
||||
req->timeout = timeout;
|
||||
req->retries = retries;
|
||||
req->end_io_data = SRpnt;
|
||||
|
||||
blk_execute_rq_nowait(req->q, NULL, req, 1, osst_end_async);
|
||||
return 0;
|
||||
free_req:
|
||||
blk_put_request(req);
|
||||
return DRIVER_ERROR << 24;
|
||||
}
|
||||
|
||||
/* Do the scsi command. Waits until command performed if do_wait is true.
|
||||
Otherwise osst_write_behind_check() is used to check that the command
|
||||
has finished. */
|
||||
@ -403,8 +478,8 @@ static struct osst_request * osst_do_scsi(struct osst_request *SRpnt, struct oss
|
||||
STp->buffer->cmdstat.have_sense = 0;
|
||||
STp->buffer->syscall_result = 0;
|
||||
|
||||
if (scsi_execute_async(STp->device, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes,
|
||||
use_sg, timeout, retries, SRpnt, osst_sleep_done, GFP_KERNEL))
|
||||
if (osst_execute(SRpnt, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes,
|
||||
use_sg, timeout, retries))
|
||||
/* could not allocate the buffer or request was too large */
|
||||
(STp->buffer)->syscall_result = (-EBUSY);
|
||||
else if (do_wait) {
|
||||
@ -5286,11 +5361,6 @@ static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma)
|
||||
struct page *page = alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order);
|
||||
STbuffer->sg[segs].offset = 0;
|
||||
if (page == NULL) {
|
||||
if (OS_FRAME_SIZE - got <= (max_segs - segs) * b_size / 2 && order) {
|
||||
b_size /= 2; /* Large enough for the rest of the buffers */
|
||||
order--;
|
||||
continue;
|
||||
}
|
||||
printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n",
|
||||
OS_FRAME_SIZE);
|
||||
#if DEBUG
|
||||
|
@ -520,6 +520,7 @@ struct osst_buffer {
|
||||
int syscall_result;
|
||||
struct osst_request *last_SRpnt;
|
||||
struct st_cmdstatus cmdstat;
|
||||
struct rq_map_data map_data;
|
||||
unsigned char *b_data;
|
||||
os_aux_t *aux; /* onstream AUX structure at end of each block */
|
||||
unsigned short use_sg; /* zero or number of s/g segments for this adapter */
|
||||
@ -634,6 +635,7 @@ struct osst_request {
|
||||
int result;
|
||||
struct osst_tape *stp;
|
||||
struct completion *waiting;
|
||||
struct bio *bio;
|
||||
};
|
||||
|
||||
/* Values of write_type */
|
||||
|
@ -966,6 +966,110 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth)
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_track_queue_full);
|
||||
|
||||
/**
|
||||
* scsi_vpd_inquiry - Request a device provide us with a VPD page
|
||||
* @sdev: The device to ask
|
||||
* @buffer: Where to put the result
|
||||
* @page: Which Vital Product Data to return
|
||||
* @len: The length of the buffer
|
||||
*
|
||||
* This is an internal helper function. You probably want to use
|
||||
* scsi_get_vpd_page instead.
|
||||
*
|
||||
* Returns 0 on success or a negative error number.
|
||||
*/
|
||||
static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
|
||||
u8 page, unsigned len)
|
||||
{
|
||||
int result;
|
||||
unsigned char cmd[16];
|
||||
|
||||
cmd[0] = INQUIRY;
|
||||
cmd[1] = 1; /* EVPD */
|
||||
cmd[2] = page;
|
||||
cmd[3] = len >> 8;
|
||||
cmd[4] = len & 0xff;
|
||||
cmd[5] = 0; /* Control byte */
|
||||
|
||||
/*
|
||||
* I'm not convinced we need to try quite this hard to get VPD, but
|
||||
* all the existing users tried this hard.
|
||||
*/
|
||||
result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer,
|
||||
len + 4, NULL, 30 * HZ, 3, NULL);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
/* Sanity check that we got the page back that we asked for */
|
||||
if (buffer[1] != page)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* scsi_get_vpd_page - Get Vital Product Data from a SCSI device
|
||||
* @sdev: The device to ask
|
||||
* @page: Which Vital Product Data to return
|
||||
*
|
||||
* SCSI devices may optionally supply Vital Product Data. Each 'page'
|
||||
* of VPD is defined in the appropriate SCSI document (eg SPC, SBC).
|
||||
* If the device supports this VPD page, this routine returns a pointer
|
||||
* to a buffer containing the data from that page. The caller is
|
||||
* responsible for calling kfree() on this pointer when it is no longer
|
||||
* needed. If we cannot retrieve the VPD page this routine returns %NULL.
|
||||
*/
|
||||
unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page)
|
||||
{
|
||||
int i, result;
|
||||
unsigned int len;
|
||||
unsigned char *buf = kmalloc(259, GFP_KERNEL);
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
/* Ask for all the pages supported by this device */
|
||||
result = scsi_vpd_inquiry(sdev, buf, 0, 255);
|
||||
if (result)
|
||||
goto fail;
|
||||
|
||||
/* If the user actually wanted this page, we can skip the rest */
|
||||
if (page == 0)
|
||||
return buf;
|
||||
|
||||
for (i = 0; i < buf[3]; i++)
|
||||
if (buf[i + 4] == page)
|
||||
goto found;
|
||||
/* The device claims it doesn't support the requested page */
|
||||
goto fail;
|
||||
|
||||
found:
|
||||
result = scsi_vpd_inquiry(sdev, buf, page, 255);
|
||||
if (result)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* Some pages are longer than 255 bytes. The actual length of
|
||||
* the page is returned in the header.
|
||||
*/
|
||||
len = (buf[2] << 8) | buf[3];
|
||||
if (len <= 255)
|
||||
return buf;
|
||||
|
||||
kfree(buf);
|
||||
buf = kmalloc(len + 4, GFP_KERNEL);
|
||||
result = scsi_vpd_inquiry(sdev, buf, page, len);
|
||||
if (result)
|
||||
goto fail;
|
||||
|
||||
return buf;
|
||||
|
||||
fail:
|
||||
kfree(buf);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_get_vpd_page);
|
||||
|
||||
/**
|
||||
* scsi_device_get - get an additional reference to a scsi_device
|
||||
* @sdev: device to get a reference to
|
||||
|
@ -40,6 +40,9 @@
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/crc-t10dif.h>
|
||||
|
||||
#include <net/checksum.h>
|
||||
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
@ -48,8 +51,7 @@
|
||||
#include <scsi/scsicam.h>
|
||||
#include <scsi/scsi_eh.h>
|
||||
|
||||
#include <linux/stat.h>
|
||||
|
||||
#include "sd.h"
|
||||
#include "scsi_logging.h"
|
||||
|
||||
#define SCSI_DEBUG_VERSION "1.81"
|
||||
@ -95,6 +97,10 @@ static const char * scsi_debug_version_date = "20070104";
|
||||
#define DEF_FAKE_RW 0
|
||||
#define DEF_VPD_USE_HOSTNO 1
|
||||
#define DEF_SECTOR_SIZE 512
|
||||
#define DEF_DIX 0
|
||||
#define DEF_DIF 0
|
||||
#define DEF_GUARD 0
|
||||
#define DEF_ATO 1
|
||||
|
||||
/* bit mask values for scsi_debug_opts */
|
||||
#define SCSI_DEBUG_OPT_NOISE 1
|
||||
@ -102,6 +108,8 @@ static const char * scsi_debug_version_date = "20070104";
|
||||
#define SCSI_DEBUG_OPT_TIMEOUT 4
|
||||
#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
|
||||
#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
|
||||
#define SCSI_DEBUG_OPT_DIF_ERR 32
|
||||
#define SCSI_DEBUG_OPT_DIX_ERR 64
|
||||
/* When "every_nth" > 0 then modulo "every_nth" commands:
|
||||
* - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
|
||||
* - a RECOVERED_ERROR is simulated on successful read and write
|
||||
@ -144,6 +152,10 @@ static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
|
||||
static int scsi_debug_fake_rw = DEF_FAKE_RW;
|
||||
static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
|
||||
static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
|
||||
static int scsi_debug_dix = DEF_DIX;
|
||||
static int scsi_debug_dif = DEF_DIF;
|
||||
static int scsi_debug_guard = DEF_GUARD;
|
||||
static int scsi_debug_ato = DEF_ATO;
|
||||
|
||||
static int scsi_debug_cmnd_count = 0;
|
||||
|
||||
@ -204,11 +216,15 @@ struct sdebug_queued_cmd {
|
||||
static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
|
||||
|
||||
static unsigned char * fake_storep; /* ramdisk storage */
|
||||
static unsigned char *dif_storep; /* protection info */
|
||||
|
||||
static int num_aborts = 0;
|
||||
static int num_dev_resets = 0;
|
||||
static int num_bus_resets = 0;
|
||||
static int num_host_resets = 0;
|
||||
static int dix_writes;
|
||||
static int dix_reads;
|
||||
static int dif_errors;
|
||||
|
||||
static DEFINE_SPINLOCK(queued_arr_lock);
|
||||
static DEFINE_RWLOCK(atomic_rw);
|
||||
@ -217,6 +233,11 @@ static char sdebug_proc_name[] = "scsi_debug";
|
||||
|
||||
static struct bus_type pseudo_lld_bus;
|
||||
|
||||
static inline sector_t dif_offset(sector_t sector)
|
||||
{
|
||||
return sector << 3;
|
||||
}
|
||||
|
||||
static struct device_driver sdebug_driverfs_driver = {
|
||||
.name = sdebug_proc_name,
|
||||
.bus = &pseudo_lld_bus,
|
||||
@ -225,6 +246,9 @@ static struct device_driver sdebug_driverfs_driver = {
|
||||
static const int check_condition_result =
|
||||
(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
|
||||
|
||||
static const int illegal_condition_result =
|
||||
(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
|
||||
|
||||
static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
|
||||
0, 0, 0x2, 0x4b};
|
||||
static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
|
||||
@ -726,7 +750,12 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
|
||||
} else if (0x86 == cmd[2]) { /* extended inquiry */
|
||||
arr[1] = cmd[2]; /*sanity */
|
||||
arr[3] = 0x3c; /* number of following entries */
|
||||
arr[4] = 0x0; /* no protection stuff */
|
||||
if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
|
||||
arr[4] = 0x4; /* SPT: GRD_CHK:1 */
|
||||
else if (scsi_debug_dif)
|
||||
arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
|
||||
else
|
||||
arr[4] = 0x0; /* no protection stuff */
|
||||
arr[5] = 0x7; /* head of q, ordered + simple q's */
|
||||
} else if (0x87 == cmd[2]) { /* mode page policy */
|
||||
arr[1] = cmd[2]; /*sanity */
|
||||
@ -767,6 +796,7 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
|
||||
arr[2] = scsi_debug_scsi_level;
|
||||
arr[3] = 2; /* response_data_format==2 */
|
||||
arr[4] = SDEBUG_LONG_INQ_SZ - 5;
|
||||
arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
|
||||
if (0 == scsi_debug_vpd_use_hostno)
|
||||
arr[5] = 0x10; /* claim: implicit TGPS */
|
||||
arr[6] = 0x10; /* claim: MultiP */
|
||||
@ -915,6 +945,12 @@ static int resp_readcap16(struct scsi_cmnd * scp,
|
||||
arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
|
||||
arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
|
||||
arr[11] = scsi_debug_sector_size & 0xff;
|
||||
|
||||
if (scsi_debug_dif) {
|
||||
arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
|
||||
arr[12] |= 1; /* PROT_EN */
|
||||
}
|
||||
|
||||
return fill_from_dev_buffer(scp, arr,
|
||||
min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
|
||||
}
|
||||
@ -1066,6 +1102,10 @@ static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
|
||||
ctrl_m_pg[2] |= 0x4;
|
||||
else
|
||||
ctrl_m_pg[2] &= ~0x4;
|
||||
|
||||
if (scsi_debug_ato)
|
||||
ctrl_m_pg[5] |= 0x80; /* ATO=1 */
|
||||
|
||||
memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
|
||||
if (1 == pcontrol)
|
||||
memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
|
||||
@ -1536,6 +1576,87 @@ static int do_device_access(struct scsi_cmnd *scmd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
|
||||
unsigned int sectors)
|
||||
{
|
||||
unsigned int i, resid;
|
||||
struct scatterlist *psgl;
|
||||
struct sd_dif_tuple *sdt;
|
||||
sector_t sector;
|
||||
sector_t tmp_sec = start_sec;
|
||||
void *paddr;
|
||||
|
||||
start_sec = do_div(tmp_sec, sdebug_store_sectors);
|
||||
|
||||
sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec));
|
||||
|
||||
for (i = 0 ; i < sectors ; i++) {
|
||||
u16 csum;
|
||||
|
||||
if (sdt[i].app_tag == 0xffff)
|
||||
continue;
|
||||
|
||||
sector = start_sec + i;
|
||||
|
||||
switch (scsi_debug_guard) {
|
||||
case 1:
|
||||
csum = ip_compute_csum(fake_storep +
|
||||
sector * scsi_debug_sector_size,
|
||||
scsi_debug_sector_size);
|
||||
break;
|
||||
case 0:
|
||||
csum = crc_t10dif(fake_storep +
|
||||
sector * scsi_debug_sector_size,
|
||||
scsi_debug_sector_size);
|
||||
csum = cpu_to_be16(csum);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (sdt[i].guard_tag != csum) {
|
||||
printk(KERN_ERR "%s: GUARD check failed on sector %lu" \
|
||||
" rcvd 0x%04x, data 0x%04x\n", __func__,
|
||||
(unsigned long)sector,
|
||||
be16_to_cpu(sdt[i].guard_tag),
|
||||
be16_to_cpu(csum));
|
||||
dif_errors++;
|
||||
return 0x01;
|
||||
}
|
||||
|
||||
if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION &&
|
||||
be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {
|
||||
printk(KERN_ERR "%s: REF check failed on sector %lu\n",
|
||||
__func__, (unsigned long)sector);
|
||||
dif_errors++;
|
||||
return 0x03;
|
||||
}
|
||||
}
|
||||
|
||||
resid = sectors * 8; /* Bytes of protection data to copy into sgl */
|
||||
sector = start_sec;
|
||||
|
||||
scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
|
||||
int len = min(psgl->length, resid);
|
||||
|
||||
paddr = kmap_atomic(sg_page(psgl), KM_IRQ0) + psgl->offset;
|
||||
memcpy(paddr, dif_storep + dif_offset(sector), len);
|
||||
|
||||
sector += len >> 3;
|
||||
if (sector >= sdebug_store_sectors) {
|
||||
/* Force wrap */
|
||||
tmp_sec = sector;
|
||||
sector = do_div(tmp_sec, sdebug_store_sectors);
|
||||
}
|
||||
resid -= len;
|
||||
kunmap_atomic(paddr, KM_IRQ0);
|
||||
}
|
||||
|
||||
dix_reads++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
|
||||
unsigned int num, struct sdebug_dev_info *devip)
|
||||
{
|
||||
@ -1563,12 +1684,162 @@ static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
|
||||
}
|
||||
return check_condition_result;
|
||||
}
|
||||
|
||||
/* DIX + T10 DIF */
|
||||
if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
|
||||
int prot_ret = prot_verify_read(SCpnt, lba, num);
|
||||
|
||||
if (prot_ret) {
|
||||
mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
|
||||
return illegal_condition_result;
|
||||
}
|
||||
}
|
||||
|
||||
read_lock_irqsave(&atomic_rw, iflags);
|
||||
ret = do_device_access(SCpnt, devip, lba, num, 0);
|
||||
read_unlock_irqrestore(&atomic_rw, iflags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dump_sector(unsigned char *buf, int len)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
printk(KERN_ERR ">>> Sector Dump <<<\n");
|
||||
|
||||
for (i = 0 ; i < len ; i += 16) {
|
||||
printk(KERN_ERR "%04d: ", i);
|
||||
|
||||
for (j = 0 ; j < 16 ; j++) {
|
||||
unsigned char c = buf[i+j];
|
||||
if (c >= 0x20 && c < 0x7e)
|
||||
printk(" %c ", buf[i+j]);
|
||||
else
|
||||
printk("%02x ", buf[i+j]);
|
||||
}
|
||||
|
||||
printk("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
|
||||
unsigned int sectors)
|
||||
{
|
||||
int i, j, ret;
|
||||
struct sd_dif_tuple *sdt;
|
||||
struct scatterlist *dsgl = scsi_sglist(SCpnt);
|
||||
struct scatterlist *psgl = scsi_prot_sglist(SCpnt);
|
||||
void *daddr, *paddr;
|
||||
sector_t tmp_sec = start_sec;
|
||||
sector_t sector;
|
||||
int ppage_offset;
|
||||
unsigned short csum;
|
||||
|
||||
sector = do_div(tmp_sec, sdebug_store_sectors);
|
||||
|
||||
if (((SCpnt->cmnd[1] >> 5) & 7) != 1) {
|
||||
printk(KERN_WARNING "scsi_debug: WRPROTECT != 1\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
BUG_ON(scsi_sg_count(SCpnt) == 0);
|
||||
BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
|
||||
|
||||
paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + psgl->offset;
|
||||
ppage_offset = 0;
|
||||
|
||||
/* For each data page */
|
||||
scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
|
||||
daddr = kmap_atomic(sg_page(dsgl), KM_IRQ0) + dsgl->offset;
|
||||
|
||||
/* For each sector-sized chunk in data page */
|
||||
for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) {
|
||||
|
||||
/* If we're at the end of the current
|
||||
* protection page advance to the next one
|
||||
*/
|
||||
if (ppage_offset >= psgl->length) {
|
||||
kunmap_atomic(paddr, KM_IRQ1);
|
||||
psgl = sg_next(psgl);
|
||||
BUG_ON(psgl == NULL);
|
||||
paddr = kmap_atomic(sg_page(psgl), KM_IRQ1)
|
||||
+ psgl->offset;
|
||||
ppage_offset = 0;
|
||||
}
|
||||
|
||||
sdt = paddr + ppage_offset;
|
||||
|
||||
switch (scsi_debug_guard) {
|
||||
case 1:
|
||||
csum = ip_compute_csum(daddr,
|
||||
scsi_debug_sector_size);
|
||||
break;
|
||||
case 0:
|
||||
csum = cpu_to_be16(crc_t10dif(daddr,
|
||||
scsi_debug_sector_size));
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (sdt->guard_tag != csum) {
|
||||
printk(KERN_ERR
|
||||
"%s: GUARD check failed on sector %lu " \
|
||||
"rcvd 0x%04x, calculated 0x%04x\n",
|
||||
__func__, (unsigned long)sector,
|
||||
be16_to_cpu(sdt->guard_tag),
|
||||
be16_to_cpu(csum));
|
||||
ret = 0x01;
|
||||
dump_sector(daddr, scsi_debug_sector_size);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION &&
|
||||
be32_to_cpu(sdt->ref_tag)
|
||||
!= (start_sec & 0xffffffff)) {
|
||||
printk(KERN_ERR
|
||||
"%s: REF check failed on sector %lu\n",
|
||||
__func__, (unsigned long)sector);
|
||||
ret = 0x03;
|
||||
dump_sector(daddr, scsi_debug_sector_size);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Would be great to copy this in bigger
|
||||
* chunks. However, for the sake of
|
||||
* correctness we need to verify each sector
|
||||
* before writing it to "stable" storage
|
||||
*/
|
||||
memcpy(dif_storep + dif_offset(sector), sdt, 8);
|
||||
|
||||
sector++;
|
||||
|
||||
if (sector == sdebug_store_sectors)
|
||||
sector = 0; /* Force wrap */
|
||||
|
||||
start_sec++;
|
||||
daddr += scsi_debug_sector_size;
|
||||
ppage_offset += sizeof(struct sd_dif_tuple);
|
||||
}
|
||||
|
||||
kunmap_atomic(daddr, KM_IRQ0);
|
||||
}
|
||||
|
||||
kunmap_atomic(paddr, KM_IRQ1);
|
||||
|
||||
dix_writes++;
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
dif_errors++;
|
||||
kunmap_atomic(daddr, KM_IRQ0);
|
||||
kunmap_atomic(paddr, KM_IRQ1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
|
||||
unsigned int num, struct sdebug_dev_info *devip)
|
||||
{
|
||||
@ -1579,6 +1850,16 @@ static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* DIX + T10 DIF */
|
||||
if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
|
||||
int prot_ret = prot_verify_write(SCpnt, lba, num);
|
||||
|
||||
if (prot_ret) {
|
||||
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
|
||||
return illegal_condition_result;
|
||||
}
|
||||
}
|
||||
|
||||
write_lock_irqsave(&atomic_rw, iflags);
|
||||
ret = do_device_access(SCpnt, devip, lba, num, 1);
|
||||
write_unlock_irqrestore(&atomic_rw, iflags);
|
||||
@ -2095,6 +2376,10 @@ module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
|
||||
module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
|
||||
S_IRUGO | S_IWUSR);
|
||||
module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
|
||||
module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
|
||||
module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
|
||||
module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
|
||||
module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
|
||||
|
||||
MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
|
||||
MODULE_DESCRIPTION("SCSI debug adapter driver");
|
||||
@ -2117,7 +2402,10 @@ MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
|
||||
MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
|
||||
MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
|
||||
MODULE_PARM_DESC(sector_size, "hardware sector size in bytes (def=512)");
|
||||
|
||||
MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
|
||||
MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
|
||||
MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
|
||||
MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
|
||||
|
||||
static char sdebug_info[256];
|
||||
|
||||
@ -2164,14 +2452,14 @@ static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **sta
|
||||
"delay=%d, max_luns=%d, scsi_level=%d\n"
|
||||
"sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
|
||||
"number of aborts=%d, device_reset=%d, bus_resets=%d, "
|
||||
"host_resets=%d\n",
|
||||
"host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n",
|
||||
SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
|
||||
scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
|
||||
scsi_debug_cmnd_count, scsi_debug_delay,
|
||||
scsi_debug_max_luns, scsi_debug_scsi_level,
|
||||
scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
|
||||
sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
|
||||
num_host_resets);
|
||||
num_host_resets, dix_reads, dix_writes, dif_errors);
|
||||
if (pos < offset) {
|
||||
len = 0;
|
||||
begin = pos;
|
||||
@ -2452,6 +2740,31 @@ static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf)
|
||||
}
|
||||
DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL);
|
||||
|
||||
static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf)
|
||||
{
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
|
||||
}
|
||||
DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL);
|
||||
|
||||
static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf)
|
||||
{
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
|
||||
}
|
||||
DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL);
|
||||
|
||||
static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf)
|
||||
{
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard);
|
||||
}
|
||||
DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL);
|
||||
|
||||
static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf)
|
||||
{
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
|
||||
}
|
||||
DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL);
|
||||
|
||||
|
||||
/* Note: The following function creates attribute files in the
|
||||
/sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
|
||||
files (over those found in the /sys/module/scsi_debug/parameters
|
||||
@ -2478,11 +2791,19 @@ static int do_create_driverfs_files(void)
|
||||
ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
|
||||
ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
|
||||
ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
|
||||
ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix);
|
||||
ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif);
|
||||
ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard);
|
||||
ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void do_remove_driverfs_files(void)
|
||||
{
|
||||
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato);
|
||||
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard);
|
||||
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif);
|
||||
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix);
|
||||
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
|
||||
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
|
||||
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
|
||||
@ -2526,11 +2847,33 @@ static int __init scsi_debug_init(void)
|
||||
case 4096:
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "scsi_debug_init: invalid sector_size %u\n",
|
||||
printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n",
|
||||
scsi_debug_sector_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (scsi_debug_dif) {
|
||||
|
||||
case SD_DIF_TYPE0_PROTECTION:
|
||||
case SD_DIF_TYPE1_PROTECTION:
|
||||
case SD_DIF_TYPE3_PROTECTION:
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "scsi_debug_init: dif must be 0, 1 or 3\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (scsi_debug_guard > 1) {
|
||||
printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (scsi_debug_ato > 1) {
|
||||
printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (scsi_debug_dev_size_mb < 1)
|
||||
scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
|
||||
sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
|
||||
@ -2563,6 +2906,24 @@ static int __init scsi_debug_init(void)
|
||||
if (scsi_debug_num_parts > 0)
|
||||
sdebug_build_parts(fake_storep, sz);
|
||||
|
||||
if (scsi_debug_dif) {
|
||||
int dif_size;
|
||||
|
||||
dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
|
||||
dif_storep = vmalloc(dif_size);
|
||||
|
||||
printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n",
|
||||
dif_size, dif_storep);
|
||||
|
||||
if (dif_storep == NULL) {
|
||||
printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n");
|
||||
ret = -ENOMEM;
|
||||
goto free_vm;
|
||||
}
|
||||
|
||||
memset(dif_storep, 0xff, dif_size);
|
||||
}
|
||||
|
||||
ret = device_register(&pseudo_primary);
|
||||
if (ret < 0) {
|
||||
printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
|
||||
@ -2615,6 +2976,8 @@ static int __init scsi_debug_init(void)
|
||||
dev_unreg:
|
||||
device_unregister(&pseudo_primary);
|
||||
free_vm:
|
||||
if (dif_storep)
|
||||
vfree(dif_storep);
|
||||
vfree(fake_storep);
|
||||
|
||||
return ret;
|
||||
@ -2632,6 +2995,9 @@ static void __exit scsi_debug_exit(void)
|
||||
bus_unregister(&pseudo_lld_bus);
|
||||
device_unregister(&pseudo_primary);
|
||||
|
||||
if (dif_storep)
|
||||
vfree(dif_storep);
|
||||
|
||||
vfree(fake_storep);
|
||||
}
|
||||
|
||||
@ -2732,6 +3098,8 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
|
||||
struct sdebug_dev_info *devip = NULL;
|
||||
int inj_recovered = 0;
|
||||
int inj_transport = 0;
|
||||
int inj_dif = 0;
|
||||
int inj_dix = 0;
|
||||
int delay_override = 0;
|
||||
|
||||
scsi_set_resid(SCpnt, 0);
|
||||
@ -2769,6 +3137,10 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
|
||||
inj_recovered = 1; /* to reads and writes below */
|
||||
else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
|
||||
inj_transport = 1; /* to reads and writes below */
|
||||
else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
|
||||
inj_dif = 1; /* to reads and writes below */
|
||||
else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
|
||||
inj_dix = 1; /* to reads and writes below */
|
||||
}
|
||||
|
||||
if (devip->wlun) {
|
||||
@ -2870,6 +3242,12 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
|
||||
mk_sense_buffer(devip, ABORTED_COMMAND,
|
||||
TRANSPORT_PROBLEM, ACK_NAK_TO);
|
||||
errsts = check_condition_result;
|
||||
} else if (inj_dif && (0 == errsts)) {
|
||||
mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
|
||||
errsts = illegal_condition_result;
|
||||
} else if (inj_dix && (0 == errsts)) {
|
||||
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
|
||||
errsts = illegal_condition_result;
|
||||
}
|
||||
break;
|
||||
case REPORT_LUNS: /* mandatory, ignore unit attention */
|
||||
@ -2894,6 +3272,12 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
|
||||
mk_sense_buffer(devip, RECOVERED_ERROR,
|
||||
THRESHOLD_EXCEEDED, 0);
|
||||
errsts = check_condition_result;
|
||||
} else if (inj_dif && (0 == errsts)) {
|
||||
mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
|
||||
errsts = illegal_condition_result;
|
||||
} else if (inj_dix && (0 == errsts)) {
|
||||
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
|
||||
errsts = illegal_condition_result;
|
||||
}
|
||||
break;
|
||||
case MODE_SENSE:
|
||||
@ -2982,6 +3366,7 @@ static int sdebug_driver_probe(struct device * dev)
|
||||
int error = 0;
|
||||
struct sdebug_host_info *sdbg_host;
|
||||
struct Scsi_Host *hpnt;
|
||||
int host_prot;
|
||||
|
||||
sdbg_host = to_sdebug_host(dev);
|
||||
|
||||
@ -3000,6 +3385,50 @@ static int sdebug_driver_probe(struct device * dev)
|
||||
hpnt->max_id = scsi_debug_num_tgts;
|
||||
hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
|
||||
|
||||
host_prot = 0;
|
||||
|
||||
switch (scsi_debug_dif) {
|
||||
|
||||
case SD_DIF_TYPE1_PROTECTION:
|
||||
host_prot = SHOST_DIF_TYPE1_PROTECTION;
|
||||
if (scsi_debug_dix)
|
||||
host_prot |= SHOST_DIX_TYPE1_PROTECTION;
|
||||
break;
|
||||
|
||||
case SD_DIF_TYPE2_PROTECTION:
|
||||
host_prot = SHOST_DIF_TYPE2_PROTECTION;
|
||||
if (scsi_debug_dix)
|
||||
host_prot |= SHOST_DIX_TYPE2_PROTECTION;
|
||||
break;
|
||||
|
||||
case SD_DIF_TYPE3_PROTECTION:
|
||||
host_prot = SHOST_DIF_TYPE3_PROTECTION;
|
||||
if (scsi_debug_dix)
|
||||
host_prot |= SHOST_DIX_TYPE3_PROTECTION;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (scsi_debug_dix)
|
||||
host_prot |= SHOST_DIX_TYPE0_PROTECTION;
|
||||
break;
|
||||
}
|
||||
|
||||
scsi_host_set_prot(hpnt, host_prot);
|
||||
|
||||
printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
|
||||
(host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
|
||||
(host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
|
||||
(host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
|
||||
(host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
|
||||
(host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
|
||||
(host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
|
||||
(host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
|
||||
|
||||
if (scsi_debug_guard == 1)
|
||||
scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
|
||||
else
|
||||
scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
|
||||
|
||||
error = scsi_add_host(hpnt, &sdbg_host->dev);
|
||||
if (error) {
|
||||
printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
|
||||
|
@ -1441,6 +1441,11 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
|
||||
}
|
||||
}
|
||||
|
||||
static void eh_lock_door_done(struct request *req, int uptodate)
|
||||
{
|
||||
__blk_put_request(req->q, req);
|
||||
}
|
||||
|
||||
/**
|
||||
* scsi_eh_lock_door - Prevent medium removal for the specified device
|
||||
* @sdev: SCSI device to prevent medium removal
|
||||
@ -1463,20 +1468,29 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
|
||||
*/
|
||||
static void scsi_eh_lock_door(struct scsi_device *sdev)
|
||||
{
|
||||
unsigned char cmnd[MAX_COMMAND_SIZE];
|
||||
struct request *req;
|
||||
|
||||
cmnd[0] = ALLOW_MEDIUM_REMOVAL;
|
||||
cmnd[1] = 0;
|
||||
cmnd[2] = 0;
|
||||
cmnd[3] = 0;
|
||||
cmnd[4] = SCSI_REMOVAL_PREVENT;
|
||||
cmnd[5] = 0;
|
||||
req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL);
|
||||
if (!req)
|
||||
return;
|
||||
|
||||
scsi_execute_async(sdev, cmnd, 6, DMA_NONE, NULL, 0, 0, 10 * HZ,
|
||||
5, NULL, NULL, GFP_KERNEL);
|
||||
req->cmd[0] = ALLOW_MEDIUM_REMOVAL;
|
||||
req->cmd[1] = 0;
|
||||
req->cmd[2] = 0;
|
||||
req->cmd[3] = 0;
|
||||
req->cmd[4] = SCSI_REMOVAL_PREVENT;
|
||||
req->cmd[5] = 0;
|
||||
|
||||
req->cmd_len = COMMAND_SIZE(req->cmd[0]);
|
||||
|
||||
req->cmd_type = REQ_TYPE_BLOCK_PC;
|
||||
req->cmd_flags |= REQ_QUIET;
|
||||
req->timeout = 10 * HZ;
|
||||
req->retries = 5;
|
||||
|
||||
blk_execute_rq_nowait(req->q, NULL, req, 1, eh_lock_door_done);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* scsi_restart_operations - restart io operations to the specified host.
|
||||
* @shost: Host we are restarting.
|
||||
|
@ -277,196 +277,6 @@ int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd,
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_execute_req);
|
||||
|
||||
struct scsi_io_context {
|
||||
void *data;
|
||||
void (*done)(void *data, char *sense, int result, int resid);
|
||||
char sense[SCSI_SENSE_BUFFERSIZE];
|
||||
};
|
||||
|
||||
static struct kmem_cache *scsi_io_context_cache;
|
||||
|
||||
static void scsi_end_async(struct request *req, int uptodate)
|
||||
{
|
||||
struct scsi_io_context *sioc = req->end_io_data;
|
||||
|
||||
if (sioc->done)
|
||||
sioc->done(sioc->data, sioc->sense, req->errors, req->data_len);
|
||||
|
||||
kmem_cache_free(scsi_io_context_cache, sioc);
|
||||
__blk_put_request(req->q, req);
|
||||
}
|
||||
|
||||
static int scsi_merge_bio(struct request *rq, struct bio *bio)
|
||||
{
|
||||
struct request_queue *q = rq->q;
|
||||
|
||||
bio->bi_flags &= ~(1 << BIO_SEG_VALID);
|
||||
if (rq_data_dir(rq) == WRITE)
|
||||
bio->bi_rw |= (1 << BIO_RW);
|
||||
blk_queue_bounce(q, &bio);
|
||||
|
||||
return blk_rq_append_bio(q, rq, bio);
|
||||
}
|
||||
|
||||
static void scsi_bi_endio(struct bio *bio, int error)
|
||||
{
|
||||
bio_put(bio);
|
||||
}
|
||||
|
||||
/**
|
||||
* scsi_req_map_sg - map a scatterlist into a request
|
||||
* @rq: request to fill
|
||||
* @sgl: scatterlist
|
||||
* @nsegs: number of elements
|
||||
* @bufflen: len of buffer
|
||||
* @gfp: memory allocation flags
|
||||
*
|
||||
* scsi_req_map_sg maps a scatterlist into a request so that the
|
||||
* request can be sent to the block layer. We do not trust the scatterlist
|
||||
* sent to use, as some ULDs use that struct to only organize the pages.
|
||||
*/
|
||||
static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl,
|
||||
int nsegs, unsigned bufflen, gfp_t gfp)
|
||||
{
|
||||
struct request_queue *q = rq->q;
|
||||
int nr_pages = (bufflen + sgl[0].offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
unsigned int data_len = bufflen, len, bytes, off;
|
||||
struct scatterlist *sg;
|
||||
struct page *page;
|
||||
struct bio *bio = NULL;
|
||||
int i, err, nr_vecs = 0;
|
||||
|
||||
for_each_sg(sgl, sg, nsegs, i) {
|
||||
page = sg_page(sg);
|
||||
off = sg->offset;
|
||||
len = sg->length;
|
||||
|
||||
while (len > 0 && data_len > 0) {
|
||||
/*
|
||||
* sg sends a scatterlist that is larger than
|
||||
* the data_len it wants transferred for certain
|
||||
* IO sizes
|
||||
*/
|
||||
bytes = min_t(unsigned int, len, PAGE_SIZE - off);
|
||||
bytes = min(bytes, data_len);
|
||||
|
||||
if (!bio) {
|
||||
nr_vecs = min_t(int, BIO_MAX_PAGES, nr_pages);
|
||||
nr_pages -= nr_vecs;
|
||||
|
||||
bio = bio_alloc(gfp, nr_vecs);
|
||||
if (!bio) {
|
||||
err = -ENOMEM;
|
||||
goto free_bios;
|
||||
}
|
||||
bio->bi_end_io = scsi_bi_endio;
|
||||
}
|
||||
|
||||
if (bio_add_pc_page(q, bio, page, bytes, off) !=
|
||||
bytes) {
|
||||
bio_put(bio);
|
||||
err = -EINVAL;
|
||||
goto free_bios;
|
||||
}
|
||||
|
||||
if (bio->bi_vcnt >= nr_vecs) {
|
||||
err = scsi_merge_bio(rq, bio);
|
||||
if (err) {
|
||||
bio_endio(bio, 0);
|
||||
goto free_bios;
|
||||
}
|
||||
bio = NULL;
|
||||
}
|
||||
|
||||
page++;
|
||||
len -= bytes;
|
||||
data_len -=bytes;
|
||||
off = 0;
|
||||
}
|
||||
}
|
||||
|
||||
rq->buffer = rq->data = NULL;
|
||||
rq->data_len = bufflen;
|
||||
return 0;
|
||||
|
||||
free_bios:
|
||||
while ((bio = rq->bio) != NULL) {
|
||||
rq->bio = bio->bi_next;
|
||||
/*
|
||||
* call endio instead of bio_put incase it was bounced
|
||||
*/
|
||||
bio_endio(bio, 0);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* scsi_execute_async - insert request
|
||||
* @sdev: scsi device
|
||||
* @cmd: scsi command
|
||||
* @cmd_len: length of scsi cdb
|
||||
* @data_direction: DMA_TO_DEVICE, DMA_FROM_DEVICE, or DMA_NONE
|
||||
* @buffer: data buffer (this can be a kernel buffer or scatterlist)
|
||||
* @bufflen: len of buffer
|
||||
* @use_sg: if buffer is a scatterlist this is the number of elements
|
||||
* @timeout: request timeout in seconds
|
||||
* @retries: number of times to retry request
|
||||
* @privdata: data passed to done()
|
||||
* @done: callback function when done
|
||||
* @gfp: memory allocation flags
|
||||
*/
|
||||
int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
|
||||
int cmd_len, int data_direction, void *buffer, unsigned bufflen,
|
||||
int use_sg, int timeout, int retries, void *privdata,
|
||||
void (*done)(void *, char *, int, int), gfp_t gfp)
|
||||
{
|
||||
struct request *req;
|
||||
struct scsi_io_context *sioc;
|
||||
int err = 0;
|
||||
int write = (data_direction == DMA_TO_DEVICE);
|
||||
|
||||
sioc = kmem_cache_zalloc(scsi_io_context_cache, gfp);
|
||||
if (!sioc)
|
||||
return DRIVER_ERROR << 24;
|
||||
|
||||
req = blk_get_request(sdev->request_queue, write, gfp);
|
||||
if (!req)
|
||||
goto free_sense;
|
||||
req->cmd_type = REQ_TYPE_BLOCK_PC;
|
||||
req->cmd_flags |= REQ_QUIET;
|
||||
|
||||
if (use_sg)
|
||||
err = scsi_req_map_sg(req, buffer, use_sg, bufflen, gfp);
|
||||
else if (bufflen)
|
||||
err = blk_rq_map_kern(req->q, req, buffer, bufflen, gfp);
|
||||
|
||||
if (err)
|
||||
goto free_req;
|
||||
|
||||
req->cmd_len = cmd_len;
|
||||
memset(req->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
|
||||
memcpy(req->cmd, cmd, req->cmd_len);
|
||||
req->sense = sioc->sense;
|
||||
req->sense_len = 0;
|
||||
req->timeout = timeout;
|
||||
req->retries = retries;
|
||||
req->end_io_data = sioc;
|
||||
|
||||
sioc->data = privdata;
|
||||
sioc->done = done;
|
||||
|
||||
blk_execute_rq_nowait(req->q, NULL, req, 1, scsi_end_async);
|
||||
return 0;
|
||||
|
||||
free_req:
|
||||
blk_put_request(req);
|
||||
free_sense:
|
||||
kmem_cache_free(scsi_io_context_cache, sioc);
|
||||
return DRIVER_ERROR << 24;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_execute_async);
|
||||
|
||||
/*
|
||||
* Function: scsi_init_cmd_errh()
|
||||
*
|
||||
@ -1920,20 +1730,12 @@ int __init scsi_init_queue(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
scsi_io_context_cache = kmem_cache_create("scsi_io_context",
|
||||
sizeof(struct scsi_io_context),
|
||||
0, 0, NULL);
|
||||
if (!scsi_io_context_cache) {
|
||||
printk(KERN_ERR "SCSI: can't init scsi io context cache\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
scsi_sdb_cache = kmem_cache_create("scsi_data_buffer",
|
||||
sizeof(struct scsi_data_buffer),
|
||||
0, 0, NULL);
|
||||
if (!scsi_sdb_cache) {
|
||||
printk(KERN_ERR "SCSI: can't init scsi sdb cache\n");
|
||||
goto cleanup_io_context;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < SG_MEMPOOL_NR; i++) {
|
||||
@ -1968,8 +1770,6 @@ int __init scsi_init_queue(void)
|
||||
kmem_cache_destroy(sgp->slab);
|
||||
}
|
||||
kmem_cache_destroy(scsi_sdb_cache);
|
||||
cleanup_io_context:
|
||||
kmem_cache_destroy(scsi_io_context_cache);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -1978,7 +1778,6 @@ void scsi_exit_queue(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
kmem_cache_destroy(scsi_io_context_cache);
|
||||
kmem_cache_destroy(scsi_sdb_cache);
|
||||
|
||||
for (i = 0; i < SG_MEMPOOL_NR; i++) {
|
||||
|
@ -797,6 +797,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
|
||||
case TYPE_ENCLOSURE:
|
||||
case TYPE_COMM:
|
||||
case TYPE_RAID:
|
||||
case TYPE_OSD:
|
||||
sdev->writeable = 1;
|
||||
break;
|
||||
case TYPE_ROM:
|
||||
|
@ -1043,7 +1043,6 @@ EXPORT_SYMBOL(scsi_register_interface);
|
||||
/**
|
||||
* scsi_sysfs_add_host - add scsi host to subsystem
|
||||
* @shost: scsi host struct to add to subsystem
|
||||
* @dev: parent struct device pointer
|
||||
**/
|
||||
int scsi_sysfs_add_host(struct Scsi_Host *shost)
|
||||
{
|
||||
|
@ -95,7 +95,7 @@ static struct {
|
||||
{ FC_PORTTYPE_NPORT, "NPort (fabric via point-to-point)" },
|
||||
{ FC_PORTTYPE_NLPORT, "NLPort (fabric via loop)" },
|
||||
{ FC_PORTTYPE_LPORT, "LPort (private loop)" },
|
||||
{ FC_PORTTYPE_PTP, "Point-To-Point (direct nport connection" },
|
||||
{ FC_PORTTYPE_PTP, "Point-To-Point (direct nport connection)" },
|
||||
{ FC_PORTTYPE_NPIV, "NPIV VPORT" },
|
||||
};
|
||||
fc_enum_name_search(port_type, fc_port_type, fc_port_type_names)
|
||||
|
@ -246,30 +246,13 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
|
||||
memset(ihost, 0, sizeof(*ihost));
|
||||
atomic_set(&ihost->nr_scans, 0);
|
||||
mutex_init(&ihost->mutex);
|
||||
|
||||
snprintf(ihost->scan_workq_name, sizeof(ihost->scan_workq_name),
|
||||
"iscsi_scan_%d", shost->host_no);
|
||||
ihost->scan_workq = create_singlethread_workqueue(
|
||||
ihost->scan_workq_name);
|
||||
if (!ihost->scan_workq)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iscsi_remove_host(struct transport_container *tc, struct device *dev,
|
||||
struct device *cdev)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(dev);
|
||||
struct iscsi_cls_host *ihost = shost->shost_data;
|
||||
|
||||
destroy_workqueue(ihost->scan_workq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
|
||||
"iscsi_host",
|
||||
iscsi_setup_host,
|
||||
iscsi_remove_host,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
static DECLARE_TRANSPORT_CLASS(iscsi_session_class,
|
||||
@ -568,7 +551,7 @@ static void __iscsi_unblock_session(struct work_struct *work)
|
||||
* scanning from userspace).
|
||||
*/
|
||||
if (shost->hostt->scan_finished) {
|
||||
if (queue_work(ihost->scan_workq, &session->scan_work))
|
||||
if (scsi_queue_work(shost, &session->scan_work))
|
||||
atomic_inc(&ihost->nr_scans);
|
||||
}
|
||||
}
|
||||
@ -636,14 +619,6 @@ static void __iscsi_unbind_session(struct work_struct *work)
|
||||
iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION);
|
||||
}
|
||||
|
||||
static int iscsi_unbind_session(struct iscsi_cls_session *session)
|
||||
{
|
||||
struct Scsi_Host *shost = iscsi_session_to_shost(session);
|
||||
struct iscsi_cls_host *ihost = shost->shost_data;
|
||||
|
||||
return queue_work(ihost->scan_workq, &session->unbind_work);
|
||||
}
|
||||
|
||||
struct iscsi_cls_session *
|
||||
iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
|
||||
int dd_size)
|
||||
@ -796,7 +771,6 @@ static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data)
|
||||
void iscsi_remove_session(struct iscsi_cls_session *session)
|
||||
{
|
||||
struct Scsi_Host *shost = iscsi_session_to_shost(session);
|
||||
struct iscsi_cls_host *ihost = shost->shost_data;
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
@ -821,7 +795,7 @@ void iscsi_remove_session(struct iscsi_cls_session *session)
|
||||
|
||||
scsi_target_unblock(&session->dev);
|
||||
/* flush running scans then delete devices */
|
||||
flush_workqueue(ihost->scan_workq);
|
||||
scsi_flush_work(shost);
|
||||
__iscsi_unbind_session(&session->unbind_work);
|
||||
|
||||
/* hw iscsi may not have removed all connections from session */
|
||||
@ -1215,14 +1189,15 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_endpoint *ep,
|
||||
{
|
||||
struct iscsi_transport *transport = priv->iscsi_transport;
|
||||
struct iscsi_cls_session *session;
|
||||
uint32_t host_no;
|
||||
struct Scsi_Host *shost;
|
||||
|
||||
session = transport->create_session(ep, cmds_max, queue_depth,
|
||||
initial_cmdsn, &host_no);
|
||||
initial_cmdsn);
|
||||
if (!session)
|
||||
return -ENOMEM;
|
||||
|
||||
ev->r.c_session_ret.host_no = host_no;
|
||||
shost = iscsi_session_to_shost(session);
|
||||
ev->r.c_session_ret.host_no = shost->host_no;
|
||||
ev->r.c_session_ret.sid = session->sid;
|
||||
return 0;
|
||||
}
|
||||
@ -1439,7 +1414,8 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
case ISCSI_UEVENT_UNBIND_SESSION:
|
||||
session = iscsi_session_lookup(ev->u.d_session.sid);
|
||||
if (session)
|
||||
iscsi_unbind_session(session);
|
||||
scsi_queue_work(iscsi_session_to_shost(session),
|
||||
&session->unbind_work);
|
||||
else
|
||||
err = -EINVAL;
|
||||
break;
|
||||
@ -1801,8 +1777,7 @@ iscsi_register_transport(struct iscsi_transport *tt)
|
||||
priv->daemon_pid = -1;
|
||||
priv->iscsi_transport = tt;
|
||||
priv->t.user_scan = iscsi_user_scan;
|
||||
if (!(tt->caps & CAP_DATA_PATH_OFFLOAD))
|
||||
priv->t.create_work_queue = 1;
|
||||
priv->t.create_work_queue = 1;
|
||||
|
||||
priv->dev.class = &iscsi_transport_class;
|
||||
dev_set_name(&priv->dev, "%s", tt->name);
|
||||
|
@ -1273,42 +1273,126 @@ void sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer)
|
||||
sdkp->capacity = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* read disk capacity
|
||||
*/
|
||||
static void
|
||||
sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer)
|
||||
static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp,
|
||||
struct scsi_sense_hdr *sshdr, int sense_valid,
|
||||
int the_result)
|
||||
{
|
||||
sd_print_result(sdkp, the_result);
|
||||
if (driver_byte(the_result) & DRIVER_SENSE)
|
||||
sd_print_sense_hdr(sdkp, sshdr);
|
||||
else
|
||||
sd_printk(KERN_NOTICE, sdkp, "Sense not available.\n");
|
||||
|
||||
/*
|
||||
* Set dirty bit for removable devices if not ready -
|
||||
* sometimes drives will not report this properly.
|
||||
*/
|
||||
if (sdp->removable &&
|
||||
sense_valid && sshdr->sense_key == NOT_READY)
|
||||
sdp->changed = 1;
|
||||
|
||||
/*
|
||||
* We used to set media_present to 0 here to indicate no media
|
||||
* in the drive, but some drives fail read capacity even with
|
||||
* media present, so we can't do that.
|
||||
*/
|
||||
sdkp->capacity = 0; /* unknown mapped to zero - as usual */
|
||||
}
|
||||
|
||||
#define RC16_LEN 32
|
||||
#if RC16_LEN > SD_BUF_SIZE
|
||||
#error RC16_LEN must not be more than SD_BUF_SIZE
|
||||
#endif
|
||||
|
||||
static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
|
||||
unsigned char *buffer)
|
||||
{
|
||||
unsigned char cmd[16];
|
||||
int the_result, retries;
|
||||
int sector_size = 0;
|
||||
/* Force READ CAPACITY(16) when PROTECT=1 */
|
||||
int longrc = scsi_device_protection(sdkp->device) ? 1 : 0;
|
||||
struct scsi_sense_hdr sshdr;
|
||||
int sense_valid = 0;
|
||||
struct scsi_device *sdp = sdkp->device;
|
||||
int the_result;
|
||||
int retries = 3;
|
||||
unsigned long long lba;
|
||||
unsigned sector_size;
|
||||
|
||||
repeat:
|
||||
retries = 3;
|
||||
do {
|
||||
if (longrc) {
|
||||
memset((void *) cmd, 0, 16);
|
||||
cmd[0] = SERVICE_ACTION_IN;
|
||||
cmd[1] = SAI_READ_CAPACITY_16;
|
||||
cmd[13] = 13;
|
||||
memset((void *) buffer, 0, 13);
|
||||
} else {
|
||||
cmd[0] = READ_CAPACITY;
|
||||
memset((void *) &cmd[1], 0, 9);
|
||||
memset((void *) buffer, 0, 8);
|
||||
}
|
||||
|
||||
memset(cmd, 0, 16);
|
||||
cmd[0] = SERVICE_ACTION_IN;
|
||||
cmd[1] = SAI_READ_CAPACITY_16;
|
||||
cmd[13] = RC16_LEN;
|
||||
memset(buffer, 0, RC16_LEN);
|
||||
|
||||
the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE,
|
||||
buffer, longrc ? 13 : 8, &sshdr,
|
||||
SD_TIMEOUT, SD_MAX_RETRIES, NULL);
|
||||
buffer, RC16_LEN, &sshdr,
|
||||
SD_TIMEOUT, SD_MAX_RETRIES, NULL);
|
||||
|
||||
if (media_not_present(sdkp, &sshdr))
|
||||
return;
|
||||
return -ENODEV;
|
||||
|
||||
if (the_result) {
|
||||
sense_valid = scsi_sense_valid(&sshdr);
|
||||
if (sense_valid &&
|
||||
sshdr.sense_key == ILLEGAL_REQUEST &&
|
||||
(sshdr.asc == 0x20 || sshdr.asc == 0x24) &&
|
||||
sshdr.ascq == 0x00)
|
||||
/* Invalid Command Operation Code or
|
||||
* Invalid Field in CDB, just retry
|
||||
* silently with RC10 */
|
||||
return -EINVAL;
|
||||
}
|
||||
retries--;
|
||||
|
||||
} while (the_result && retries);
|
||||
|
||||
if (the_result) {
|
||||
sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY(16) failed\n");
|
||||
read_capacity_error(sdkp, sdp, &sshdr, sense_valid, the_result);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sector_size = (buffer[8] << 24) | (buffer[9] << 16) |
|
||||
(buffer[10] << 8) | buffer[11];
|
||||
lba = (((u64)buffer[0] << 56) | ((u64)buffer[1] << 48) |
|
||||
((u64)buffer[2] << 40) | ((u64)buffer[3] << 32) |
|
||||
((u64)buffer[4] << 24) | ((u64)buffer[5] << 16) |
|
||||
((u64)buffer[6] << 8) | (u64)buffer[7]);
|
||||
|
||||
sd_read_protection_type(sdkp, buffer);
|
||||
|
||||
if ((sizeof(sdkp->capacity) == 4) && (lba >= 0xffffffffULL)) {
|
||||
sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a "
|
||||
"kernel compiled with support for large block "
|
||||
"devices.\n");
|
||||
sdkp->capacity = 0;
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
sdkp->capacity = lba + 1;
|
||||
return sector_size;
|
||||
}
|
||||
|
||||
static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
|
||||
unsigned char *buffer)
|
||||
{
|
||||
unsigned char cmd[16];
|
||||
struct scsi_sense_hdr sshdr;
|
||||
int sense_valid = 0;
|
||||
int the_result;
|
||||
int retries = 3;
|
||||
sector_t lba;
|
||||
unsigned sector_size;
|
||||
|
||||
do {
|
||||
cmd[0] = READ_CAPACITY;
|
||||
memset(&cmd[1], 0, 9);
|
||||
memset(buffer, 0, 8);
|
||||
|
||||
the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE,
|
||||
buffer, 8, &sshdr,
|
||||
SD_TIMEOUT, SD_MAX_RETRIES, NULL);
|
||||
|
||||
if (media_not_present(sdkp, &sshdr))
|
||||
return -ENODEV;
|
||||
|
||||
if (the_result)
|
||||
sense_valid = scsi_sense_valid(&sshdr);
|
||||
@ -1316,85 +1400,96 @@ sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer)
|
||||
|
||||
} while (the_result && retries);
|
||||
|
||||
if (the_result && !longrc) {
|
||||
if (the_result) {
|
||||
sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY failed\n");
|
||||
sd_print_result(sdkp, the_result);
|
||||
if (driver_byte(the_result) & DRIVER_SENSE)
|
||||
sd_print_sense_hdr(sdkp, &sshdr);
|
||||
else
|
||||
sd_printk(KERN_NOTICE, sdkp, "Sense not available.\n");
|
||||
read_capacity_error(sdkp, sdp, &sshdr, sense_valid, the_result);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Set dirty bit for removable devices if not ready -
|
||||
* sometimes drives will not report this properly. */
|
||||
if (sdp->removable &&
|
||||
sense_valid && sshdr.sense_key == NOT_READY)
|
||||
sdp->changed = 1;
|
||||
sector_size = (buffer[4] << 24) | (buffer[5] << 16) |
|
||||
(buffer[6] << 8) | buffer[7];
|
||||
lba = (buffer[0] << 24) | (buffer[1] << 16) |
|
||||
(buffer[2] << 8) | buffer[3];
|
||||
|
||||
/* Either no media are present but the drive didn't tell us,
|
||||
or they are present but the read capacity command fails */
|
||||
/* sdkp->media_present = 0; -- not always correct */
|
||||
sdkp->capacity = 0; /* unknown mapped to zero - as usual */
|
||||
if ((sizeof(sdkp->capacity) == 4) && (lba == 0xffffffff)) {
|
||||
sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a "
|
||||
"kernel compiled with support for large block "
|
||||
"devices.\n");
|
||||
sdkp->capacity = 0;
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (the_result && longrc) {
|
||||
/* READ CAPACITY(16) has been failed */
|
||||
sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY(16) failed\n");
|
||||
sd_print_result(sdkp, the_result);
|
||||
sd_printk(KERN_NOTICE, sdkp, "Use 0xffffffff as device size\n");
|
||||
sdkp->capacity = lba + 1;
|
||||
return sector_size;
|
||||
}
|
||||
|
||||
sdkp->capacity = 1 + (sector_t) 0xffffffff;
|
||||
goto got_data;
|
||||
}
|
||||
|
||||
if (!longrc) {
|
||||
sector_size = (buffer[4] << 24) |
|
||||
(buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
|
||||
if (buffer[0] == 0xff && buffer[1] == 0xff &&
|
||||
buffer[2] == 0xff && buffer[3] == 0xff) {
|
||||
if(sizeof(sdkp->capacity) > 4) {
|
||||
sd_printk(KERN_NOTICE, sdkp, "Very big device. "
|
||||
"Trying to use READ CAPACITY(16).\n");
|
||||
longrc = 1;
|
||||
goto repeat;
|
||||
}
|
||||
sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use "
|
||||
"a kernel compiled with support for large "
|
||||
"block devices.\n");
|
||||
sdkp->capacity = 0;
|
||||
static int sd_try_rc16_first(struct scsi_device *sdp)
|
||||
{
|
||||
if (sdp->scsi_level > SCSI_SPC_2)
|
||||
return 1;
|
||||
if (scsi_device_protection(sdp))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* read disk capacity
|
||||
*/
|
||||
static void
|
||||
sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer)
|
||||
{
|
||||
int sector_size;
|
||||
struct scsi_device *sdp = sdkp->device;
|
||||
sector_t old_capacity = sdkp->capacity;
|
||||
|
||||
if (sd_try_rc16_first(sdp)) {
|
||||
sector_size = read_capacity_16(sdkp, sdp, buffer);
|
||||
if (sector_size == -EOVERFLOW)
|
||||
goto got_data;
|
||||
if (sector_size == -ENODEV)
|
||||
return;
|
||||
if (sector_size < 0)
|
||||
sector_size = read_capacity_10(sdkp, sdp, buffer);
|
||||
if (sector_size < 0)
|
||||
return;
|
||||
} else {
|
||||
sector_size = read_capacity_10(sdkp, sdp, buffer);
|
||||
if (sector_size == -EOVERFLOW)
|
||||
goto got_data;
|
||||
if (sector_size < 0)
|
||||
return;
|
||||
if ((sizeof(sdkp->capacity) > 4) &&
|
||||
(sdkp->capacity > 0xffffffffULL)) {
|
||||
int old_sector_size = sector_size;
|
||||
sd_printk(KERN_NOTICE, sdkp, "Very big device. "
|
||||
"Trying to use READ CAPACITY(16).\n");
|
||||
sector_size = read_capacity_16(sdkp, sdp, buffer);
|
||||
if (sector_size < 0) {
|
||||
sd_printk(KERN_NOTICE, sdkp,
|
||||
"Using 0xffffffff as device size\n");
|
||||
sdkp->capacity = 1 + (sector_t) 0xffffffff;
|
||||
sector_size = old_sector_size;
|
||||
goto got_data;
|
||||
}
|
||||
}
|
||||
sdkp->capacity = 1 + (((sector_t)buffer[0] << 24) |
|
||||
(buffer[1] << 16) |
|
||||
(buffer[2] << 8) |
|
||||
buffer[3]);
|
||||
} else {
|
||||
sdkp->capacity = 1 + (((u64)buffer[0] << 56) |
|
||||
((u64)buffer[1] << 48) |
|
||||
((u64)buffer[2] << 40) |
|
||||
((u64)buffer[3] << 32) |
|
||||
((sector_t)buffer[4] << 24) |
|
||||
((sector_t)buffer[5] << 16) |
|
||||
((sector_t)buffer[6] << 8) |
|
||||
(sector_t)buffer[7]);
|
||||
|
||||
sector_size = (buffer[8] << 24) |
|
||||
(buffer[9] << 16) | (buffer[10] << 8) | buffer[11];
|
||||
}
|
||||
|
||||
sd_read_protection_type(sdkp, buffer);
|
||||
}
|
||||
|
||||
/* Some devices return the total number of sectors, not the
|
||||
* highest sector number. Make the necessary adjustment. */
|
||||
if (sdp->fix_capacity) {
|
||||
/* Some devices are known to return the total number of blocks,
|
||||
* not the highest block number. Some devices have versions
|
||||
* which do this and others which do not. Some devices we might
|
||||
* suspect of doing this but we don't know for certain.
|
||||
*
|
||||
* If we know the reported capacity is wrong, decrement it. If
|
||||
* we can only guess, then assume the number of blocks is even
|
||||
* (usually true but not always) and err on the side of lowering
|
||||
* the capacity.
|
||||
*/
|
||||
if (sdp->fix_capacity ||
|
||||
(sdp->guess_capacity && (sdkp->capacity & 0x01))) {
|
||||
sd_printk(KERN_INFO, sdkp, "Adjusting the sector count "
|
||||
"from its reported value: %llu\n",
|
||||
(unsigned long long) sdkp->capacity);
|
||||
--sdkp->capacity;
|
||||
|
||||
/* Some devices have version which report the correct sizes
|
||||
* and others which do not. We guess size according to a heuristic
|
||||
* and err on the side of lowering the capacity. */
|
||||
} else {
|
||||
if (sdp->guess_capacity)
|
||||
if (sdkp->capacity & 0x01) /* odd sizes are odd */
|
||||
--sdkp->capacity;
|
||||
}
|
||||
|
||||
got_data:
|
||||
@ -1437,10 +1532,11 @@ sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer)
|
||||
string_get_size(sz, STRING_UNITS_10, cap_str_10,
|
||||
sizeof(cap_str_10));
|
||||
|
||||
sd_printk(KERN_NOTICE, sdkp,
|
||||
"%llu %d-byte hardware sectors: (%s/%s)\n",
|
||||
(unsigned long long)sdkp->capacity,
|
||||
sector_size, cap_str_10, cap_str_2);
|
||||
if (sdkp->first_scan || old_capacity != sdkp->capacity)
|
||||
sd_printk(KERN_NOTICE, sdkp,
|
||||
"%llu %d-byte hardware sectors: (%s/%s)\n",
|
||||
(unsigned long long)sdkp->capacity,
|
||||
sector_size, cap_str_10, cap_str_2);
|
||||
}
|
||||
|
||||
/* Rescale capacity to 512-byte units */
|
||||
@ -1477,6 +1573,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)
|
||||
int res;
|
||||
struct scsi_device *sdp = sdkp->device;
|
||||
struct scsi_mode_data data;
|
||||
int old_wp = sdkp->write_prot;
|
||||
|
||||
set_disk_ro(sdkp->disk, 0);
|
||||
if (sdp->skip_ms_page_3f) {
|
||||
@ -1517,11 +1614,13 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)
|
||||
} else {
|
||||
sdkp->write_prot = ((data.device_specific & 0x80) != 0);
|
||||
set_disk_ro(sdkp->disk, sdkp->write_prot);
|
||||
sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n",
|
||||
sdkp->write_prot ? "on" : "off");
|
||||
sd_printk(KERN_DEBUG, sdkp,
|
||||
"Mode Sense: %02x %02x %02x %02x\n",
|
||||
buffer[0], buffer[1], buffer[2], buffer[3]);
|
||||
if (sdkp->first_scan || old_wp != sdkp->write_prot) {
|
||||
sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n",
|
||||
sdkp->write_prot ? "on" : "off");
|
||||
sd_printk(KERN_DEBUG, sdkp,
|
||||
"Mode Sense: %02x %02x %02x %02x\n",
|
||||
buffer[0], buffer[1], buffer[2], buffer[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1539,6 +1638,9 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
|
||||
int modepage;
|
||||
struct scsi_mode_data data;
|
||||
struct scsi_sense_hdr sshdr;
|
||||
int old_wce = sdkp->WCE;
|
||||
int old_rcd = sdkp->RCD;
|
||||
int old_dpofua = sdkp->DPOFUA;
|
||||
|
||||
if (sdp->skip_ms_page_8)
|
||||
goto defaults;
|
||||
@ -1610,12 +1712,14 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
|
||||
sdkp->DPOFUA = 0;
|
||||
}
|
||||
|
||||
sd_printk(KERN_NOTICE, sdkp,
|
||||
"Write cache: %s, read cache: %s, %s\n",
|
||||
sdkp->WCE ? "enabled" : "disabled",
|
||||
sdkp->RCD ? "disabled" : "enabled",
|
||||
sdkp->DPOFUA ? "supports DPO and FUA"
|
||||
: "doesn't support DPO or FUA");
|
||||
if (sdkp->first_scan || old_wce != sdkp->WCE ||
|
||||
old_rcd != sdkp->RCD || old_dpofua != sdkp->DPOFUA)
|
||||
sd_printk(KERN_NOTICE, sdkp,
|
||||
"Write cache: %s, read cache: %s, %s\n",
|
||||
sdkp->WCE ? "enabled" : "disabled",
|
||||
sdkp->RCD ? "disabled" : "enabled",
|
||||
sdkp->DPOFUA ? "supports DPO and FUA"
|
||||
: "doesn't support DPO or FUA");
|
||||
|
||||
return;
|
||||
}
|
||||
@ -1711,15 +1815,6 @@ static int sd_revalidate_disk(struct gendisk *disk)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* defaults, until the device tells us otherwise */
|
||||
sdp->sector_size = 512;
|
||||
sdkp->capacity = 0;
|
||||
sdkp->media_present = 1;
|
||||
sdkp->write_prot = 0;
|
||||
sdkp->WCE = 0;
|
||||
sdkp->RCD = 0;
|
||||
sdkp->ATO = 0;
|
||||
|
||||
sd_spinup_disk(sdkp);
|
||||
|
||||
/*
|
||||
@ -1733,6 +1828,8 @@ static int sd_revalidate_disk(struct gendisk *disk)
|
||||
sd_read_app_tag_own(sdkp, buffer);
|
||||
}
|
||||
|
||||
sdkp->first_scan = 0;
|
||||
|
||||
/*
|
||||
* We now have all cache related info, determine how we deal
|
||||
* with ordered requests. Note that as the current SCSI
|
||||
@ -1843,6 +1940,16 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
|
||||
gd->private_data = &sdkp->driver;
|
||||
gd->queue = sdkp->device->request_queue;
|
||||
|
||||
/* defaults, until the device tells us otherwise */
|
||||
sdp->sector_size = 512;
|
||||
sdkp->capacity = 0;
|
||||
sdkp->media_present = 1;
|
||||
sdkp->write_prot = 0;
|
||||
sdkp->WCE = 0;
|
||||
sdkp->RCD = 0;
|
||||
sdkp->ATO = 0;
|
||||
sdkp->first_scan = 1;
|
||||
|
||||
sd_revalidate_disk(gd);
|
||||
|
||||
blk_queue_prep_rq(sdp->request_queue, sd_prep_fn);
|
||||
|
@ -53,6 +53,7 @@ struct scsi_disk {
|
||||
unsigned WCE : 1; /* state of disk WCE bit */
|
||||
unsigned RCD : 1; /* state of disk RCD bit, unused */
|
||||
unsigned DPOFUA : 1; /* state of disk DPOFUA bit */
|
||||
unsigned first_scan : 1;
|
||||
};
|
||||
#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)
|
||||
|
||||
|
@ -345,44 +345,21 @@ static int ses_enclosure_find_by_addr(struct enclosure_device *edev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define VPD_INQUIRY_SIZE 36
|
||||
|
||||
static void ses_match_to_enclosure(struct enclosure_device *edev,
|
||||
struct scsi_device *sdev)
|
||||
{
|
||||
unsigned char *buf = kmalloc(VPD_INQUIRY_SIZE, GFP_KERNEL);
|
||||
unsigned char *buf;
|
||||
unsigned char *desc;
|
||||
u16 vpd_len;
|
||||
unsigned int vpd_len;
|
||||
struct efd efd = {
|
||||
.addr = 0,
|
||||
};
|
||||
unsigned char cmd[] = {
|
||||
INQUIRY,
|
||||
1,
|
||||
0x83,
|
||||
VPD_INQUIRY_SIZE >> 8,
|
||||
VPD_INQUIRY_SIZE & 0xff,
|
||||
0
|
||||
};
|
||||
|
||||
buf = scsi_get_vpd_page(sdev, 0x83);
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
if (scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf,
|
||||
VPD_INQUIRY_SIZE, NULL, SES_TIMEOUT, SES_RETRIES,
|
||||
NULL))
|
||||
goto free;
|
||||
|
||||
vpd_len = (buf[2] << 8) + buf[3];
|
||||
kfree(buf);
|
||||
buf = kmalloc(vpd_len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return;
|
||||
cmd[3] = vpd_len >> 8;
|
||||
cmd[4] = vpd_len & 0xff;
|
||||
if (scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf,
|
||||
vpd_len, NULL, SES_TIMEOUT, SES_RETRIES, NULL))
|
||||
goto free;
|
||||
vpd_len = ((buf[2] << 8) | buf[3]) + 4;
|
||||
|
||||
desc = buf + 4;
|
||||
while (desc < buf + vpd_len) {
|
||||
@ -393,7 +370,7 @@ static void ses_match_to_enclosure(struct enclosure_device *edev,
|
||||
u8 type = desc[1] & 0x0f;
|
||||
u8 len = desc[3];
|
||||
|
||||
if (piv && code_set == 1 && assoc == 1 && code_set == 1
|
||||
if (piv && code_set == 1 && assoc == 1
|
||||
&& proto == SCSI_PROTOCOL_SAS && type == 3 && len == 8)
|
||||
efd.addr = (u64)desc[4] << 56 |
|
||||
(u64)desc[5] << 48 |
|
||||
|
@ -98,7 +98,6 @@ static int scatter_elem_sz = SG_SCATTER_SZ;
|
||||
static int scatter_elem_sz_prev = SG_SCATTER_SZ;
|
||||
|
||||
#define SG_SECTOR_SZ 512
|
||||
#define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
|
||||
|
||||
static int sg_add(struct device *, struct class_interface *);
|
||||
static void sg_remove(struct device *, struct class_interface *);
|
||||
@ -137,10 +136,11 @@ typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */
|
||||
volatile char done; /* 0->before bh, 1->before read, 2->read */
|
||||
struct request *rq;
|
||||
struct bio *bio;
|
||||
struct execute_work ew;
|
||||
} Sg_request;
|
||||
|
||||
typedef struct sg_fd { /* holds the state of a file descriptor */
|
||||
struct sg_fd *nextfp; /* NULL when last opened fd on this device */
|
||||
struct list_head sfd_siblings;
|
||||
struct sg_device *parentdp; /* owning device */
|
||||
wait_queue_head_t read_wait; /* queue read until command done */
|
||||
rwlock_t rq_list_lock; /* protect access to list in req_arr */
|
||||
@ -158,6 +158,8 @@ typedef struct sg_fd { /* holds the state of a file descriptor */
|
||||
char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */
|
||||
char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */
|
||||
char mmap_called; /* 0 -> mmap() never called on this fd */
|
||||
struct kref f_ref;
|
||||
struct execute_work ew;
|
||||
} Sg_fd;
|
||||
|
||||
typedef struct sg_device { /* holds the state of each scsi generic device */
|
||||
@ -165,27 +167,25 @@ typedef struct sg_device { /* holds the state of each scsi generic device */
|
||||
wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */
|
||||
int sg_tablesize; /* adapter's max scatter-gather table size */
|
||||
u32 index; /* device index number */
|
||||
Sg_fd *headfp; /* first open fd belonging to this device */
|
||||
struct list_head sfds;
|
||||
volatile char detached; /* 0->attached, 1->detached pending removal */
|
||||
volatile char exclude; /* opened for exclusive access */
|
||||
char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
|
||||
struct gendisk *disk;
|
||||
struct cdev * cdev; /* char_dev [sysfs: /sys/cdev/major/sg<n>] */
|
||||
struct kref d_ref;
|
||||
} Sg_device;
|
||||
|
||||
static int sg_fasync(int fd, struct file *filp, int mode);
|
||||
/* tasklet or soft irq callback */
|
||||
static void sg_rq_end_io(struct request *rq, int uptodate);
|
||||
static int sg_start_req(Sg_request *srp, unsigned char *cmd);
|
||||
static void sg_finish_rem_req(Sg_request * srp);
|
||||
static int sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size);
|
||||
static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp,
|
||||
int tablesize);
|
||||
static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count,
|
||||
Sg_request * srp);
|
||||
static ssize_t sg_new_write(Sg_fd *sfp, struct file *file,
|
||||
const char __user *buf, size_t count, int blocking,
|
||||
int read_only, Sg_request **o_srp);
|
||||
int read_only, int sg_io_owned, Sg_request **o_srp);
|
||||
static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
|
||||
unsigned char *cmnd, int timeout, int blocking);
|
||||
static int sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer);
|
||||
@ -194,16 +194,13 @@ static void sg_build_reserve(Sg_fd * sfp, int req_size);
|
||||
static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size);
|
||||
static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp);
|
||||
static Sg_fd *sg_add_sfp(Sg_device * sdp, int dev);
|
||||
static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
|
||||
static void __sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
|
||||
static void sg_remove_sfp(struct kref *);
|
||||
static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id);
|
||||
static Sg_request *sg_add_request(Sg_fd * sfp);
|
||||
static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
|
||||
static int sg_res_in_use(Sg_fd * sfp);
|
||||
static Sg_device *sg_get_dev(int dev);
|
||||
#ifdef CONFIG_SCSI_PROC_FS
|
||||
static int sg_last_dev(void);
|
||||
#endif
|
||||
static void sg_put_dev(Sg_device *sdp);
|
||||
|
||||
#define SZ_SG_HEADER sizeof(struct sg_header)
|
||||
#define SZ_SG_IO_HDR sizeof(sg_io_hdr_t)
|
||||
@ -237,22 +234,17 @@ sg_open(struct inode *inode, struct file *filp)
|
||||
nonseekable_open(inode, filp);
|
||||
SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags));
|
||||
sdp = sg_get_dev(dev);
|
||||
if ((!sdp) || (!sdp->device)) {
|
||||
unlock_kernel();
|
||||
return -ENXIO;
|
||||
}
|
||||
if (sdp->detached) {
|
||||
unlock_kernel();
|
||||
return -ENODEV;
|
||||
if (IS_ERR(sdp)) {
|
||||
retval = PTR_ERR(sdp);
|
||||
sdp = NULL;
|
||||
goto sg_put;
|
||||
}
|
||||
|
||||
/* This driver's module count bumped by fops_get in <linux/fs.h> */
|
||||
/* Prevent the device driver from vanishing while we sleep */
|
||||
retval = scsi_device_get(sdp->device);
|
||||
if (retval) {
|
||||
unlock_kernel();
|
||||
return retval;
|
||||
}
|
||||
if (retval)
|
||||
goto sg_put;
|
||||
|
||||
if (!((flags & O_NONBLOCK) ||
|
||||
scsi_block_when_processing_errors(sdp->device))) {
|
||||
@ -266,13 +258,13 @@ sg_open(struct inode *inode, struct file *filp)
|
||||
retval = -EPERM; /* Can't lock it with read only access */
|
||||
goto error_out;
|
||||
}
|
||||
if (sdp->headfp && (flags & O_NONBLOCK)) {
|
||||
if (!list_empty(&sdp->sfds) && (flags & O_NONBLOCK)) {
|
||||
retval = -EBUSY;
|
||||
goto error_out;
|
||||
}
|
||||
res = 0;
|
||||
__wait_event_interruptible(sdp->o_excl_wait,
|
||||
((sdp->headfp || sdp->exclude) ? 0 : (sdp->exclude = 1)), res);
|
||||
((!list_empty(&sdp->sfds) || sdp->exclude) ? 0 : (sdp->exclude = 1)), res);
|
||||
if (res) {
|
||||
retval = res; /* -ERESTARTSYS because signal hit process */
|
||||
goto error_out;
|
||||
@ -294,7 +286,7 @@ sg_open(struct inode *inode, struct file *filp)
|
||||
retval = -ENODEV;
|
||||
goto error_out;
|
||||
}
|
||||
if (!sdp->headfp) { /* no existing opens on this device */
|
||||
if (list_empty(&sdp->sfds)) { /* no existing opens on this device */
|
||||
sdp->sgdebug = 0;
|
||||
q = sdp->device->request_queue;
|
||||
sdp->sg_tablesize = min(q->max_hw_segments,
|
||||
@ -303,16 +295,20 @@ sg_open(struct inode *inode, struct file *filp)
|
||||
if ((sfp = sg_add_sfp(sdp, dev)))
|
||||
filp->private_data = sfp;
|
||||
else {
|
||||
if (flags & O_EXCL)
|
||||
if (flags & O_EXCL) {
|
||||
sdp->exclude = 0; /* undo if error */
|
||||
wake_up_interruptible(&sdp->o_excl_wait);
|
||||
}
|
||||
retval = -ENOMEM;
|
||||
goto error_out;
|
||||
}
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
|
||||
error_out:
|
||||
scsi_device_put(sdp->device);
|
||||
retval = 0;
|
||||
error_out:
|
||||
if (retval)
|
||||
scsi_device_put(sdp->device);
|
||||
sg_put:
|
||||
if (sdp)
|
||||
sg_put_dev(sdp);
|
||||
unlock_kernel();
|
||||
return retval;
|
||||
}
|
||||
@ -327,13 +323,13 @@ sg_release(struct inode *inode, struct file *filp)
|
||||
if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
|
||||
return -ENXIO;
|
||||
SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name));
|
||||
if (0 == sg_remove_sfp(sdp, sfp)) { /* Returns 1 when sdp gone */
|
||||
if (!sdp->detached) {
|
||||
scsi_device_put(sdp->device);
|
||||
}
|
||||
sdp->exclude = 0;
|
||||
wake_up_interruptible(&sdp->o_excl_wait);
|
||||
}
|
||||
|
||||
sfp->closed = 1;
|
||||
|
||||
sdp->exclude = 0;
|
||||
wake_up_interruptible(&sdp->o_excl_wait);
|
||||
|
||||
kref_put(&sfp->f_ref, sg_remove_sfp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -557,7 +553,8 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
|
||||
return -EFAULT;
|
||||
blocking = !(filp->f_flags & O_NONBLOCK);
|
||||
if (old_hdr.reply_len < 0)
|
||||
return sg_new_write(sfp, filp, buf, count, blocking, 0, NULL);
|
||||
return sg_new_write(sfp, filp, buf, count,
|
||||
blocking, 0, 0, NULL);
|
||||
if (count < (SZ_SG_HEADER + 6))
|
||||
return -EIO; /* The minimum scsi command length is 6 bytes. */
|
||||
|
||||
@ -638,7 +635,7 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
|
||||
|
||||
static ssize_t
|
||||
sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf,
|
||||
size_t count, int blocking, int read_only,
|
||||
size_t count, int blocking, int read_only, int sg_io_owned,
|
||||
Sg_request **o_srp)
|
||||
{
|
||||
int k;
|
||||
@ -658,6 +655,7 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf,
|
||||
SCSI_LOG_TIMEOUT(1, printk("sg_new_write: queue full\n"));
|
||||
return -EDOM;
|
||||
}
|
||||
srp->sg_io_owned = sg_io_owned;
|
||||
hp = &srp->header;
|
||||
if (__copy_from_user(hp, buf, SZ_SG_IO_HDR)) {
|
||||
sg_remove_request(sfp, srp);
|
||||
@ -755,23 +753,12 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
|
||||
hp->duration = jiffies_to_msecs(jiffies);
|
||||
|
||||
srp->rq->timeout = timeout;
|
||||
kref_get(&sfp->f_ref); /* sg_rq_end_io() does kref_put(). */
|
||||
blk_execute_rq_nowait(sdp->device->request_queue, sdp->disk,
|
||||
srp->rq, 1, sg_rq_end_io);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sg_srp_done(Sg_request *srp, Sg_fd *sfp)
|
||||
{
|
||||
unsigned long iflags;
|
||||
int done;
|
||||
|
||||
read_lock_irqsave(&sfp->rq_list_lock, iflags);
|
||||
done = srp->done;
|
||||
read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
|
||||
return done;
|
||||
}
|
||||
|
||||
static int
|
||||
sg_ioctl(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd_in, unsigned long arg)
|
||||
@ -804,27 +791,26 @@ sg_ioctl(struct inode *inode, struct file *filp,
|
||||
return -EFAULT;
|
||||
result =
|
||||
sg_new_write(sfp, filp, p, SZ_SG_IO_HDR,
|
||||
blocking, read_only, &srp);
|
||||
blocking, read_only, 1, &srp);
|
||||
if (result < 0)
|
||||
return result;
|
||||
srp->sg_io_owned = 1;
|
||||
while (1) {
|
||||
result = 0; /* following macro to beat race condition */
|
||||
__wait_event_interruptible(sfp->read_wait,
|
||||
(sdp->detached || sfp->closed || sg_srp_done(srp, sfp)),
|
||||
result);
|
||||
(srp->done || sdp->detached),
|
||||
result);
|
||||
if (sdp->detached)
|
||||
return -ENODEV;
|
||||
if (sfp->closed)
|
||||
return 0; /* request packet dropped already */
|
||||
if (0 == result)
|
||||
write_lock_irq(&sfp->rq_list_lock);
|
||||
if (srp->done) {
|
||||
srp->done = 2;
|
||||
write_unlock_irq(&sfp->rq_list_lock);
|
||||
break;
|
||||
}
|
||||
srp->orphan = 1;
|
||||
write_unlock_irq(&sfp->rq_list_lock);
|
||||
return result; /* -ERESTARTSYS because signal hit process */
|
||||
}
|
||||
write_lock_irqsave(&sfp->rq_list_lock, iflags);
|
||||
srp->done = 2;
|
||||
write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
|
||||
result = sg_new_read(sfp, p, SZ_SG_IO_HDR, srp);
|
||||
return (result < 0) ? result : 0;
|
||||
}
|
||||
@ -1238,6 +1224,15 @@ sg_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sg_rq_end_io_usercontext(struct work_struct *work)
|
||||
{
|
||||
struct sg_request *srp = container_of(work, struct sg_request, ew.work);
|
||||
struct sg_fd *sfp = srp->parentfp;
|
||||
|
||||
sg_finish_rem_req(srp);
|
||||
kref_put(&sfp->f_ref, sg_remove_sfp);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is a "bottom half" handler that is called by the mid
|
||||
* level when a command is completed (or has failed).
|
||||
@ -1245,24 +1240,23 @@ sg_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
static void sg_rq_end_io(struct request *rq, int uptodate)
|
||||
{
|
||||
struct sg_request *srp = rq->end_io_data;
|
||||
Sg_device *sdp = NULL;
|
||||
Sg_device *sdp;
|
||||
Sg_fd *sfp;
|
||||
unsigned long iflags;
|
||||
unsigned int ms;
|
||||
char *sense;
|
||||
int result, resid;
|
||||
int result, resid, done = 1;
|
||||
|
||||
if (NULL == srp) {
|
||||
printk(KERN_ERR "sg_cmd_done: NULL request\n");
|
||||
if (WARN_ON(srp->done != 0))
|
||||
return;
|
||||
}
|
||||
|
||||
sfp = srp->parentfp;
|
||||
if (sfp)
|
||||
sdp = sfp->parentdp;
|
||||
if ((NULL == sdp) || sdp->detached) {
|
||||
printk(KERN_INFO "sg_cmd_done: device detached\n");
|
||||
if (WARN_ON(sfp == NULL))
|
||||
return;
|
||||
}
|
||||
|
||||
sdp = sfp->parentdp;
|
||||
if (unlikely(sdp->detached))
|
||||
printk(KERN_INFO "sg_rq_end_io: device detached\n");
|
||||
|
||||
sense = rq->sense;
|
||||
result = rq->errors;
|
||||
@ -1301,33 +1295,25 @@ static void sg_rq_end_io(struct request *rq, int uptodate)
|
||||
}
|
||||
/* Rely on write phase to clean out srp status values, so no "else" */
|
||||
|
||||
if (sfp->closed) { /* whoops this fd already released, cleanup */
|
||||
SCSI_LOG_TIMEOUT(1, printk("sg_cmd_done: already closed, freeing ...\n"));
|
||||
sg_finish_rem_req(srp);
|
||||
srp = NULL;
|
||||
if (NULL == sfp->headrp) {
|
||||
SCSI_LOG_TIMEOUT(1, printk("sg_cmd_done: already closed, final cleanup\n"));
|
||||
if (0 == sg_remove_sfp(sdp, sfp)) { /* device still present */
|
||||
scsi_device_put(sdp->device);
|
||||
}
|
||||
sfp = NULL;
|
||||
}
|
||||
} else if (srp && srp->orphan) {
|
||||
write_lock_irqsave(&sfp->rq_list_lock, iflags);
|
||||
if (unlikely(srp->orphan)) {
|
||||
if (sfp->keep_orphan)
|
||||
srp->sg_io_owned = 0;
|
||||
else {
|
||||
sg_finish_rem_req(srp);
|
||||
srp = NULL;
|
||||
}
|
||||
else
|
||||
done = 0;
|
||||
}
|
||||
if (sfp && srp) {
|
||||
/* Now wake up any sg_read() that is waiting for this packet. */
|
||||
kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN);
|
||||
write_lock_irqsave(&sfp->rq_list_lock, iflags);
|
||||
srp->done = 1;
|
||||
srp->done = done;
|
||||
write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
|
||||
|
||||
if (likely(done)) {
|
||||
/* Now wake up any sg_read() that is waiting for this
|
||||
* packet.
|
||||
*/
|
||||
wake_up_interruptible(&sfp->read_wait);
|
||||
write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
|
||||
}
|
||||
kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN);
|
||||
kref_put(&sfp->f_ref, sg_remove_sfp);
|
||||
} else
|
||||
execute_in_process_context(sg_rq_end_io_usercontext, &srp->ew);
|
||||
}
|
||||
|
||||
static struct file_operations sg_fops = {
|
||||
@ -1362,17 +1348,18 @@ static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
|
||||
printk(KERN_WARNING "kmalloc Sg_device failure\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
error = -ENOMEM;
|
||||
|
||||
if (!idr_pre_get(&sg_index_idr, GFP_KERNEL)) {
|
||||
printk(KERN_WARNING "idr expansion Sg_device failure\n");
|
||||
error = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
write_lock_irqsave(&sg_index_lock, iflags);
|
||||
error = idr_get_new(&sg_index_idr, sdp, &k);
|
||||
write_unlock_irqrestore(&sg_index_lock, iflags);
|
||||
|
||||
error = idr_get_new(&sg_index_idr, sdp, &k);
|
||||
if (error) {
|
||||
write_unlock_irqrestore(&sg_index_lock, iflags);
|
||||
printk(KERN_WARNING "idr allocation Sg_device failure: %d\n",
|
||||
error);
|
||||
goto out;
|
||||
@ -1386,9 +1373,13 @@ static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
|
||||
disk->first_minor = k;
|
||||
sdp->disk = disk;
|
||||
sdp->device = scsidp;
|
||||
INIT_LIST_HEAD(&sdp->sfds);
|
||||
init_waitqueue_head(&sdp->o_excl_wait);
|
||||
sdp->sg_tablesize = min(q->max_hw_segments, q->max_phys_segments);
|
||||
sdp->index = k;
|
||||
kref_init(&sdp->d_ref);
|
||||
|
||||
write_unlock_irqrestore(&sg_index_lock, iflags);
|
||||
|
||||
error = 0;
|
||||
out:
|
||||
@ -1399,6 +1390,8 @@ static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
|
||||
return sdp;
|
||||
|
||||
overflow:
|
||||
idr_remove(&sg_index_idr, k);
|
||||
write_unlock_irqrestore(&sg_index_lock, iflags);
|
||||
sdev_printk(KERN_WARNING, scsidp,
|
||||
"Unable to attach sg device type=%d, minor "
|
||||
"number exceeds %d\n", scsidp->type, SG_MAX_DEVS - 1);
|
||||
@ -1486,49 +1479,46 @@ sg_add(struct device *cl_dev, struct class_interface *cl_intf)
|
||||
return error;
|
||||
}
|
||||
|
||||
static void
|
||||
sg_remove(struct device *cl_dev, struct class_interface *cl_intf)
|
||||
static void sg_device_destroy(struct kref *kref)
|
||||
{
|
||||
struct sg_device *sdp = container_of(kref, struct sg_device, d_ref);
|
||||
unsigned long flags;
|
||||
|
||||
/* CAUTION! Note that the device can still be found via idr_find()
|
||||
* even though the refcount is 0. Therefore, do idr_remove() BEFORE
|
||||
* any other cleanup.
|
||||
*/
|
||||
|
||||
write_lock_irqsave(&sg_index_lock, flags);
|
||||
idr_remove(&sg_index_idr, sdp->index);
|
||||
write_unlock_irqrestore(&sg_index_lock, flags);
|
||||
|
||||
SCSI_LOG_TIMEOUT(3,
|
||||
printk("sg_device_destroy: %s\n",
|
||||
sdp->disk->disk_name));
|
||||
|
||||
put_disk(sdp->disk);
|
||||
kfree(sdp);
|
||||
}
|
||||
|
||||
static void sg_remove(struct device *cl_dev, struct class_interface *cl_intf)
|
||||
{
|
||||
struct scsi_device *scsidp = to_scsi_device(cl_dev->parent);
|
||||
Sg_device *sdp = dev_get_drvdata(cl_dev);
|
||||
unsigned long iflags;
|
||||
Sg_fd *sfp;
|
||||
Sg_fd *tsfp;
|
||||
Sg_request *srp;
|
||||
Sg_request *tsrp;
|
||||
int delay;
|
||||
|
||||
if (!sdp)
|
||||
if (!sdp || sdp->detached)
|
||||
return;
|
||||
|
||||
delay = 0;
|
||||
SCSI_LOG_TIMEOUT(3, printk("sg_remove: %s\n", sdp->disk->disk_name));
|
||||
|
||||
/* Need a write lock to set sdp->detached. */
|
||||
write_lock_irqsave(&sg_index_lock, iflags);
|
||||
if (sdp->headfp) {
|
||||
sdp->detached = 1;
|
||||
for (sfp = sdp->headfp; sfp; sfp = tsfp) {
|
||||
tsfp = sfp->nextfp;
|
||||
for (srp = sfp->headrp; srp; srp = tsrp) {
|
||||
tsrp = srp->nextrp;
|
||||
if (sfp->closed || (0 == sg_srp_done(srp, sfp)))
|
||||
sg_finish_rem_req(srp);
|
||||
}
|
||||
if (sfp->closed) {
|
||||
scsi_device_put(sdp->device);
|
||||
__sg_remove_sfp(sdp, sfp);
|
||||
} else {
|
||||
delay = 1;
|
||||
wake_up_interruptible(&sfp->read_wait);
|
||||
kill_fasync(&sfp->async_qp, SIGPOLL,
|
||||
POLL_HUP);
|
||||
}
|
||||
}
|
||||
SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d, dirty\n", sdp->index));
|
||||
if (NULL == sdp->headfp) {
|
||||
idr_remove(&sg_index_idr, sdp->index);
|
||||
}
|
||||
} else { /* nothing active, simple case */
|
||||
SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d\n", sdp->index));
|
||||
idr_remove(&sg_index_idr, sdp->index);
|
||||
sdp->detached = 1;
|
||||
list_for_each_entry(sfp, &sdp->sfds, sfd_siblings) {
|
||||
wake_up_interruptible(&sfp->read_wait);
|
||||
kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP);
|
||||
}
|
||||
write_unlock_irqrestore(&sg_index_lock, iflags);
|
||||
|
||||
@ -1536,13 +1526,8 @@ sg_remove(struct device *cl_dev, struct class_interface *cl_intf)
|
||||
device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, sdp->index));
|
||||
cdev_del(sdp->cdev);
|
||||
sdp->cdev = NULL;
|
||||
put_disk(sdp->disk);
|
||||
sdp->disk = NULL;
|
||||
if (NULL == sdp->headfp)
|
||||
kfree(sdp);
|
||||
|
||||
if (delay)
|
||||
msleep(10); /* dirty detach so delay device destruction */
|
||||
sg_put_dev(sdp);
|
||||
}
|
||||
|
||||
module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR);
|
||||
@ -1736,8 +1721,8 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
|
||||
return -EFAULT;
|
||||
if (0 == blk_size)
|
||||
++blk_size; /* don't know why */
|
||||
/* round request up to next highest SG_SECTOR_SZ byte boundary */
|
||||
blk_size = (blk_size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK);
|
||||
/* round request up to next highest SG_SECTOR_SZ byte boundary */
|
||||
blk_size = ALIGN(blk_size, SG_SECTOR_SZ);
|
||||
SCSI_LOG_TIMEOUT(4, printk("sg_build_indirect: buff_size=%d, blk_size=%d\n",
|
||||
buff_size, blk_size));
|
||||
|
||||
@ -1939,22 +1924,6 @@ sg_get_rq_mark(Sg_fd * sfp, int pack_id)
|
||||
return resp;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SCSI_PROC_FS
|
||||
static Sg_request *
|
||||
sg_get_nth_request(Sg_fd * sfp, int nth)
|
||||
{
|
||||
Sg_request *resp;
|
||||
unsigned long iflags;
|
||||
int k;
|
||||
|
||||
read_lock_irqsave(&sfp->rq_list_lock, iflags);
|
||||
for (k = 0, resp = sfp->headrp; resp && (k < nth);
|
||||
++k, resp = resp->nextrp) ;
|
||||
read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
|
||||
return resp;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* always adds to end of list */
|
||||
static Sg_request *
|
||||
sg_add_request(Sg_fd * sfp)
|
||||
@ -2030,22 +1999,6 @@ sg_remove_request(Sg_fd * sfp, Sg_request * srp)
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SCSI_PROC_FS
|
||||
static Sg_fd *
|
||||
sg_get_nth_sfp(Sg_device * sdp, int nth)
|
||||
{
|
||||
Sg_fd *resp;
|
||||
unsigned long iflags;
|
||||
int k;
|
||||
|
||||
read_lock_irqsave(&sg_index_lock, iflags);
|
||||
for (k = 0, resp = sdp->headfp; resp && (k < nth);
|
||||
++k, resp = resp->nextfp) ;
|
||||
read_unlock_irqrestore(&sg_index_lock, iflags);
|
||||
return resp;
|
||||
}
|
||||
#endif
|
||||
|
||||
static Sg_fd *
|
||||
sg_add_sfp(Sg_device * sdp, int dev)
|
||||
{
|
||||
@ -2060,6 +2013,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
|
||||
init_waitqueue_head(&sfp->read_wait);
|
||||
rwlock_init(&sfp->rq_list_lock);
|
||||
|
||||
kref_init(&sfp->f_ref);
|
||||
sfp->timeout = SG_DEFAULT_TIMEOUT;
|
||||
sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER;
|
||||
sfp->force_packid = SG_DEF_FORCE_PACK_ID;
|
||||
@ -2069,14 +2023,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
|
||||
sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
|
||||
sfp->parentdp = sdp;
|
||||
write_lock_irqsave(&sg_index_lock, iflags);
|
||||
if (!sdp->headfp)
|
||||
sdp->headfp = sfp;
|
||||
else { /* add to tail of existing list */
|
||||
Sg_fd *pfp = sdp->headfp;
|
||||
while (pfp->nextfp)
|
||||
pfp = pfp->nextfp;
|
||||
pfp->nextfp = sfp;
|
||||
}
|
||||
list_add_tail(&sfp->sfd_siblings, &sdp->sfds);
|
||||
write_unlock_irqrestore(&sg_index_lock, iflags);
|
||||
SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp));
|
||||
if (unlikely(sg_big_buff != def_reserved_size))
|
||||
@ -2087,75 +2034,52 @@ sg_add_sfp(Sg_device * sdp, int dev)
|
||||
sg_build_reserve(sfp, bufflen);
|
||||
SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, k_use_sg=%d\n",
|
||||
sfp->reserve.bufflen, sfp->reserve.k_use_sg));
|
||||
|
||||
kref_get(&sdp->d_ref);
|
||||
__module_get(THIS_MODULE);
|
||||
return sfp;
|
||||
}
|
||||
|
||||
static void
|
||||
__sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
|
||||
static void sg_remove_sfp_usercontext(struct work_struct *work)
|
||||
{
|
||||
Sg_fd *fp;
|
||||
Sg_fd *prev_fp;
|
||||
struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work);
|
||||
struct sg_device *sdp = sfp->parentdp;
|
||||
|
||||
/* Cleanup any responses which were never read(). */
|
||||
while (sfp->headrp)
|
||||
sg_finish_rem_req(sfp->headrp);
|
||||
|
||||
prev_fp = sdp->headfp;
|
||||
if (sfp == prev_fp)
|
||||
sdp->headfp = prev_fp->nextfp;
|
||||
else {
|
||||
while ((fp = prev_fp->nextfp)) {
|
||||
if (sfp == fp) {
|
||||
prev_fp->nextfp = fp->nextfp;
|
||||
break;
|
||||
}
|
||||
prev_fp = fp;
|
||||
}
|
||||
}
|
||||
if (sfp->reserve.bufflen > 0) {
|
||||
SCSI_LOG_TIMEOUT(6,
|
||||
printk("__sg_remove_sfp: bufflen=%d, k_use_sg=%d\n",
|
||||
(int) sfp->reserve.bufflen, (int) sfp->reserve.k_use_sg));
|
||||
SCSI_LOG_TIMEOUT(6,
|
||||
printk("sg_remove_sfp: bufflen=%d, k_use_sg=%d\n",
|
||||
(int) sfp->reserve.bufflen,
|
||||
(int) sfp->reserve.k_use_sg));
|
||||
sg_remove_scat(&sfp->reserve);
|
||||
}
|
||||
sfp->parentdp = NULL;
|
||||
SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp: sfp=0x%p\n", sfp));
|
||||
|
||||
SCSI_LOG_TIMEOUT(6,
|
||||
printk("sg_remove_sfp: %s, sfp=0x%p\n",
|
||||
sdp->disk->disk_name,
|
||||
sfp));
|
||||
kfree(sfp);
|
||||
|
||||
scsi_device_put(sdp->device);
|
||||
sg_put_dev(sdp);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
/* Returns 0 in normal case, 1 when detached and sdp object removed */
|
||||
static int
|
||||
sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
|
||||
static void sg_remove_sfp(struct kref *kref)
|
||||
{
|
||||
Sg_request *srp;
|
||||
Sg_request *tsrp;
|
||||
int dirty = 0;
|
||||
int res = 0;
|
||||
struct sg_fd *sfp = container_of(kref, struct sg_fd, f_ref);
|
||||
struct sg_device *sdp = sfp->parentdp;
|
||||
unsigned long iflags;
|
||||
|
||||
for (srp = sfp->headrp; srp; srp = tsrp) {
|
||||
tsrp = srp->nextrp;
|
||||
if (sg_srp_done(srp, sfp))
|
||||
sg_finish_rem_req(srp);
|
||||
else
|
||||
++dirty;
|
||||
}
|
||||
if (0 == dirty) {
|
||||
unsigned long iflags;
|
||||
write_lock_irqsave(&sg_index_lock, iflags);
|
||||
list_del(&sfp->sfd_siblings);
|
||||
write_unlock_irqrestore(&sg_index_lock, iflags);
|
||||
wake_up_interruptible(&sdp->o_excl_wait);
|
||||
|
||||
write_lock_irqsave(&sg_index_lock, iflags);
|
||||
__sg_remove_sfp(sdp, sfp);
|
||||
if (sdp->detached && (NULL == sdp->headfp)) {
|
||||
idr_remove(&sg_index_idr, sdp->index);
|
||||
kfree(sdp);
|
||||
res = 1;
|
||||
}
|
||||
write_unlock_irqrestore(&sg_index_lock, iflags);
|
||||
} else {
|
||||
/* MOD_INC's to inhibit unloading sg and associated adapter driver */
|
||||
/* only bump the access_count if we actually succeeded in
|
||||
* throwing another counter on the host module */
|
||||
scsi_device_get(sdp->device); /* XXX: retval ignored? */
|
||||
sfp->closed = 1; /* flag dirty state on this fd */
|
||||
SCSI_LOG_TIMEOUT(1, printk("sg_remove_sfp: worrisome, %d writes pending\n",
|
||||
dirty));
|
||||
}
|
||||
return res;
|
||||
execute_in_process_context(sg_remove_sfp_usercontext, &sfp->ew);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2197,19 +2121,38 @@ sg_last_dev(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
static Sg_device *
|
||||
sg_get_dev(int dev)
|
||||
/* must be called with sg_index_lock held */
|
||||
static Sg_device *sg_lookup_dev(int dev)
|
||||
{
|
||||
Sg_device *sdp;
|
||||
unsigned long iflags;
|
||||
return idr_find(&sg_index_idr, dev);
|
||||
}
|
||||
|
||||
read_lock_irqsave(&sg_index_lock, iflags);
|
||||
sdp = idr_find(&sg_index_idr, dev);
|
||||
read_unlock_irqrestore(&sg_index_lock, iflags);
|
||||
static Sg_device *sg_get_dev(int dev)
|
||||
{
|
||||
struct sg_device *sdp;
|
||||
unsigned long flags;
|
||||
|
||||
read_lock_irqsave(&sg_index_lock, flags);
|
||||
sdp = sg_lookup_dev(dev);
|
||||
if (!sdp)
|
||||
sdp = ERR_PTR(-ENXIO);
|
||||
else if (sdp->detached) {
|
||||
/* If sdp->detached, then the refcount may already be 0, in
|
||||
* which case it would be a bug to do kref_get().
|
||||
*/
|
||||
sdp = ERR_PTR(-ENODEV);
|
||||
} else
|
||||
kref_get(&sdp->d_ref);
|
||||
read_unlock_irqrestore(&sg_index_lock, flags);
|
||||
|
||||
return sdp;
|
||||
}
|
||||
|
||||
static void sg_put_dev(struct sg_device *sdp)
|
||||
{
|
||||
kref_put(&sdp->d_ref, sg_device_destroy);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SCSI_PROC_FS
|
||||
|
||||
static struct proc_dir_entry *sg_proc_sgp = NULL;
|
||||
@ -2466,8 +2409,10 @@ static int sg_proc_seq_show_dev(struct seq_file *s, void *v)
|
||||
struct sg_proc_deviter * it = (struct sg_proc_deviter *) v;
|
||||
Sg_device *sdp;
|
||||
struct scsi_device *scsidp;
|
||||
unsigned long iflags;
|
||||
|
||||
sdp = it ? sg_get_dev(it->index) : NULL;
|
||||
read_lock_irqsave(&sg_index_lock, iflags);
|
||||
sdp = it ? sg_lookup_dev(it->index) : NULL;
|
||||
if (sdp && (scsidp = sdp->device) && (!sdp->detached))
|
||||
seq_printf(s, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
|
||||
scsidp->host->host_no, scsidp->channel,
|
||||
@ -2478,6 +2423,7 @@ static int sg_proc_seq_show_dev(struct seq_file *s, void *v)
|
||||
(int) scsi_device_online(scsidp));
|
||||
else
|
||||
seq_printf(s, "-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n");
|
||||
read_unlock_irqrestore(&sg_index_lock, iflags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2491,16 +2437,20 @@ static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v)
|
||||
struct sg_proc_deviter * it = (struct sg_proc_deviter *) v;
|
||||
Sg_device *sdp;
|
||||
struct scsi_device *scsidp;
|
||||
unsigned long iflags;
|
||||
|
||||
sdp = it ? sg_get_dev(it->index) : NULL;
|
||||
read_lock_irqsave(&sg_index_lock, iflags);
|
||||
sdp = it ? sg_lookup_dev(it->index) : NULL;
|
||||
if (sdp && (scsidp = sdp->device) && (!sdp->detached))
|
||||
seq_printf(s, "%8.8s\t%16.16s\t%4.4s\n",
|
||||
scsidp->vendor, scsidp->model, scsidp->rev);
|
||||
else
|
||||
seq_printf(s, "<no active device>\n");
|
||||
read_unlock_irqrestore(&sg_index_lock, iflags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* must be called while holding sg_index_lock */
|
||||
static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
|
||||
{
|
||||
int k, m, new_interface, blen, usg;
|
||||
@ -2510,9 +2460,12 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
|
||||
const char * cp;
|
||||
unsigned int ms;
|
||||
|
||||
for (k = 0; (fp = sg_get_nth_sfp(sdp, k)); ++k) {
|
||||
k = 0;
|
||||
list_for_each_entry(fp, &sdp->sfds, sfd_siblings) {
|
||||
k++;
|
||||
read_lock(&fp->rq_list_lock); /* irqs already disabled */
|
||||
seq_printf(s, " FD(%d): timeout=%dms bufflen=%d "
|
||||
"(res)sgat=%d low_dma=%d\n", k + 1,
|
||||
"(res)sgat=%d low_dma=%d\n", k,
|
||||
jiffies_to_msecs(fp->timeout),
|
||||
fp->reserve.bufflen,
|
||||
(int) fp->reserve.k_use_sg,
|
||||
@ -2520,7 +2473,9 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
|
||||
seq_printf(s, " cmd_q=%d f_packid=%d k_orphan=%d closed=%d\n",
|
||||
(int) fp->cmd_q, (int) fp->force_packid,
|
||||
(int) fp->keep_orphan, (int) fp->closed);
|
||||
for (m = 0; (srp = sg_get_nth_request(fp, m)); ++m) {
|
||||
for (m = 0, srp = fp->headrp;
|
||||
srp != NULL;
|
||||
++m, srp = srp->nextrp) {
|
||||
hp = &srp->header;
|
||||
new_interface = (hp->interface_id == '\0') ? 0 : 1;
|
||||
if (srp->res_used) {
|
||||
@ -2557,6 +2512,7 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
|
||||
}
|
||||
if (0 == m)
|
||||
seq_printf(s, " No requests active\n");
|
||||
read_unlock(&fp->rq_list_lock);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2569,39 +2525,34 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v)
|
||||
{
|
||||
struct sg_proc_deviter * it = (struct sg_proc_deviter *) v;
|
||||
Sg_device *sdp;
|
||||
unsigned long iflags;
|
||||
|
||||
if (it && (0 == it->index)) {
|
||||
seq_printf(s, "max_active_device=%d(origin 1)\n",
|
||||
(int)it->max);
|
||||
seq_printf(s, " def_reserved_size=%d\n", sg_big_buff);
|
||||
}
|
||||
sdp = it ? sg_get_dev(it->index) : NULL;
|
||||
if (sdp) {
|
||||
|
||||
read_lock_irqsave(&sg_index_lock, iflags);
|
||||
sdp = it ? sg_lookup_dev(it->index) : NULL;
|
||||
if (sdp && !list_empty(&sdp->sfds)) {
|
||||
struct scsi_device *scsidp = sdp->device;
|
||||
|
||||
if (NULL == scsidp) {
|
||||
seq_printf(s, "device %d detached ??\n",
|
||||
(int)it->index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sg_get_nth_sfp(sdp, 0)) {
|
||||
seq_printf(s, " >>> device=%s ",
|
||||
sdp->disk->disk_name);
|
||||
if (sdp->detached)
|
||||
seq_printf(s, "detached pending close ");
|
||||
else
|
||||
seq_printf
|
||||
(s, "scsi%d chan=%d id=%d lun=%d em=%d",
|
||||
scsidp->host->host_no,
|
||||
scsidp->channel, scsidp->id,
|
||||
scsidp->lun,
|
||||
scsidp->host->hostt->emulated);
|
||||
seq_printf(s, " sg_tablesize=%d excl=%d\n",
|
||||
sdp->sg_tablesize, sdp->exclude);
|
||||
}
|
||||
seq_printf(s, " >>> device=%s ", sdp->disk->disk_name);
|
||||
if (sdp->detached)
|
||||
seq_printf(s, "detached pending close ");
|
||||
else
|
||||
seq_printf
|
||||
(s, "scsi%d chan=%d id=%d lun=%d em=%d",
|
||||
scsidp->host->host_no,
|
||||
scsidp->channel, scsidp->id,
|
||||
scsidp->lun,
|
||||
scsidp->host->hostt->emulated);
|
||||
seq_printf(s, " sg_tablesize=%d excl=%d\n",
|
||||
sdp->sg_tablesize, sdp->exclude);
|
||||
sg_proc_debug_helper(s, sdp);
|
||||
}
|
||||
read_unlock_irqrestore(&sg_index_lock, iflags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -374,9 +374,9 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
|
||||
if (!debugging) { /* Abnormal conditions for tape */
|
||||
if (!cmdstatp->have_sense)
|
||||
printk(KERN_WARNING
|
||||
"%s: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
|
||||
name, result, suggestion(result),
|
||||
driver_byte(result) & DRIVER_MASK, host_byte(result));
|
||||
"%s: Error %x (driver bt 0x%x, host bt 0x%x).\n",
|
||||
name, result, driver_byte(result),
|
||||
host_byte(result));
|
||||
else if (cmdstatp->have_sense &&
|
||||
scode != NO_SENSE &&
|
||||
scode != RECOVERED_ERROR &&
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* SuperTrak EX Series Storage Controller driver for Linux
|
||||
*
|
||||
* Copyright (C) 2005, 2006 Promise Technology Inc.
|
||||
* Copyright (C) 2005-2009 Promise Technology Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -36,8 +36,8 @@
|
||||
#include <scsi/scsi_eh.h>
|
||||
|
||||
#define DRV_NAME "stex"
|
||||
#define ST_DRIVER_VERSION "3.6.0000.1"
|
||||
#define ST_VER_MAJOR 3
|
||||
#define ST_DRIVER_VERSION "4.6.0000.1"
|
||||
#define ST_VER_MAJOR 4
|
||||
#define ST_VER_MINOR 6
|
||||
#define ST_OEM 0
|
||||
#define ST_BUILD_VER 1
|
||||
@ -103,7 +103,7 @@ enum {
|
||||
MU_REQ_COUNT = (MU_MAX_REQUEST + 1),
|
||||
MU_STATUS_COUNT = (MU_MAX_REQUEST + 1),
|
||||
|
||||
STEX_CDB_LENGTH = MAX_COMMAND_SIZE,
|
||||
STEX_CDB_LENGTH = 16,
|
||||
REQ_VARIABLE_LEN = 1024,
|
||||
STATUS_VAR_LEN = 128,
|
||||
ST_CAN_QUEUE = MU_MAX_REQUEST,
|
||||
@ -114,15 +114,19 @@ enum {
|
||||
SG_CF_EOT = 0x80, /* end of table */
|
||||
SG_CF_64B = 0x40, /* 64 bit item */
|
||||
SG_CF_HOST = 0x20, /* sg in host memory */
|
||||
MSG_DATA_DIR_ND = 0,
|
||||
MSG_DATA_DIR_IN = 1,
|
||||
MSG_DATA_DIR_OUT = 2,
|
||||
|
||||
st_shasta = 0,
|
||||
st_vsc = 1,
|
||||
st_vsc1 = 2,
|
||||
st_yosemite = 3,
|
||||
st_seq = 4,
|
||||
|
||||
PASSTHRU_REQ_TYPE = 0x00000001,
|
||||
PASSTHRU_REQ_NO_WAKEUP = 0x00000100,
|
||||
ST_INTERNAL_TIMEOUT = 30,
|
||||
ST_INTERNAL_TIMEOUT = 180,
|
||||
|
||||
ST_TO_CMD = 0,
|
||||
ST_FROM_CMD = 1,
|
||||
@ -152,35 +156,6 @@ enum {
|
||||
ST_ADDITIONAL_MEM = 0x200000,
|
||||
};
|
||||
|
||||
/* SCSI inquiry data */
|
||||
typedef struct st_inq {
|
||||
u8 DeviceType :5;
|
||||
u8 DeviceTypeQualifier :3;
|
||||
u8 DeviceTypeModifier :7;
|
||||
u8 RemovableMedia :1;
|
||||
u8 Versions;
|
||||
u8 ResponseDataFormat :4;
|
||||
u8 HiSupport :1;
|
||||
u8 NormACA :1;
|
||||
u8 ReservedBit :1;
|
||||
u8 AERC :1;
|
||||
u8 AdditionalLength;
|
||||
u8 Reserved[2];
|
||||
u8 SoftReset :1;
|
||||
u8 CommandQueue :1;
|
||||
u8 Reserved2 :1;
|
||||
u8 LinkedCommands :1;
|
||||
u8 Synchronous :1;
|
||||
u8 Wide16Bit :1;
|
||||
u8 Wide32Bit :1;
|
||||
u8 RelativeAddressing :1;
|
||||
u8 VendorId[8];
|
||||
u8 ProductId[16];
|
||||
u8 ProductRevisionLevel[4];
|
||||
u8 VendorSpecific[20];
|
||||
u8 Reserved3[40];
|
||||
} ST_INQ;
|
||||
|
||||
struct st_sgitem {
|
||||
u8 ctrl; /* SG_CF_xxx */
|
||||
u8 reserved[3];
|
||||
@ -222,7 +197,7 @@ struct req_msg {
|
||||
u8 target;
|
||||
u8 task_attr;
|
||||
u8 task_manage;
|
||||
u8 prd_entry;
|
||||
u8 data_dir;
|
||||
u8 payload_sz; /* payload size in 4-byte, not used */
|
||||
u8 cdb[STEX_CDB_LENGTH];
|
||||
u8 variable[REQ_VARIABLE_LEN];
|
||||
@ -284,7 +259,7 @@ struct st_drvver {
|
||||
#define MU_REQ_BUFFER_SIZE (MU_REQ_COUNT * sizeof(struct req_msg))
|
||||
#define MU_STATUS_BUFFER_SIZE (MU_STATUS_COUNT * sizeof(struct status_msg))
|
||||
#define MU_BUFFER_SIZE (MU_REQ_BUFFER_SIZE + MU_STATUS_BUFFER_SIZE)
|
||||
#define STEX_EXTRA_SIZE max(sizeof(struct st_frame), sizeof(ST_INQ))
|
||||
#define STEX_EXTRA_SIZE sizeof(struct st_frame)
|
||||
#define STEX_BUFFER_SIZE (MU_BUFFER_SIZE + STEX_EXTRA_SIZE)
|
||||
|
||||
struct st_ccb {
|
||||
@ -346,8 +321,8 @@ MODULE_VERSION(ST_DRIVER_VERSION);
|
||||
static void stex_gettime(__le32 *time)
|
||||
{
|
||||
struct timeval tv;
|
||||
do_gettimeofday(&tv);
|
||||
|
||||
do_gettimeofday(&tv);
|
||||
*time = cpu_to_le32(tv.tv_sec & 0xffffffff);
|
||||
*(time + 1) = cpu_to_le32((tv.tv_sec >> 16) >> 16);
|
||||
}
|
||||
@ -368,7 +343,7 @@ static void stex_invalid_field(struct scsi_cmnd *cmd,
|
||||
{
|
||||
cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
|
||||
|
||||
/* "Invalid field in cbd" */
|
||||
/* "Invalid field in cdb" */
|
||||
scsi_build_sense_buffer(0, cmd->sense_buffer, ILLEGAL_REQUEST, 0x24,
|
||||
0x0);
|
||||
done(cmd);
|
||||
@ -497,6 +472,7 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
|
||||
unsigned int id,lun;
|
||||
struct req_msg *req;
|
||||
u16 tag;
|
||||
|
||||
host = cmd->device->host;
|
||||
id = cmd->device->id;
|
||||
lun = cmd->device->lun;
|
||||
@ -508,6 +484,7 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
|
||||
static char ms10_caching_page[12] =
|
||||
{ 0, 0x12, 0, 0, 0, 0, 0, 0, 0x8, 0xa, 0x4, 0 };
|
||||
unsigned char page;
|
||||
|
||||
page = cmd->cmnd[2] & 0x3f;
|
||||
if (page == 0x8 || page == 0x3f) {
|
||||
scsi_sg_copy_from_buffer(cmd, ms10_caching_page,
|
||||
@ -551,6 +528,7 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
|
||||
if (cmd->cmnd[1] == PASSTHRU_GET_DRVVER) {
|
||||
struct st_drvver ver;
|
||||
size_t cp_len = sizeof(ver);
|
||||
|
||||
ver.major = ST_VER_MAJOR;
|
||||
ver.minor = ST_VER_MINOR;
|
||||
ver.oem = ST_OEM;
|
||||
@ -584,6 +562,13 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
|
||||
/* cdb */
|
||||
memcpy(req->cdb, cmd->cmnd, STEX_CDB_LENGTH);
|
||||
|
||||
if (cmd->sc_data_direction == DMA_FROM_DEVICE)
|
||||
req->data_dir = MSG_DATA_DIR_IN;
|
||||
else if (cmd->sc_data_direction == DMA_TO_DEVICE)
|
||||
req->data_dir = MSG_DATA_DIR_OUT;
|
||||
else
|
||||
req->data_dir = MSG_DATA_DIR_ND;
|
||||
|
||||
hba->ccb[tag].cmd = cmd;
|
||||
hba->ccb[tag].sense_bufflen = SCSI_SENSE_BUFFERSIZE;
|
||||
hba->ccb[tag].sense_buffer = cmd->sense_buffer;
|
||||
@ -642,6 +627,7 @@ static void stex_copy_data(struct st_ccb *ccb,
|
||||
struct status_msg *resp, unsigned int variable)
|
||||
{
|
||||
size_t count = variable;
|
||||
|
||||
if (resp->scsi_status != SAM_STAT_GOOD) {
|
||||
if (ccb->sense_buffer != NULL)
|
||||
memcpy(ccb->sense_buffer, resp->variable,
|
||||
@ -661,24 +647,6 @@ static void stex_ys_commands(struct st_hba *hba,
|
||||
resp->scsi_status != SAM_STAT_CHECK_CONDITION) {
|
||||
scsi_set_resid(ccb->cmd, scsi_bufflen(ccb->cmd) -
|
||||
le32_to_cpu(*(__le32 *)&resp->variable[0]));
|
||||
return;
|
||||
}
|
||||
|
||||
if (resp->srb_status != 0)
|
||||
return;
|
||||
|
||||
/* determine inquiry command status by DeviceTypeQualifier */
|
||||
if (ccb->cmd->cmnd[0] == INQUIRY &&
|
||||
resp->scsi_status == SAM_STAT_GOOD) {
|
||||
ST_INQ *inq_data;
|
||||
|
||||
scsi_sg_copy_to_buffer(ccb->cmd, hba->copy_buffer,
|
||||
STEX_EXTRA_SIZE);
|
||||
inq_data = (ST_INQ *)hba->copy_buffer;
|
||||
if (inq_data->DeviceTypeQualifier != 0)
|
||||
ccb->srb_status = SRB_STATUS_SELECTION_TIMEOUT;
|
||||
else
|
||||
ccb->srb_status = SRB_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@ -746,6 +714,7 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
|
||||
stex_copy_data(ccb, resp, size);
|
||||
}
|
||||
|
||||
ccb->req = NULL;
|
||||
ccb->srb_status = resp->srb_status;
|
||||
ccb->scsi_status = resp->scsi_status;
|
||||
|
||||
@ -983,6 +952,7 @@ static int stex_reset(struct scsi_cmnd *cmd)
|
||||
struct st_hba *hba;
|
||||
unsigned long flags;
|
||||
unsigned long before;
|
||||
|
||||
hba = (struct st_hba *) &cmd->device->host->hostdata[0];
|
||||
|
||||
printk(KERN_INFO DRV_NAME
|
||||
@ -1067,6 +1037,7 @@ static struct scsi_host_template driver_template = {
|
||||
static int stex_set_dma_mask(struct pci_dev * pdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)
|
||||
&& !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
|
||||
return 0;
|
||||
@ -1124,9 +1095,9 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
}
|
||||
|
||||
hba->cardtype = (unsigned int) id->driver_data;
|
||||
if (hba->cardtype == st_vsc && (pdev->subsystem_device & 0xf) == 0x1)
|
||||
if (hba->cardtype == st_vsc && (pdev->subsystem_device & 1))
|
||||
hba->cardtype = st_vsc1;
|
||||
hba->dma_size = (hba->cardtype == st_vsc1) ?
|
||||
hba->dma_size = (hba->cardtype == st_vsc1 || hba->cardtype == st_seq) ?
|
||||
(STEX_BUFFER_SIZE + ST_ADDITIONAL_MEM) : (STEX_BUFFER_SIZE);
|
||||
hba->dma_mem = dma_alloc_coherent(&pdev->dev,
|
||||
hba->dma_size, &hba->dma_handle, GFP_KERNEL);
|
||||
@ -1146,10 +1117,10 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
host->max_lun = 8;
|
||||
host->max_id = 16 + 1;
|
||||
} else if (hba->cardtype == st_yosemite) {
|
||||
host->max_lun = 128;
|
||||
host->max_lun = 256;
|
||||
host->max_id = 1 + 1;
|
||||
} else {
|
||||
/* st_vsc and st_vsc1 */
|
||||
/* st_vsc , st_vsc1 and st_seq */
|
||||
host->max_lun = 1;
|
||||
host->max_id = 128 + 1;
|
||||
}
|
||||
@ -1299,18 +1270,10 @@ static struct pci_device_id stex_pci_tbl[] = {
|
||||
{ 0x105a, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc },
|
||||
|
||||
/* st_yosemite */
|
||||
{ 0x105a, 0x8650, PCI_ANY_ID, 0x4600, 0, 0,
|
||||
st_yosemite }, /* SuperTrak EX4650 */
|
||||
{ 0x105a, 0x8650, PCI_ANY_ID, 0x4610, 0, 0,
|
||||
st_yosemite }, /* SuperTrak EX4650o */
|
||||
{ 0x105a, 0x8650, PCI_ANY_ID, 0x8600, 0, 0,
|
||||
st_yosemite }, /* SuperTrak EX8650EL */
|
||||
{ 0x105a, 0x8650, PCI_ANY_ID, 0x8601, 0, 0,
|
||||
st_yosemite }, /* SuperTrak EX8650 */
|
||||
{ 0x105a, 0x8650, PCI_ANY_ID, 0x8602, 0, 0,
|
||||
st_yosemite }, /* SuperTrak EX8654 */
|
||||
{ 0x105a, 0x8650, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
st_yosemite }, /* generic st_yosemite */
|
||||
{ 0x105a, 0x8650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_yosemite },
|
||||
|
||||
/* st_seq */
|
||||
{ 0x105a, 0x3360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_seq },
|
||||
{ } /* terminate list */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, stex_pci_tbl);
|
||||
|
@ -792,9 +792,9 @@ static int sym53c8xx_slave_configure(struct scsi_device *sdev)
|
||||
|
||||
/*
|
||||
* Select queue depth from driver setup.
|
||||
* Donnot use more than configured by user.
|
||||
* Use at least 2.
|
||||
* Donnot use more than our maximum.
|
||||
* Do not use more than configured by user.
|
||||
* Use at least 1.
|
||||
* Do not use more than our maximum.
|
||||
*/
|
||||
reqtags = sym_driver_setup.max_tag;
|
||||
if (reqtags > tp->usrtags)
|
||||
@ -803,7 +803,7 @@ static int sym53c8xx_slave_configure(struct scsi_device *sdev)
|
||||
reqtags = 0;
|
||||
if (reqtags > SYM_CONF_MAX_TAG)
|
||||
reqtags = SYM_CONF_MAX_TAG;
|
||||
depth_to_use = reqtags ? reqtags : 2;
|
||||
depth_to_use = reqtags ? reqtags : 1;
|
||||
scsi_adjust_queue_depth(sdev,
|
||||
sdev->tagged_supported ? MSG_SIMPLE_TAG : 0,
|
||||
depth_to_use);
|
||||
@ -1235,15 +1235,30 @@ static int sym53c8xx_proc_info(struct Scsi_Host *shost, char *buffer,
|
||||
}
|
||||
#endif /* SYM_LINUX_PROC_INFO_SUPPORT */
|
||||
|
||||
/*
|
||||
* Free resources claimed by sym_iomap_device(). Note that
|
||||
* sym_free_resources() should be used instead of this function after calling
|
||||
* sym_attach().
|
||||
*/
|
||||
static void __devinit
|
||||
sym_iounmap_device(struct sym_device *device)
|
||||
{
|
||||
if (device->s.ioaddr)
|
||||
pci_iounmap(device->pdev, device->s.ioaddr);
|
||||
if (device->s.ramaddr)
|
||||
pci_iounmap(device->pdev, device->s.ramaddr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free controller resources.
|
||||
*/
|
||||
static void sym_free_resources(struct sym_hcb *np, struct pci_dev *pdev)
|
||||
static void sym_free_resources(struct sym_hcb *np, struct pci_dev *pdev,
|
||||
int do_free_irq)
|
||||
{
|
||||
/*
|
||||
* Free O/S specific resources.
|
||||
*/
|
||||
if (pdev->irq)
|
||||
if (do_free_irq)
|
||||
free_irq(pdev->irq, np->s.host);
|
||||
if (np->s.ioaddr)
|
||||
pci_iounmap(pdev, np->s.ioaddr);
|
||||
@ -1271,10 +1286,11 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
|
||||
{
|
||||
struct sym_data *sym_data;
|
||||
struct sym_hcb *np = NULL;
|
||||
struct Scsi_Host *shost;
|
||||
struct Scsi_Host *shost = NULL;
|
||||
struct pci_dev *pdev = dev->pdev;
|
||||
unsigned long flags;
|
||||
struct sym_fw *fw;
|
||||
int do_free_irq = 0;
|
||||
|
||||
printk(KERN_INFO "sym%d: <%s> rev 0x%x at pci %s irq %u\n",
|
||||
unit, dev->chip.name, pdev->revision, pci_name(pdev),
|
||||
@ -1285,11 +1301,11 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
|
||||
*/
|
||||
fw = sym_find_firmware(&dev->chip);
|
||||
if (!fw)
|
||||
return NULL;
|
||||
goto attach_failed;
|
||||
|
||||
shost = scsi_host_alloc(tpnt, sizeof(*sym_data));
|
||||
if (!shost)
|
||||
return NULL;
|
||||
goto attach_failed;
|
||||
sym_data = shost_priv(shost);
|
||||
|
||||
/*
|
||||
@ -1319,6 +1335,10 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
|
||||
np->maxoffs = dev->chip.offset_max;
|
||||
np->maxburst = dev->chip.burst_max;
|
||||
np->myaddr = dev->host_id;
|
||||
np->mmio_ba = (u32)dev->mmio_base;
|
||||
np->ram_ba = (u32)dev->ram_base;
|
||||
np->s.ioaddr = dev->s.ioaddr;
|
||||
np->s.ramaddr = dev->s.ramaddr;
|
||||
|
||||
/*
|
||||
* Edit its name.
|
||||
@ -1334,22 +1354,6 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
|
||||
goto attach_failed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to map the controller chip to
|
||||
* virtual and physical memory.
|
||||
*/
|
||||
np->mmio_ba = (u32)dev->mmio_base;
|
||||
np->s.ioaddr = dev->s.ioaddr;
|
||||
np->s.ramaddr = dev->s.ramaddr;
|
||||
|
||||
/*
|
||||
* Map on-chip RAM if present and supported.
|
||||
*/
|
||||
if (!(np->features & FE_RAM))
|
||||
dev->ram_base = 0;
|
||||
if (dev->ram_base)
|
||||
np->ram_ba = (u32)dev->ram_base;
|
||||
|
||||
if (sym_hcb_attach(shost, fw, dev->nvram))
|
||||
goto attach_failed;
|
||||
|
||||
@ -1364,6 +1368,7 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
|
||||
sym_name(np), pdev->irq);
|
||||
goto attach_failed;
|
||||
}
|
||||
do_free_irq = 1;
|
||||
|
||||
/*
|
||||
* After SCSI devices have been opened, we cannot
|
||||
@ -1416,12 +1421,13 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
|
||||
"TERMINATION, DEVICE POWER etc.!\n", sym_name(np));
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
attach_failed:
|
||||
if (!shost)
|
||||
return NULL;
|
||||
printf_info("%s: giving up ...\n", sym_name(np));
|
||||
printf_info("sym%d: giving up ...\n", unit);
|
||||
if (np)
|
||||
sym_free_resources(np, pdev);
|
||||
scsi_host_put(shost);
|
||||
sym_free_resources(np, pdev, do_free_irq);
|
||||
else
|
||||
sym_iounmap_device(dev);
|
||||
if (shost)
|
||||
scsi_host_put(shost);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -1550,30 +1556,28 @@ static int __devinit sym_set_workarounds(struct sym_device *device)
|
||||
}
|
||||
|
||||
/*
|
||||
* Read and check the PCI configuration for any detected NCR
|
||||
* boards and save data for attaching after all boards have
|
||||
* been detected.
|
||||
* Map HBA registers and on-chip SRAM (if present).
|
||||
*/
|
||||
static void __devinit
|
||||
sym_init_device(struct pci_dev *pdev, struct sym_device *device)
|
||||
static int __devinit
|
||||
sym_iomap_device(struct sym_device *device)
|
||||
{
|
||||
int i = 2;
|
||||
struct pci_dev *pdev = device->pdev;
|
||||
struct pci_bus_region bus_addr;
|
||||
|
||||
device->host_id = SYM_SETUP_HOST_ID;
|
||||
device->pdev = pdev;
|
||||
int i = 2;
|
||||
|
||||
pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[1]);
|
||||
device->mmio_base = bus_addr.start;
|
||||
|
||||
/*
|
||||
* If the BAR is 64-bit, resource 2 will be occupied by the
|
||||
* upper 32 bits
|
||||
*/
|
||||
if (!pdev->resource[i].flags)
|
||||
i++;
|
||||
pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[i]);
|
||||
device->ram_base = bus_addr.start;
|
||||
if (device->chip.features & FE_RAM) {
|
||||
/*
|
||||
* If the BAR is 64-bit, resource 2 will be occupied by the
|
||||
* upper 32 bits
|
||||
*/
|
||||
if (!pdev->resource[i].flags)
|
||||
i++;
|
||||
pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[i]);
|
||||
device->ram_base = bus_addr.start;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SCSI_SYM53C8XX_MMIO
|
||||
if (device->mmio_base)
|
||||
@ -1583,9 +1587,21 @@ sym_init_device(struct pci_dev *pdev, struct sym_device *device)
|
||||
if (!device->s.ioaddr)
|
||||
device->s.ioaddr = pci_iomap(pdev, 0,
|
||||
pci_resource_len(pdev, 0));
|
||||
if (device->ram_base)
|
||||
if (!device->s.ioaddr) {
|
||||
dev_err(&pdev->dev, "could not map registers; giving up.\n");
|
||||
return -EIO;
|
||||
}
|
||||
if (device->ram_base) {
|
||||
device->s.ramaddr = pci_iomap(pdev, i,
|
||||
pci_resource_len(pdev, i));
|
||||
if (!device->s.ramaddr) {
|
||||
dev_warn(&pdev->dev,
|
||||
"could not map SRAM; continuing anyway.\n");
|
||||
device->ram_base = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1659,7 +1675,8 @@ static int sym_detach(struct Scsi_Host *shost, struct pci_dev *pdev)
|
||||
udelay(10);
|
||||
OUTB(np, nc_istat, 0);
|
||||
|
||||
sym_free_resources(np, pdev);
|
||||
sym_free_resources(np, pdev, 1);
|
||||
scsi_host_put(shost);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -1696,9 +1713,13 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
|
||||
struct sym_device sym_dev;
|
||||
struct sym_nvram nvram;
|
||||
struct Scsi_Host *shost;
|
||||
int do_iounmap = 0;
|
||||
int do_disable_device = 1;
|
||||
|
||||
memset(&sym_dev, 0, sizeof(sym_dev));
|
||||
memset(&nvram, 0, sizeof(nvram));
|
||||
sym_dev.pdev = pdev;
|
||||
sym_dev.host_id = SYM_SETUP_HOST_ID;
|
||||
|
||||
if (pci_enable_device(pdev))
|
||||
goto leave;
|
||||
@ -1708,12 +1729,17 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
|
||||
if (pci_request_regions(pdev, NAME53C8XX))
|
||||
goto disable;
|
||||
|
||||
sym_init_device(pdev, &sym_dev);
|
||||
if (sym_check_supported(&sym_dev))
|
||||
goto free;
|
||||
|
||||
if (sym_check_raid(&sym_dev))
|
||||
goto leave; /* Don't disable the device */
|
||||
if (sym_iomap_device(&sym_dev))
|
||||
goto free;
|
||||
do_iounmap = 1;
|
||||
|
||||
if (sym_check_raid(&sym_dev)) {
|
||||
do_disable_device = 0; /* Don't disable the device */
|
||||
goto free;
|
||||
}
|
||||
|
||||
if (sym_set_workarounds(&sym_dev))
|
||||
goto free;
|
||||
@ -1722,6 +1748,7 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
|
||||
|
||||
sym_get_nvram(&sym_dev, &nvram);
|
||||
|
||||
do_iounmap = 0; /* Don't sym_iounmap_device() after sym_attach(). */
|
||||
shost = sym_attach(&sym2_template, attach_count, &sym_dev);
|
||||
if (!shost)
|
||||
goto free;
|
||||
@ -1737,9 +1764,12 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
|
||||
detach:
|
||||
sym_detach(pci_get_drvdata(pdev), pdev);
|
||||
free:
|
||||
if (do_iounmap)
|
||||
sym_iounmap_device(&sym_dev);
|
||||
pci_release_regions(pdev);
|
||||
disable:
|
||||
pci_disable_device(pdev);
|
||||
if (do_disable_device)
|
||||
pci_disable_device(pdev);
|
||||
leave:
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -1749,7 +1779,6 @@ static void sym2_remove(struct pci_dev *pdev)
|
||||
struct Scsi_Host *shost = pci_get_drvdata(pdev);
|
||||
|
||||
scsi_remove_host(shost);
|
||||
scsi_host_put(shost);
|
||||
sym_detach(shost, pdev);
|
||||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
|
@ -1433,13 +1433,12 @@ static int sym_prepare_nego(struct sym_hcb *np, struct sym_ccb *cp, u_char *msgp
|
||||
* Many devices implement PPR in a buggy way, so only use it if we
|
||||
* really want to.
|
||||
*/
|
||||
if (goal->offset &&
|
||||
(goal->iu || goal->dt || goal->qas || (goal->period < 0xa))) {
|
||||
if (goal->renego == NS_PPR || (goal->offset &&
|
||||
(goal->iu || goal->dt || goal->qas || (goal->period < 0xa)))) {
|
||||
nego = NS_PPR;
|
||||
} else if (spi_width(starget) != goal->width) {
|
||||
} else if (goal->renego == NS_WIDE || goal->width) {
|
||||
nego = NS_WIDE;
|
||||
} else if (spi_period(starget) != goal->period ||
|
||||
spi_offset(starget) != goal->offset) {
|
||||
} else if (goal->renego == NS_SYNC || goal->offset) {
|
||||
nego = NS_SYNC;
|
||||
} else {
|
||||
goal->check_nego = 0;
|
||||
@ -2040,6 +2039,29 @@ static void sym_settrans(struct sym_hcb *np, int target, u_char opts, u_char ofs
|
||||
}
|
||||
}
|
||||
|
||||
static void sym_announce_transfer_rate(struct sym_tcb *tp)
|
||||
{
|
||||
struct scsi_target *starget = tp->starget;
|
||||
|
||||
if (tp->tprint.period != spi_period(starget) ||
|
||||
tp->tprint.offset != spi_offset(starget) ||
|
||||
tp->tprint.width != spi_width(starget) ||
|
||||
tp->tprint.iu != spi_iu(starget) ||
|
||||
tp->tprint.dt != spi_dt(starget) ||
|
||||
tp->tprint.qas != spi_qas(starget) ||
|
||||
!tp->tprint.check_nego) {
|
||||
tp->tprint.period = spi_period(starget);
|
||||
tp->tprint.offset = spi_offset(starget);
|
||||
tp->tprint.width = spi_width(starget);
|
||||
tp->tprint.iu = spi_iu(starget);
|
||||
tp->tprint.dt = spi_dt(starget);
|
||||
tp->tprint.qas = spi_qas(starget);
|
||||
tp->tprint.check_nego = 1;
|
||||
|
||||
spi_display_xfer_agreement(starget);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We received a WDTR.
|
||||
* Let everything be aware of the changes.
|
||||
@ -2049,11 +2071,13 @@ static void sym_setwide(struct sym_hcb *np, int target, u_char wide)
|
||||
struct sym_tcb *tp = &np->target[target];
|
||||
struct scsi_target *starget = tp->starget;
|
||||
|
||||
if (spi_width(starget) == wide)
|
||||
return;
|
||||
|
||||
sym_settrans(np, target, 0, 0, 0, wide, 0, 0);
|
||||
|
||||
if (wide)
|
||||
tp->tgoal.renego = NS_WIDE;
|
||||
else
|
||||
tp->tgoal.renego = 0;
|
||||
tp->tgoal.check_nego = 0;
|
||||
tp->tgoal.width = wide;
|
||||
spi_offset(starget) = 0;
|
||||
spi_period(starget) = 0;
|
||||
@ -2063,7 +2087,7 @@ static void sym_setwide(struct sym_hcb *np, int target, u_char wide)
|
||||
spi_qas(starget) = 0;
|
||||
|
||||
if (sym_verbose >= 3)
|
||||
spi_display_xfer_agreement(starget);
|
||||
sym_announce_transfer_rate(tp);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2080,6 +2104,12 @@ sym_setsync(struct sym_hcb *np, int target,
|
||||
|
||||
sym_settrans(np, target, 0, ofs, per, wide, div, fak);
|
||||
|
||||
if (wide)
|
||||
tp->tgoal.renego = NS_WIDE;
|
||||
else if (ofs)
|
||||
tp->tgoal.renego = NS_SYNC;
|
||||
else
|
||||
tp->tgoal.renego = 0;
|
||||
spi_period(starget) = per;
|
||||
spi_offset(starget) = ofs;
|
||||
spi_iu(starget) = spi_dt(starget) = spi_qas(starget) = 0;
|
||||
@ -2090,7 +2120,7 @@ sym_setsync(struct sym_hcb *np, int target,
|
||||
tp->tgoal.check_nego = 0;
|
||||
}
|
||||
|
||||
spi_display_xfer_agreement(starget);
|
||||
sym_announce_transfer_rate(tp);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2106,6 +2136,10 @@ sym_setpprot(struct sym_hcb *np, int target, u_char opts, u_char ofs,
|
||||
|
||||
sym_settrans(np, target, opts, ofs, per, wide, div, fak);
|
||||
|
||||
if (wide || ofs)
|
||||
tp->tgoal.renego = NS_PPR;
|
||||
else
|
||||
tp->tgoal.renego = 0;
|
||||
spi_width(starget) = tp->tgoal.width = wide;
|
||||
spi_period(starget) = tp->tgoal.period = per;
|
||||
spi_offset(starget) = tp->tgoal.offset = ofs;
|
||||
@ -2114,7 +2148,7 @@ sym_setpprot(struct sym_hcb *np, int target, u_char opts, u_char ofs,
|
||||
spi_qas(starget) = tp->tgoal.qas = !!(opts & PPR_OPT_QAS);
|
||||
tp->tgoal.check_nego = 0;
|
||||
|
||||
spi_display_xfer_agreement(starget);
|
||||
sym_announce_transfer_rate(tp);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3516,6 +3550,7 @@ static void sym_sir_task_recovery(struct sym_hcb *np, int num)
|
||||
spi_dt(starget) = 0;
|
||||
spi_qas(starget) = 0;
|
||||
tp->tgoal.check_nego = 1;
|
||||
tp->tgoal.renego = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -5135,9 +5170,14 @@ int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *
|
||||
/*
|
||||
* Build a negotiation message if needed.
|
||||
* (nego_status is filled by sym_prepare_nego())
|
||||
*
|
||||
* Always negotiate on INQUIRY and REQUEST SENSE.
|
||||
*
|
||||
*/
|
||||
cp->nego_status = 0;
|
||||
if (tp->tgoal.check_nego && !tp->nego_cp && lp) {
|
||||
if ((tp->tgoal.check_nego ||
|
||||
cmd->cmnd[0] == INQUIRY || cmd->cmnd[0] == REQUEST_SENSE) &&
|
||||
!tp->nego_cp && lp) {
|
||||
msglen += sym_prepare_nego(np, cp, msgptr + msglen);
|
||||
}
|
||||
|
||||
|
@ -354,6 +354,7 @@ struct sym_trans {
|
||||
unsigned int dt:1;
|
||||
unsigned int qas:1;
|
||||
unsigned int check_nego:1;
|
||||
unsigned int renego:2;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -419,6 +420,9 @@ struct sym_tcb {
|
||||
/* Transfer goal */
|
||||
struct sym_trans tgoal;
|
||||
|
||||
/* Last printed transfer speed */
|
||||
struct sym_trans tprint;
|
||||
|
||||
/*
|
||||
* Keep track of the CCB used for the negotiation in order
|
||||
* to ensure that only 1 negotiation is queued at a time.
|
||||
|
@ -787,7 +787,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
|
||||
/* Did we transfer less than the minimum amount required? */
|
||||
if ((srb->result == SAM_STAT_GOOD || srb->sense_buffer[2] == 0) &&
|
||||
scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow)
|
||||
srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24);
|
||||
srb->result = DID_ERROR << 16;
|
||||
|
||||
last_sector_hacks(us, srb);
|
||||
return;
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef BSG_H
|
||||
#define BSG_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define BSG_PROTOCOL_SCSI 0
|
||||
|
||||
#define BSG_SUB_PROTOCOL_SCSI_CMD 0
|
||||
|
@ -78,6 +78,7 @@
|
||||
#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
|
||||
#define ETH_P_AOE 0x88A2 /* ATA over Ethernet */
|
||||
#define ETH_P_TIPC 0x88CA /* TIPC */
|
||||
#define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */
|
||||
#define ETH_P_EDSA 0xDADA /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
|
||||
|
||||
/*
|
||||
|
@ -171,5 +171,6 @@
|
||||
#define VIOTAPE_MAJOR 230
|
||||
|
||||
#define BLOCK_EXT_MAJOR 259
|
||||
#define SCSI_OSD_MAJOR 260 /* open-osd's OSD scsi device */
|
||||
|
||||
#endif
|
||||
|
@ -26,6 +26,7 @@
|
||||
#define TUN_MINOR 200
|
||||
#define MWAVE_MINOR 219 /* ACP/Mwave Modem */
|
||||
#define MPT_MINOR 220
|
||||
#define MPT2SAS_MINOR 221
|
||||
#define HPET_MINOR 228
|
||||
#define FUSE_MINOR 229
|
||||
#define KVM_MINOR 232
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user