Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
xcap
xcap-capability-linux
Commits
38a9a621
Commit
38a9a621
authored
Oct 28, 2005
by
James Bottomley
Browse files
Options
Browse Files
Download
Plain Diff
Merge HEAD from ../scsi-misc-2.6-old
parents
27d1097d
e75d5176
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
6095 additions
and
443 deletions
+6095
-443
drivers/scsi/Kconfig
drivers/scsi/Kconfig
+25
-1
drivers/scsi/Makefile
drivers/scsi/Makefile
+1
-0
drivers/scsi/aacraid/aachba.c
drivers/scsi/aacraid/aachba.c
+42
-15
drivers/scsi/aacraid/aacraid.h
drivers/scsi/aacraid/aacraid.h
+1
-1
drivers/scsi/aacraid/commctrl.c
drivers/scsi/aacraid/commctrl.c
+3
-3
drivers/scsi/aacraid/linit.c
drivers/scsi/aacraid/linit.c
+5
-5
drivers/scsi/dc395x.c
drivers/scsi/dc395x.c
+13
-0
drivers/scsi/iscsi_tcp.c
drivers/scsi/iscsi_tcp.c
+3642
-0
drivers/scsi/iscsi_tcp.h
drivers/scsi/iscsi_tcp.h
+322
-0
drivers/scsi/ncr53c8xx.c
drivers/scsi/ncr53c8xx.c
+11
-11
drivers/scsi/scsi_transport_iscsi.c
drivers/scsi/scsi_transport_iscsi.c
+1133
-247
drivers/scsi/sym53c8xx_defs.h
drivers/scsi/sym53c8xx_defs.h
+0
-13
drivers/scsi/tmscsim.c
drivers/scsi/tmscsim.c
+8
-0
include/scsi/iscsi_if.h
include/scsi/iscsi_if.h
+245
-0
include/scsi/iscsi_proto.h
include/scsi/iscsi_proto.h
+589
-0
include/scsi/scsi_transport_iscsi.h
include/scsi/scsi_transport_iscsi.h
+55
-147
No files found.
drivers/scsi/Kconfig
View file @
38a9a621
...
...
@@ -229,7 +229,7 @@ config SCSI_FC_ATTRS
config
SCSI_ISCSI_ATTRS
tristate
"iSCSI Transport Attributes"
depends
on
SCSI
depends
on
SCSI
&&
NET
help
If
you
wish
to
export
transport
-
specific
information
about
each
attached
iSCSI
device
to
sysfs
,
say
Y
.
...
...
@@ -247,6 +247,30 @@ endmenu
menu
"SCSI low-level drivers"
depends
on
SCSI
!=n
config
ISCSI_TCP
tristate
"iSCSI Initiator over TCP/IP"
depends
on
SCSI
&&
INET
select
CRYPTO
select
CRYPTO_MD5
select
CRYPTO_CRC32C
select
SCSI_ISCSI_ATTRS
help
The
iSCSI
Driver
provides
a
host
with
the
ability
to
access
storage
through
an
IP
network
.
The
driver
uses
the
iSCSI
protocol
to
transport
SCSI
requests
and
responses
over
a
TCP
/
IP
network
between
the
host
(
the
"initiator"
)
and
"targets"
.
Architecturally
,
the
iSCSI
driver
combines
with
the
host
's TCP/IP stack, network drivers, and Network
Interface Card (NIC) to provide the same functions as a SCSI or a
Fibre Channel (FC) adapter driver with a Host Bus Adapter (HBA).
To compile this driver as a module, choose M here: the
module will be called iscsi_tcp.
The userspace component needed to initialize the driver, documentation,
and sample configuration files can be found here:
http://linux-iscsi.sf.net
config SGIWD93_SCSI
tristate "SGI WD93C93 SCSI Driver"
depends on SGI_IP22 && SCSI
...
...
drivers/scsi/Makefile
View file @
38a9a621
...
...
@@ -33,6 +33,7 @@ obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o
obj-$(CONFIG_SCSI_ISCSI_ATTRS)
+=
scsi_transport_iscsi.o
obj-$(CONFIG_SCSI_SAS_ATTRS)
+=
scsi_transport_sas.o
obj-$(CONFIG_ISCSI_TCP)
+=
iscsi_tcp.o
obj-$(CONFIG_SCSI_AMIGA7XX)
+=
amiga7xx.o 53c7xx.o
obj-$(CONFIG_A3000_SCSI)
+=
a3000.o wd33c93.o
obj-$(CONFIG_A2091_SCSI)
+=
a2091.o wd33c93.o
...
...
drivers/scsi/aacraid/aachba.c
View file @
38a9a621
...
...
@@ -608,17 +608,43 @@ static char *container_types[] = {
* files instead of in OS dependant driver source.
*/
static
void
setinqstr
(
int
devtype
,
void
*
data
,
int
tindex
)
static
void
setinqstr
(
struct
aac_dev
*
dev
,
void
*
data
,
int
tindex
)
{
struct
scsi_inq
*
str
;
struct
aac_driver_ident
*
mp
;
mp
=
aac_get_driver_ident
(
devtype
);
str
=
(
struct
scsi_inq
*
)(
data
);
/* cast data to scsi inq block */
inqstrcpy
(
mp
->
vname
,
str
->
vid
);
inqstrcpy
(
mp
->
model
,
str
->
pid
);
/* last six chars reserved for vol type */
memset
(
str
,
' '
,
sizeof
(
*
str
));
if
(
dev
->
supplement_adapter_info
.
AdapterTypeText
[
0
])
{
char
*
cp
=
dev
->
supplement_adapter_info
.
AdapterTypeText
;
int
c
=
sizeof
(
str
->
vid
);
while
(
*
cp
&&
*
cp
!=
' '
&&
--
c
)
++
cp
;
c
=
*
cp
;
*
cp
=
'\0'
;
inqstrcpy
(
dev
->
supplement_adapter_info
.
AdapterTypeText
,
str
->
vid
);
*
cp
=
c
;
while
(
*
cp
&&
*
cp
!=
' '
)
++
cp
;
while
(
*
cp
==
' '
)
++
cp
;
/* last six chars reserved for vol type */
c
=
0
;
if
(
strlen
(
cp
)
>
sizeof
(
str
->
pid
))
{
c
=
cp
[
sizeof
(
str
->
pid
)];
cp
[
sizeof
(
str
->
pid
)]
=
'\0'
;
}
inqstrcpy
(
cp
,
str
->
pid
);
if
(
c
)
cp
[
sizeof
(
str
->
pid
)]
=
c
;
}
else
{
struct
aac_driver_ident
*
mp
=
aac_get_driver_ident
(
dev
->
cardtype
);
inqstrcpy
(
mp
->
vname
,
str
->
vid
);
/* last six chars reserved for vol type */
inqstrcpy
(
mp
->
model
,
str
->
pid
);
}
if
(
tindex
<
(
sizeof
(
container_types
)
/
sizeof
(
char
*
))){
char
*
findit
=
str
->
pid
;
...
...
@@ -627,7 +653,9 @@ static void setinqstr(int devtype, void *data, int tindex)
/* RAID is superfluous in the context of a RAID device */
if
(
memcmp
(
findit
-
4
,
"RAID"
,
4
)
==
0
)
*
(
findit
-=
4
)
=
' '
;
inqstrcpy
(
container_types
[
tindex
],
findit
+
1
);
if
(((
findit
-
str
->
pid
)
+
strlen
(
container_types
[
tindex
]))
<
(
sizeof
(
str
->
pid
)
+
sizeof
(
str
->
prl
)))
inqstrcpy
(
container_types
[
tindex
],
findit
+
1
);
}
inqstrcpy
(
"V1.0"
,
str
->
prl
);
}
...
...
@@ -822,12 +850,12 @@ int aac_get_adapter_info(struct aac_dev* dev)
dev
->
dac_support
=
(
dacmode
!=
0
);
}
if
(
dev
->
dac_support
!=
0
)
{
if
(
!
pci_set_dma_mask
(
dev
->
pdev
,
0xFFFFFFFFFFFFFFFFULL
)
&&
!
pci_set_consistent_dma_mask
(
dev
->
pdev
,
0xFFFFFFFFFFFFFFFFULL
))
{
if
(
!
pci_set_dma_mask
(
dev
->
pdev
,
DMA_64BIT_MASK
)
&&
!
pci_set_consistent_dma_mask
(
dev
->
pdev
,
DMA_64BIT_MASK
))
{
printk
(
KERN_INFO
"%s%d: 64 Bit DAC enabled
\n
"
,
dev
->
name
,
dev
->
id
);
}
else
if
(
!
pci_set_dma_mask
(
dev
->
pdev
,
0xFFFFFFFFULL
)
&&
!
pci_set_consistent_dma_mask
(
dev
->
pdev
,
0xFFFFFFFFULL
))
{
}
else
if
(
!
pci_set_dma_mask
(
dev
->
pdev
,
DMA_32BIT_MASK
)
&&
!
pci_set_consistent_dma_mask
(
dev
->
pdev
,
DMA_32BIT_MASK
))
{
printk
(
KERN_INFO
"%s%d: DMA mask set failed, 64 Bit DAC disabled
\n
"
,
dev
->
name
,
dev
->
id
);
dev
->
dac_support
=
0
;
...
...
@@ -1438,7 +1466,6 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
struct
Scsi_Host
*
host
=
scsicmd
->
device
->
host
;
struct
aac_dev
*
dev
=
(
struct
aac_dev
*
)
host
->
hostdata
;
struct
fsa_dev_info
*
fsa_dev_ptr
=
dev
->
fsa_dev
;
int
cardtype
=
dev
->
cardtype
;
int
ret
;
/*
...
...
@@ -1542,14 +1569,14 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
* see: <vendor>.c i.e. aac.c
*/
if
(
scsicmd
->
device
->
id
==
host
->
this_id
)
{
setinqstr
(
cardtype
,
(
void
*
)
(
inq_data
.
inqd_vid
),
(
sizeof
(
container_types
)
/
sizeof
(
char
*
)));
setinqstr
(
dev
,
(
void
*
)
(
inq_data
.
inqd_vid
),
(
sizeof
(
container_types
)
/
sizeof
(
char
*
)));
inq_data
.
inqd_pdt
=
INQD_PDT_PROC
;
/* Processor device */
aac_internal_transfer
(
scsicmd
,
&
inq_data
,
0
,
sizeof
(
inq_data
));
scsicmd
->
result
=
DID_OK
<<
16
|
COMMAND_COMPLETE
<<
8
|
SAM_STAT_GOOD
;
scsicmd
->
scsi_done
(
scsicmd
);
return
0
;
}
setinqstr
(
cardtype
,
(
void
*
)
(
inq_data
.
inqd_vid
),
fsa_dev_ptr
[
cid
].
type
);
setinqstr
(
dev
,
(
void
*
)
(
inq_data
.
inqd_vid
),
fsa_dev_ptr
[
cid
].
type
);
inq_data
.
inqd_pdt
=
INQD_PDT_DA
;
/* Direct/random access device */
aac_internal_transfer
(
scsicmd
,
&
inq_data
,
0
,
sizeof
(
inq_data
));
return
aac_get_container_name
(
scsicmd
,
cid
);
...
...
drivers/scsi/aacraid/aacraid.h
View file @
38a9a621
...
...
@@ -1560,7 +1560,7 @@ struct fib_ioctl
struct
revision
{
__le
32
compat
;
u
32
compat
;
__le32
version
;
__le32
build
;
};
...
...
drivers/scsi/aacraid/commctrl.c
View file @
38a9a621
...
...
@@ -408,7 +408,7 @@ static int check_revision(struct aac_dev *dev, void __user *arg)
char
*
driver_version
=
aac_driver_version
;
u32
version
;
response
.
compat
=
cpu_to_le32
(
1
)
;
response
.
compat
=
1
;
version
=
(
simple_strtol
(
driver_version
,
&
driver_version
,
10
)
<<
24
)
|
0x00000400
;
version
+=
simple_strtol
(
driver_version
+
1
,
&
driver_version
,
10
)
<<
16
;
...
...
@@ -574,7 +574,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
rcode
=
-
ENOMEM
;
goto
cleanup
;
}
sg_user
[
i
]
=
(
void
__user
*
)
usg
->
sg
[
i
].
addr
;
sg_user
[
i
]
=
(
void
__user
*
)
(
long
)
usg
->
sg
[
i
].
addr
;
sg_list
[
i
]
=
p
;
// save so we can clean up later
sg_indx
=
i
;
...
...
@@ -624,7 +624,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
rcode
=
-
ENOMEM
;
goto
cleanup
;
}
sg_user
[
i
]
=
(
void
__user
*
)
upsg
->
sg
[
i
].
addr
;
sg_user
[
i
]
=
(
void
__user
*
)
(
long
)
upsg
->
sg
[
i
].
addr
;
sg_list
[
i
]
=
p
;
// save so we can clean up later
sg_indx
=
i
;
...
...
drivers/scsi/aacraid/linit.c
View file @
38a9a621
...
...
@@ -752,8 +752,8 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
if
(
error
)
goto
out
;
if
(
pci_set_dma_mask
(
pdev
,
0xFFFFFFFFULL
)
||
pci_set_consistent_dma_mask
(
pdev
,
0xFFFFFFFFULL
))
if
(
pci_set_dma_mask
(
pdev
,
DMA_32BIT_MASK
)
||
pci_set_consistent_dma_mask
(
pdev
,
DMA_32BIT_MASK
))
goto
out
;
/*
* If the quirk31 bit is set, the adapter needs adapter
...
...
@@ -797,9 +797,9 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
* address space.
*/
if
(
aac_drivers
[
index
].
quirks
&
AAC_QUIRK_31BIT
)
if
(
pci_set_dma_mask
(
pdev
,
0xFFFFFFFFULL
))
goto
out_
free_fibs
;
if
(
pci_set_dma_mask
(
pdev
,
DMA_32BIT_MASK
))
goto
out_
deinit
;
aac
->
maximum_num_channels
=
aac_drivers
[
index
].
channels
;
error
=
aac_get_adapter_info
(
aac
);
if
(
error
<
0
)
...
...
drivers/scsi/dc395x.c
View file @
38a9a621
...
...
@@ -976,6 +976,16 @@ static void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
}
}
static
inline
void
pio_trigger
(
void
)
{
static
int
feedback_requested
;
if
(
!
feedback_requested
)
{
feedback_requested
=
1
;
printk
(
KERN_WARNING
"%s: Please, contact <linux-scsi@vger.kernel.org> "
"to help improve support for your system.
\n
"
,
__FILE__
);
}
}
/* Prepare SRB for being sent to Device DCB w/ command *cmd */
static
void
build_srb
(
struct
scsi_cmnd
*
cmd
,
struct
DeviceCtlBlk
*
dcb
,
...
...
@@ -2320,6 +2330,7 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
CFG2_WIDEFIFO
);
while
(
DC395x_read8
(
acb
,
TRM_S1040_SCSI_FIFOCNT
)
!=
0x40
)
{
u8
byte
=
DC395x_read8
(
acb
,
TRM_S1040_SCSI_FIFO
);
pio_trigger
();
*
(
srb
->
virt_addr
)
++
=
byte
;
if
(
debug_enabled
(
DBG_PIO
))
printk
(
" %02x"
,
byte
);
...
...
@@ -2331,6 +2342,7 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
/* Read the last byte ... */
if
(
srb
->
total_xfer_length
>
0
)
{
u8
byte
=
DC395x_read8
(
acb
,
TRM_S1040_SCSI_FIFO
);
pio_trigger
();
*
(
srb
->
virt_addr
)
++
=
byte
;
srb
->
total_xfer_length
--
;
if
(
debug_enabled
(
DBG_PIO
))
...
...
@@ -2507,6 +2519,7 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
if
(
debug_enabled
(
DBG_PIO
))
printk
(
" %02x"
,
(
unsigned
char
)
*
(
srb
->
virt_addr
));
pio_trigger
();
DC395x_write8
(
acb
,
TRM_S1040_SCSI_FIFO
,
*
(
srb
->
virt_addr
)
++
);
...
...
drivers/scsi/iscsi_tcp.c
0 → 100644
View file @
38a9a621
/*
* iSCSI Initiator over TCP/IP Data-Path
*
* Copyright (C) 2004 Dmitry Yusupov
* Copyright (C) 2004 Alex Aizman
* Copyright (C) 2005 Mike Christie
* maintained by open-iscsi@googlegroups.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.
*
* See the file COPYING included with this distribution for more details.
*
* Credits:
* Christoph Hellwig
* FUJITA Tomonori
* Arne Redlich
* Zhenyu Wang
*/
#include <linux/types.h>
#include <linux/list.h>
#include <linux/inet.h>
#include <linux/blkdev.h>
#include <linux/crypto.h>
#include <linux/delay.h>
#include <linux/kfifo.h>
#include <linux/scatterlist.h>
#include <net/tcp.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_request.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi.h>
#include <scsi/scsi_transport_iscsi.h>
#include "iscsi_tcp.h"
MODULE_AUTHOR
(
"Dmitry Yusupov <dmitry_yus@yahoo.com>, "
"Alex Aizman <itn780@yahoo.com>"
);
MODULE_DESCRIPTION
(
"iSCSI/TCP data-path"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_VERSION
(
"0:4.409"
);
/* #define DEBUG_TCP */
/* #define DEBUG_SCSI */
#define DEBUG_ASSERT
#ifdef DEBUG_TCP
#define debug_tcp(fmt...) printk(KERN_DEBUG "tcp: " fmt)
#else
#define debug_tcp(fmt...)
#endif
#ifdef DEBUG_SCSI
#define debug_scsi(fmt...) printk(KERN_DEBUG "scsi: " fmt)
#else
#define debug_scsi(fmt...)
#endif
#ifndef DEBUG_ASSERT
#ifdef BUG_ON
#undef BUG_ON
#endif
#define BUG_ON(expr)
#endif
#define INVALID_SN_DELTA 0xffff
static
unsigned
int
iscsi_max_lun
=
512
;
module_param_named
(
max_lun
,
iscsi_max_lun
,
uint
,
S_IRUGO
);
/* global data */
static
kmem_cache_t
*
taskcache
;
static
inline
void
iscsi_buf_init_virt
(
struct
iscsi_buf
*
ibuf
,
char
*
vbuf
,
int
size
)
{
sg_init_one
(
&
ibuf
->
sg
,
(
u8
*
)
vbuf
,
size
);
ibuf
->
sent
=
0
;
}
static
inline
void
iscsi_buf_init_iov
(
struct
iscsi_buf
*
ibuf
,
char
*
vbuf
,
int
size
)
{
ibuf
->
sg
.
page
=
(
void
*
)
vbuf
;
ibuf
->
sg
.
offset
=
(
unsigned
int
)
-
1
;
ibuf
->
sg
.
length
=
size
;
ibuf
->
sent
=
0
;
}
static
inline
void
*
iscsi_buf_iov_base
(
struct
iscsi_buf
*
ibuf
)
{
return
(
char
*
)
ibuf
->
sg
.
page
+
ibuf
->
sent
;
}
static
inline
void
iscsi_buf_init_sg
(
struct
iscsi_buf
*
ibuf
,
struct
scatterlist
*
sg
)
{
/*
* Fastpath: sg element fits into single page
*/
if
(
sg
->
length
+
sg
->
offset
<=
PAGE_SIZE
&&
page_count
(
sg
->
page
)
>=
2
)
{
ibuf
->
sg
.
page
=
sg
->
page
;
ibuf
->
sg
.
offset
=
sg
->
offset
;
ibuf
->
sg
.
length
=
sg
->
length
;
}
else
iscsi_buf_init_iov
(
ibuf
,
page_address
(
sg
->
page
),
sg
->
length
);
ibuf
->
sent
=
0
;
}
static
inline
int
iscsi_buf_left
(
struct
iscsi_buf
*
ibuf
)
{
int
rc
;
rc
=
ibuf
->
sg
.
length
-
ibuf
->
sent
;
BUG_ON
(
rc
<
0
);
return
rc
;
}
static
inline
void
iscsi_hdr_digest
(
struct
iscsi_conn
*
conn
,
struct
iscsi_buf
*
buf
,
u8
*
crc
)
{
crypto_digest_digest
(
conn
->
tx_tfm
,
&
buf
->
sg
,
1
,
crc
);
buf
->
sg
.
length
+=
sizeof
(
uint32_t
);
}
static
void
iscsi_conn_failure
(
struct
iscsi_conn
*
conn
,
enum
iscsi_err
err
)
{
struct
iscsi_session
*
session
=
conn
->
session
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
session
->
lock
,
flags
);
if
(
session
->
conn_cnt
==
1
||
session
->
leadconn
==
conn
)
session
->
state
=
ISCSI_STATE_FAILED
;
spin_unlock_irqrestore
(
&
session
->
lock
,
flags
);
set_bit
(
SUSPEND_BIT
,
&
conn
->
suspend_tx
);
set_bit
(
SUSPEND_BIT
,
&
conn
->
suspend_rx
);
iscsi_conn_error
(
iscsi_handle
(
conn
),
err
);
}
static
inline
int
iscsi_check_assign_cmdsn
(
struct
iscsi_session
*
session
,
struct
iscsi_nopin
*
hdr
)
{
uint32_t
max_cmdsn
=
be32_to_cpu
(
hdr
->
max_cmdsn
);
uint32_t
exp_cmdsn
=
be32_to_cpu
(
hdr
->
exp_cmdsn
);
if
(
max_cmdsn
<
exp_cmdsn
-
1
&&
max_cmdsn
>
exp_cmdsn
-
INVALID_SN_DELTA
)
return
ISCSI_ERR_MAX_CMDSN
;
if
(
max_cmdsn
>
session
->
max_cmdsn
||
max_cmdsn
<
session
->
max_cmdsn
-
INVALID_SN_DELTA
)
session
->
max_cmdsn
=
max_cmdsn
;
if
(
exp_cmdsn
>
session
->
exp_cmdsn
||
exp_cmdsn
<
session
->
exp_cmdsn
-
INVALID_SN_DELTA
)
session
->
exp_cmdsn
=
exp_cmdsn
;
return
0
;
}
static
inline
int
iscsi_hdr_extract
(
struct
iscsi_conn
*
conn
)
{
struct
sk_buff
*
skb
=
conn
->
in
.
skb
;
if
(
conn
->
in
.
copy
>=
conn
->
hdr_size
&&
conn
->
in_progress
==
IN_PROGRESS_WAIT_HEADER
)
{
/*
* Zero-copy PDU Header: using connection context
* to store header pointer.
*/
if
(
skb_shinfo
(
skb
)
->
frag_list
==
NULL
&&
!
skb_shinfo
(
skb
)
->
nr_frags
)
conn
->
in
.
hdr
=
(
struct
iscsi_hdr
*
)
((
char
*
)
skb
->
data
+
conn
->
in
.
offset
);
else
{
/* ignoring return code since we checked
* in.copy before */
skb_copy_bits
(
skb
,
conn
->
in
.
offset
,
&
conn
->
hdr
,
conn
->
hdr_size
);
conn
->
in
.
hdr
=
&
conn
->
hdr
;
}
conn
->
in
.
offset
+=
conn
->
hdr_size
;
conn
->
in
.
copy
-=
conn
->
hdr_size
;
}
else
{
int
hdr_remains
;
int
copylen
;
/*
* PDU header scattered across SKB's,
* copying it... This'll happen quite rarely.
*/
if
(
conn
->
in_progress
==
IN_PROGRESS_WAIT_HEADER
)
conn
->
in
.
hdr_offset
=
0
;
hdr_remains
=
conn
->
hdr_size
-
conn
->
in
.
hdr_offset
;
BUG_ON
(
hdr_remains
<=
0
);
copylen
=
min
(
conn
->
in
.
copy
,
hdr_remains
);
skb_copy_bits
(
skb
,
conn
->
in
.
offset
,
(
char
*
)
&
conn
->
hdr
+
conn
->
in
.
hdr_offset
,
copylen
);
debug_tcp
(
"PDU gather offset %d bytes %d in.offset %d "
"in.copy %d
\n
"
,
conn
->
in
.
hdr_offset
,
copylen
,
conn
->
in
.
offset
,
conn
->
in
.
copy
);
conn
->
in
.
offset
+=
copylen
;
conn
->
in
.
copy
-=
copylen
;
if
(
copylen
<
hdr_remains
)
{
conn
->
in_progress
=
IN_PROGRESS_HEADER_GATHER
;
conn
->
in
.
hdr_offset
+=
copylen
;
return
-
EAGAIN
;
}
conn
->
in
.
hdr
=
&
conn
->
hdr
;
conn
->
discontiguous_hdr_cnt
++
;
conn
->
in_progress
=
IN_PROGRESS_WAIT_HEADER
;
}
return
0
;
}
static
inline
void
iscsi_ctask_cleanup
(
struct
iscsi_conn
*
conn
,
struct
iscsi_cmd_task
*
ctask
)
{
struct
scsi_cmnd
*
sc
=
ctask
->
sc
;
struct
iscsi_session
*
session
=
conn
->
session
;
spin_lock
(
&
session
->
lock
);
if
(
unlikely
(
!
sc
))
{
spin_unlock
(
&
session
->
lock
);
return
;
}
if
(
sc
->
sc_data_direction
==
DMA_TO_DEVICE
)
{
struct
iscsi_data_task
*
dtask
,
*
n
;
/* WRITE: cleanup Data-Out's if any */
spin_lock
(
&
conn
->
lock
);
list_for_each_entry_safe
(
dtask
,
n
,
&
ctask
->
dataqueue
,
item
)
{
list_del
(
&
dtask
->
item
);
mempool_free
(
dtask
,
ctask
->
datapool
);
}
spin_unlock
(
&
conn
->
lock
);
}
ctask
->
xmstate
=
XMSTATE_IDLE
;
ctask
->
r2t
=
NULL
;
ctask
->
sc
=
NULL
;
__kfifo_put
(
session
->
cmdpool
.
queue
,
(
void
*
)
&
ctask
,
sizeof
(
void
*
));
spin_unlock
(
&
session
->
lock
);
}
/**
* iscsi_cmd_rsp - SCSI Command Response processing
* @conn: iscsi connection
* @ctask: scsi command task
**/
static
int
iscsi_cmd_rsp
(
struct
iscsi_conn
*
conn
,
struct
iscsi_cmd_task
*
ctask
)
{
int
rc
;
struct
iscsi_cmd_rsp
*
rhdr
=
(
struct
iscsi_cmd_rsp
*
)
conn
->
in
.
hdr
;
struct
iscsi_session
*
session
=
conn
->
session
;
struct
scsi_cmnd
*
sc
=
ctask
->
sc
;
rc
=
iscsi_check_assign_cmdsn
(
session
,
(
struct
iscsi_nopin
*
)
rhdr
);
if
(
rc
)
{
sc
->
result
=
(
DID_ERROR
<<
16
);
goto
out
;
}
conn
->
exp_statsn
=
be32_to_cpu
(
rhdr
->
statsn
)
+
1
;
sc
->
result
=
(
DID_OK
<<
16
)
|
rhdr
->
cmd_status
;
if
(
rhdr
->
response
!=
ISCSI_STATUS_CMD_COMPLETED
)
{
sc
->
result
=
(
DID_ERROR
<<
16
);
goto
out
;
}
if
(
rhdr
->
cmd_status
==
SAM_STAT_CHECK_CONDITION
&&
conn
->
senselen
)
{
int
sensecopy
=
min
(
conn
->
senselen
,
SCSI_SENSE_BUFFERSIZE
);
memcpy
(
sc
->
sense_buffer
,
conn
->
data
+
2
,
sensecopy
);
debug_scsi
(
"copied %d bytes of sense
\n
"
,
sensecopy
);
}
if
(
sc
->
sc_data_direction
==
DMA_TO_DEVICE
)
goto
out
;
if
(
rhdr
->
flags
&
ISCSI_FLAG_CMD_UNDERFLOW
)
{
int
res_count
=
be32_to_cpu
(
rhdr
->
residual_count
);
if
(
res_count
>
0
&&
res_count
<=
sc
->
request_bufflen
)
sc
->
resid
=
res_count
;
else
sc
->
result
=
(
DID_BAD_TARGET
<<
16
)
|
rhdr
->
cmd_status
;
}
else
if
(
rhdr
->
flags
&
ISCSI_FLAG_CMD_BIDI_UNDERFLOW
)
sc
->
result
=
(
DID_BAD_TARGET
<<
16
)
|
rhdr
->
cmd_status
;
else
if
(
rhdr
->
flags
&
ISCSI_FLAG_CMD_OVERFLOW
)
sc
->
resid
=
be32_to_cpu
(
rhdr
->
residual_count
);
out:
debug_scsi
(
"done [sc %lx res %d itt 0x%x]
\n
"
,
(
long
)
sc
,
sc
->
result
,
ctask
->
itt
);
conn
->
scsirsp_pdus_cnt
++
;
iscsi_ctask_cleanup
(
conn
,
ctask
);
sc
->
scsi_done
(
sc
);
return
rc
;
}
/**
* iscsi_data_rsp - SCSI Data-In Response processing
* @conn: iscsi connection
* @ctask: scsi command task
**/
static
int
iscsi_data_rsp
(
struct
iscsi_conn
*
conn
,
struct
iscsi_cmd_task
*
ctask
)
{
int
rc
;
struct
iscsi_data_rsp
*
rhdr
=
(
struct
iscsi_data_rsp
*
)
conn
->
in
.
hdr
;
struct
iscsi_session
*
session
=
conn
->
session
;
int
datasn
=
be32_to_cpu
(
rhdr
->
datasn
);
rc
=
iscsi_check_assign_cmdsn
(
session
,
(
struct
iscsi_nopin
*
)
rhdr
);
if
(
rc
)
return
rc
;
/*
* setup Data-In byte counter (gets decremented..)
*/
ctask
->
data_count
=
conn
->
in
.
datalen
;
if
(
conn
->
in
.
datalen
==
0
)
return
0
;
if
(
ctask
->
datasn
!=
datasn
)
return
ISCSI_ERR_DATASN
;
ctask
->
datasn
++
;
ctask
->
data_offset
=
be32_to_cpu
(
rhdr
->
offset
);
if
(
ctask
->
data_offset
+
conn
->
in
.
datalen
>
ctask
->
total_length
)
return
ISCSI_ERR_DATA_OFFSET
;
if
(
rhdr
->
flags
&
ISCSI_FLAG_DATA_STATUS
)
{
struct
scsi_cmnd
*
sc
=
ctask
->
sc
;
conn
->
exp_statsn
=
be32_to_cpu
(
rhdr
->
statsn
)
+
1
;