Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
ac4646f7
Commit
ac4646f7
authored
Nov 24, 2004
by
James Bottomley
Browse files
Options
Browse Files
Download
Plain Diff
Merge
ssh://linux-scsi@linux-scsi.bkbits.net/scsi-misc-2.6
into mulgrave.(none):/home/jejb/BK/scsi-misc-2.6
parents
0a57a616
c53ba412
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
1546 additions
and
634 deletions
+1546
-634
drivers/scsi/Kconfig
drivers/scsi/Kconfig
+8
-0
drivers/scsi/Makefile
drivers/scsi/Makefile
+1
-1
drivers/scsi/constants.c
drivers/scsi/constants.c
+580
-341
drivers/scsi/hosts.c
drivers/scsi/hosts.c
+6
-1
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_debug.c
+265
-214
drivers/scsi/scsi_error.c
drivers/scsi/scsi_error.c
+35
-12
drivers/scsi/scsi_ioctl.c
drivers/scsi/scsi_ioctl.c
+18
-12
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_lib.c
+17
-12
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_scan.c
+34
-18
drivers/scsi/scsi_sysfs.c
drivers/scsi/scsi_sysfs.c
+5
-0
drivers/scsi/scsi_transport_fc.c
drivers/scsi/scsi_transport_fc.c
+33
-17
drivers/scsi/scsi_transport_iscsi.c
drivers/scsi/scsi_transport_iscsi.c
+355
-0
include/scsi/scsi_transport.h
include/scsi/scsi_transport.h
+5
-0
include/scsi/scsi_transport_fc.h
include/scsi/scsi_transport_fc.h
+6
-6
include/scsi/scsi_transport_iscsi.h
include/scsi/scsi_transport_iscsi.h
+178
-0
No files found.
drivers/scsi/Kconfig
View file @
ac4646f7
...
...
@@ -203,6 +203,14 @@ config SCSI_FC_ATTRS
each attached FiberChannel device to sysfs, say Y.
Otherwise, say N.
config SCSI_ISCSI_ATTRS
tristate "iSCSI Transport Attributes"
depends on SCSI
help
If you wish to export transport-specific information about
each attached iSCSI device to sysfs, say Y.
Otherwise, say N.
endmenu
menu "SCSI low-level drivers"
...
...
drivers/scsi/Makefile
View file @
ac4646f7
...
...
@@ -28,7 +28,7 @@ obj-$(CONFIG_SCSI) += scsi_mod.o
# --------------------------
obj-$(CONFIG_SCSI_SPI_ATTRS)
+=
scsi_transport_spi.o
obj-$(CONFIG_SCSI_FC_ATTRS)
+=
scsi_transport_fc.o
obj-$(CONFIG_SCSI_ISCSI_ATTRS)
+=
scsi_transport_iscsi.o
obj-$(CONFIG_SCSI_AMIGA7XX)
+=
amiga7xx.o 53c7xx.o
obj-$(CONFIG_A3000_SCSI)
+=
a3000.o wd33c93.o
...
...
drivers/scsi/constants.c
View file @
ac4646f7
...
...
@@ -4,6 +4,7 @@
* Additions for SCSI 2 and Linux 2.2.x by D. Gilbert (990422)
* Additions for SCSI 3+ (SPC-3 T10/1416-D Rev 07 3 May 2002)
* by D. Gilbert and aeb (20020609)
* Additions for SPC-3 T10/1416-D Rev 21 22 Sept 2004, D. Gilbert 20041025
*/
#include <linux/config.h>
...
...
@@ -15,96 +16,78 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_request.h>
#include <scsi/scsi_eh.h>
#define CONST_COMMAND 0x01
#define CONST_STATUS 0x02
#define CONST_SENSE 0x04
#define CONST_XSENSE 0x08
#define CONST_CMND 0x10
#define CONST_MSG 0x20
#define CONST_HOST 0x40
#define CONST_DRIVER 0x80
static
const
char
unknown
[]
=
"UNKNOWN"
;
/* Commands with service actions that change the command name */
#define MAINTENANCE_IN 0xa3
#define MAINTENANCE_OUT 0xa4
#define SERVICE_ACTION_IN_12 0xab
#define SERVICE_ACTION_OUT_12 0xa9
#define SERVICE_ACTION_IN_16 0x9e
#define SERVICE_ACTION_OUT_16 0x9f
#define VARIABLE_LENGTH_CMD 0x7f
#ifdef CONFIG_SCSI_CONSTANTS
#ifdef CONSTANTS
#undef CONSTANTS
#endif
#define CONSTANTS (CONST_COMMAND | CONST_STATUS | CONST_SENSE | CONST_XSENSE \
| CONST_CMND | CONST_MSG | CONST_HOST | CONST_DRIVER)
#else
#define CONSTANTS 0
#endif
#if (CONSTANTS & CONST_COMMAND)
static
const
char
*
group_0_commands
[]
=
{
/* 00-03 */
"Test Unit Ready"
,
"Rezero Unit"
,
unknown
,
"Request Sense"
,
/* 04-07 */
"Format Unit"
,
"Read Block Limits"
,
unknown
,
"Reasssign Blocks"
,
/* 08-0d */
"Read (6)"
,
unknown
,
"Write (6)"
,
"Seek (6)"
,
unknown
,
unknown
,
/* 0e-12 */
unknown
,
"Read Reverse"
,
"Write Filemarks"
,
"Space"
,
"Inquiry"
,
/* 13-16 */
"Verify"
,
"Recover Buffered Data"
,
"Mode Select"
,
"Reserve"
,
/* 17-1b */
"Release"
,
"Copy"
,
"Erase"
,
"Mode Sense"
,
"Start/Stop Unit"
,
/* 1c-1d */
"Receive Diagnostic"
,
"Send Diagnostic"
,
/* 1e-1f */
"Prevent/Allow Medium Removal"
,
unknown
,
};
static
const
char
*
group_1_commands
[]
=
{
/* 20-22 */
unknown
,
unknown
,
unknown
,
/* 23-28 */
unknown
,
"Define window parameters"
,
"Read Capacity"
,
unknown
,
unknown
,
"Read (10)"
,
/* 29-2d */
"Read Generation"
,
"Write (10)"
,
"Seek (10)"
,
"Erase"
,
#ifdef CONFIG_SCSI_CONSTANTS
static
const
char
*
cdb_byte0_names
[]
=
{
/* 00-03 */
"Test Unit Ready"
,
"Rezero Unit/Rewind"
,
NULL
,
"Request Sense"
,
/* 04-07 */
"Format Unit/Medium"
,
"Read Block Limits"
,
NULL
,
"Reasssign Blocks"
,
/* 08-0d */
"Read (6)"
,
NULL
,
"Write (6)"
,
"Seek (6)"
,
NULL
,
NULL
,
/* 0e-12 */
NULL
,
"Read Reverse"
,
"Write Filemarks"
,
"Space"
,
"Inquiry"
,
/* 13-16 */
"Verify (6)"
,
"Recover Buffered Data"
,
"Mode Select (6)"
,
"Reserve (6)"
,
/* 17-1a */
"Release (6)"
,
"Copy"
,
"Erase"
,
"Mode Sense (6)"
,
/* 1b-1d */
"Start/Stop Unit"
,
"Receive Diagnostic"
,
"Send Diagnostic"
,
/* 1e-1f */
"Prevent/Allow Medium Removal"
,
NULL
,
/* 20-22 */
NULL
,
NULL
,
NULL
,
/* 23-28 */
"Read Format Capacities"
,
"Set Window"
,
"Read Capacity (10)"
,
NULL
,
NULL
,
"Read (10)"
,
/* 29-2d */
"Read Generation"
,
"Write (10)"
,
"Seek (10)"
,
"Erase (10)"
,
"Read updated block"
,
/* 2e-31 */
"Write Verify"
,
"Verify"
,
"Search High"
,
"Search Equal"
,
/* 32-34 */
"Search Low"
,
"Set Limits"
,
"Prefetch or Read Position"
,
/* 35-37 */
"Synchronize Cache"
,
"Lock/Unlock Cache"
,
"Read Defect Data"
,
/* 2e-31 */
"Write Verify (10)"
,
"Verify (10)"
,
"Search High"
,
"Search Equal"
,
/* 32-34 */
"Search Low"
,
"Set Limits"
,
"Prefetch/Read Position"
,
/* 35-37 */
"Synchronize Cache (10)"
,
"Lock/Unlock Cache (10)"
,
"Read Defect Data(10)"
,
/* 38-3c */
"Medium Scan"
,
"Compare"
,
"Copy Verify"
,
"Write Buffer"
,
"Read Buffer"
,
/* 3d-3f */
"Update Block"
,
"Read Long"
,
"Write Long"
,
};
static
const
char
*
group_2_commands
[]
=
{
/* 40-41 */
"Change Definition"
,
"Write Same"
,
/* 42-48 */
"Read sub-channel"
,
"Read TOC"
,
"Read header"
,
/* 3d-3f */
"Update Block"
,
"Read Long (10)"
,
"Write Long (10)"
,
/* 40-41 */
"Change Definition"
,
"Write Same (10)"
,
/* 42-48 */
"Read sub-channel"
,
"Read TOC/PMA/ATIP"
,
"Read density support"
,
"Play audio (10)"
,
"Get configuration"
,
"Play audio msf"
,
"Play audio track/index"
,
/* 49-4f */
"Play track relative (10)"
,
"Get event status notification"
,
"Pause/resume"
,
"Log Select"
,
"Log Sense"
,
"Stop play/scan"
,
unknown
,
NULL
,
/* 50-55 */
"Xdwrite"
,
"Xpwrite, Read disk info"
,
"Xdread, Read track info"
,
"Reserve track"
,
"Send OPC
o
nfo"
,
"Mode Select (10)"
,
"Reserve track"
,
"Send OPC
i
nfo"
,
"Mode Select (10)"
,
/* 56-5b */
"Reserve (10)"
,
"Release (10)"
,
"Repair track"
,
"Read master cue"
,
"Mode Sense (10)"
,
"Close track/session"
,
/* 5c-5f */
"Read buffer capacity"
,
"Send cue sheet"
,
"Persistent reserve in"
,
"Persistent reserve out"
,
};
/* The following are 16 byte commands in group 4 */
static
const
char
*
group_4_commands
[]
=
{
/* 60-67 */
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
/* 68-6f */
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
/* 70-77 */
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
/* 78-7f */
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
"Variable length"
,
/* 80-84 */
"Xdwrite (16)"
,
"Rebuild (16)"
,
"Regenerate (16)"
,
"Extended copy"
,
"Receive copy results"
,
/* 85-89 */
"Memory Export In (16)"
,
"Access control in"
,
"Access control out"
,
"Read (16)"
,
"Memory Export Out (16)"
,
/* 8a-8f */
"Write (16)"
,
unknown
,
"Read attributes"
,
"Write attributes"
,
/* 8a-8f */
"Write (16)"
,
NULL
,
"Read attributes"
,
"Write attributes"
,
"Write and verify (16)"
,
"Verify (16)"
,
/* 90-94 */
"Pre-fetch (16)"
,
"Synchronize cache (16)"
,
"Lock/unlock cache (16)"
,
"Write same (16)"
,
unknown
,
/* 95-99 */
unknown
,
unknown
,
unknown
,
unknown
,
unknown
,
/* 9a-9f */
unknown
,
unknown
,
unknown
,
unknown
,
"Service action in"
,
"Service action out"
,
};
/* The following are 12 byte commands in group 5 */
static
const
char
*
group_5_commands
[]
=
{
/* a0-a5 */
"Report luns"
,
"Blank"
,
"Send event"
,
"Maintenance (in)"
,
"Maintenance (out)"
,
"Move medium/play audio(12)"
,
"Lock/unlock cache (16)"
,
"Write same (16)"
,
NULL
,
/* 95-99 */
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
/* 9a-9f */
NULL
,
NULL
,
NULL
,
NULL
,
"Service action in (16)"
,
"Service action out (16)"
,
/* a0-a5 */
"Report luns"
,
"Blank"
,
"Send event"
,
"Maintenance in"
,
"Maintenance out"
,
"Move medium/play audio(12)"
,
/* a6-a9 */
"Exchange medium"
,
"Move medium attached"
,
"Read(12)"
,
"Play track relative(12)"
,
/* aa-ae */
"Write(12)"
,
unknown
,
"Erase(12), Get Performance"
,
/* aa-ae */
"Write(12)"
,
NULL
,
"Erase(12), Get Performance"
,
"Read DVD structure"
,
"Write and verify(12)"
,
/* af-b1 */
"Verify(12)"
,
"Search data high(12)"
,
"Search data equal(12)"
,
/* b2-b4 */
"Search data low(12)"
,
"Set limits(12)"
,
...
...
@@ -112,57 +95,278 @@ static const char *group_5_commands[] = {
/* b5-b6 */
"Request volume element address"
,
"Send volume tag, set streaming"
,
/* b7-b9 */
"Read defect data(12)"
,
"Read element status"
,
"Read CD msf"
,
/* ba-bc */
"Redundancy group (in), Scan"
,
"Redundancy group (out), Set cd-rom speed"
,
"Spare
(in)
, Play cd"
,
/* bd-bf */
"Spare
(out), Mechanism status"
,
"Volume set (in)
, Read cd"
,
"Volume set
(out)
, Send DVD structure"
,
"Redundancy group (out), Set cd-rom speed"
,
"Spare
in
, Play cd"
,
/* bd-bf */
"Spare
out, Mechanism status"
,
"Volume set in
, Read cd"
,
"Volume set
out
, Send DVD structure"
,
};
struct
value_name_pair
{
int
value
;
const
char
*
name
;
};
static
const
struct
value_name_pair
maint_in_arr
[]
=
{
{
0x5
,
"Report device identifier"
},
{
0xa
,
"Report target port groups"
},
{
0xb
,
"Report aliases"
},
{
0xc
,
"Report supported operation codes"
},
{
0xd
,
"Report supported task management functions"
},
{
0xe
,
"Report priority"
},
};
#define MAINT_IN_SZ \
(int)(sizeof(maint_in_arr) / sizeof(maint_in_arr[0]))
static
const
struct
value_name_pair
maint_out_arr
[]
=
{
{
0x6
,
"Set device identifier"
},
{
0xa
,
"Set target port groups"
},
{
0xb
,
"Change aliases"
},
{
0xe
,
"Set priority"
},
};
#define MAINT_OUT_SZ \
(int)(sizeof(maint_out_arr) / sizeof(maint_out_arr[0]))
#define group(opcode) (((opcode) >> 5) & 7)
static
const
struct
value_name_pair
serv_in12_arr
[]
=
{
{
0x1
,
"Read media serial number"
},
};
#define SERV_IN12_SZ \
(int)(sizeof(serv_in12_arr) / sizeof(serv_in12_arr[0]))
#define RESERVED_GROUP 0
#define VENDOR_GROUP 1
static
const
struct
value_name_pair
serv_out12_arr
[]
=
{
{
-
1
,
"dummy entry"
},
};
#define SERV_OUT12_SZ \
(int)(sizeof(serv_out12_arr) / sizeof(serv_in12_arr[0]))
static
const
char
**
commands
[]
=
{
group_0_commands
,
group_1_commands
,
group_2_commands
,
(
const
char
**
)
RESERVED_GROUP
,
group_4_commands
,
group_5_commands
,
(
const
char
**
)
VENDOR_GROUP
,
(
const
char
**
)
VENDOR_GROUP
static
const
struct
value_name_pair
serv_in16_arr
[]
=
{
{
0x10
,
"Read capacity(16)"
},
{
0x11
,
"Read long(16)"
},
};
#define SERV_IN16_SZ \
(int)(sizeof(serv_in16_arr) / sizeof(serv_in16_arr[0]))
static
const
char
reserved
[]
=
"RESERVED"
;
static
const
char
vendor
[]
=
"VENDOR SPECIFIC"
;
static
void
print_opcode
(
int
opcode
)
{
const
char
**
table
=
commands
[
group
(
opcode
)
];
switch
((
unsigned
long
)
table
)
{
case
RESERVED_GROUP
:
printk
(
"%s(0x%02x) "
,
reserved
,
opcode
);
break
;
case
VENDOR_GROUP
:
printk
(
"%s(0x%02x) "
,
vendor
,
opcode
);
break
;
default:
if
(
table
[
opcode
&
0x1f
]
!=
unknown
)
printk
(
"%s "
,
table
[
opcode
&
0x1f
]);
else
printk
(
"%s(0x%02x) "
,
unknown
,
opcode
);
break
;
}
static
const
struct
value_name_pair
serv_out16_arr
[]
=
{
{
0x11
,
"Write long(16)"
},
{
0x1f
,
"Notify data transfer device(16)"
},
};
#define SERV_OUT16_SZ \
(int)(sizeof(serv_out16_arr) / sizeof(serv_in16_arr[0]))
static
const
struct
value_name_pair
variable_length_arr
[]
=
{
{
0x1
,
"Rebuild(32)"
},
{
0x2
,
"Regenerate(32)"
},
{
0x3
,
"Xdread(32)"
},
{
0x4
,
"Xdwrite(32)"
},
{
0x5
,
"Xdwrite extended(32)"
},
{
0x6
,
"Xpwrite(32)"
},
{
0x7
,
"Xdwriteread(32)"
},
{
0x8
,
"Xdwrite extended(64)"
},
{
0x9
,
"Read(32)"
},
{
0xa
,
"Verify(32)"
},
{
0xb
,
"Write(32)"
},
{
0xc
,
"Write an verify(32)"
},
{
0xd
,
"Write same(32)"
},
{
0x8801
,
"Format OSD"
},
{
0x8802
,
"Create (osd)"
},
{
0x8803
,
"List (osd)"
},
{
0x8805
,
"Read (osd)"
},
{
0x8806
,
"Write (osd)"
},
{
0x8807
,
"Append (osd)"
},
{
0x8808
,
"Flush (osd)"
},
{
0x880a
,
"Remove (osd)"
},
{
0x880b
,
"Create partition (osd)"
},
{
0x880c
,
"Remove partition (osd)"
},
{
0x880e
,
"Get attributes (osd)"
},
{
0x880f
,
"Set attributes (osd)"
},
{
0x8812
,
"Create and write (osd)"
},
{
0x8815
,
"Create collection (osd)"
},
{
0x8816
,
"Remove collection (osd)"
},
{
0x8817
,
"List collection (osd)"
},
{
0x8818
,
"Set key (osd)"
},
{
0x8819
,
"Set master key (osd)"
},
{
0x881a
,
"Flush collection (osd)"
},
{
0x881b
,
"Flush partition (osd)"
},
{
0x881c
,
"Flush OSD"
},
{
0x8f7e
,
"Perform SCSI command (osd)"
},
{
0x8f7f
,
"Perform task management function (osd)"
},
};
#define VARIABLE_LENGTH_SZ \
(int)(sizeof(variable_length_arr) / sizeof(variable_length_arr[0]))
static
const
char
*
get_sa_name
(
const
struct
value_name_pair
*
arr
,
int
arr_sz
,
int
service_action
)
{
int
k
;
for
(
k
=
0
;
k
<
arr_sz
;
++
k
,
++
arr
)
{
if
(
service_action
==
arr
->
value
)
break
;
}
return
(
k
<
arr_sz
)
?
arr
->
name
:
NULL
;
}
/* attempt to guess cdb length if cdb_len==0 . No trailing linefeed. */
static
void
print_opcode_name
(
unsigned
char
*
cdbp
,
int
cdb_len
,
int
start_of_line
)
{
int
sa
,
len
,
cdb0
;
const
char
*
name
;
const
char
*
leadin
=
start_of_line
?
KERN_INFO
:
""
;
cdb0
=
cdbp
[
0
];
switch
(
cdb0
)
{
case
VARIABLE_LENGTH_CMD
:
len
=
cdbp
[
7
]
+
8
;
if
(
len
<
10
)
{
printk
(
"%sshort variable length command, "
"len=%d ext_len=%d"
,
leadin
,
len
,
cdb_len
);
break
;
}
sa
=
(
cdbp
[
8
]
<<
8
)
+
cdbp
[
9
];
name
=
get_sa_name
(
maint_in_arr
,
MAINT_IN_SZ
,
sa
);
if
(
name
)
{
printk
(
"%s%s"
,
leadin
,
name
);
if
((
cdb_len
>
0
)
&&
(
len
!=
cdb_len
))
printk
(
", in_cdb_len=%d, ext_len=%d"
,
len
,
cdb_len
);
}
else
{
printk
(
"%scdb[0]=0x%x, sa=0x%x"
,
leadin
,
cdb0
,
sa
);
if
((
cdb_len
>
0
)
&&
(
len
!=
cdb_len
))
printk
(
", in_cdb_len=%d, ext_len=%d"
,
len
,
cdb_len
);
}
break
;
case
MAINTENANCE_IN
:
sa
=
cdbp
[
1
]
&
0x1f
;
name
=
get_sa_name
(
maint_in_arr
,
MAINT_IN_SZ
,
sa
);
if
(
name
)
printk
(
"%s%s"
,
leadin
,
name
);
else
printk
(
"%scdb[0]=0x%x, sa=0x%x"
,
leadin
,
cdb0
,
sa
);
break
;
case
MAINTENANCE_OUT
:
sa
=
cdbp
[
1
]
&
0x1f
;
name
=
get_sa_name
(
maint_out_arr
,
MAINT_OUT_SZ
,
sa
);
if
(
name
)
printk
(
"%s%s"
,
leadin
,
name
);
else
printk
(
"%scdb[0]=0x%x, sa=0x%x"
,
leadin
,
cdb0
,
sa
);
break
;
case
SERVICE_ACTION_IN_12
:
sa
=
cdbp
[
1
]
&
0x1f
;
name
=
get_sa_name
(
serv_in12_arr
,
SERV_IN12_SZ
,
sa
);
if
(
name
)
printk
(
"%s%s"
,
leadin
,
name
);
else
printk
(
"%scdb[0]=0x%x, sa=0x%x"
,
leadin
,
cdb0
,
sa
);
break
;
case
SERVICE_ACTION_OUT_12
:
sa
=
cdbp
[
1
]
&
0x1f
;
name
=
get_sa_name
(
serv_out12_arr
,
SERV_OUT12_SZ
,
sa
);
if
(
name
)
printk
(
"%s%s"
,
leadin
,
name
);
else
printk
(
"%scdb[0]=0x%x, sa=0x%x"
,
leadin
,
cdb0
,
sa
);
break
;
case
SERVICE_ACTION_IN_16
:
sa
=
cdbp
[
1
]
&
0x1f
;
name
=
get_sa_name
(
serv_in16_arr
,
SERV_IN16_SZ
,
sa
);
if
(
name
)
printk
(
"%s%s"
,
leadin
,
name
);
else
printk
(
"%scdb[0]=0x%x, sa=0x%x"
,
leadin
,
cdb0
,
sa
);
break
;
case
SERVICE_ACTION_OUT_16
:
sa
=
cdbp
[
1
]
&
0x1f
;
name
=
get_sa_name
(
serv_out16_arr
,
SERV_OUT16_SZ
,
sa
);
if
(
name
)
printk
(
"%s%s"
,
leadin
,
name
);
else
printk
(
"%scdb[0]=0x%x, sa=0x%x"
,
leadin
,
cdb0
,
sa
);
break
;
default:
if
(
cdb0
<
0xc0
)
{
name
=
cdb_byte0_names
[
cdb0
];
if
(
name
)
printk
(
"%s%s"
,
leadin
,
name
);
else
printk
(
"%scdb[0]=0x%x (reserved)"
,
leadin
,
cdb0
);
}
else
printk
(
"%scdb[0]=0x%x (vendor)"
,
leadin
,
cdb0
);
break
;
}
}
#else
/* CONST & CONST_COMMAND */
static
void
print_opcode
(
int
opcode
)
{
printk
(
"0x%02x "
,
opcode
);
#else
/* ifndef CONFIG_SCSI_CONSTANTS */
static
void
print_opcode_name
(
unsigned
char
*
cdbp
,
int
cdb_len
,
int
start_of_line
)
{
int
sa
,
len
,
cdb0
;
const
char
*
leadin
=
start_of_line
?
KERN_INFO
:
""
;
cdb0
=
cdbp
[
0
];
switch
(
cdb0
)
{
case
VARIABLE_LENGTH_CMD
:
len
=
cdbp
[
7
]
+
8
;
if
(
len
<
10
)
{
printk
(
"%sshort opcode=0x%x command, len=%d "
"ext_len=%d"
,
leadin
,
cdb0
,
len
,
cdb_len
);
break
;
}
sa
=
(
cdbp
[
8
]
<<
8
)
+
cdbp
[
9
];
printk
(
"%scdb[0]=0x%x, sa=0x%x"
,
leadin
,
cdb0
,
sa
);
if
(
len
!=
cdb_len
)
printk
(
", in_cdb_len=%d, ext_len=%d"
,
len
,
cdb_len
);
break
;
case
MAINTENANCE_IN
:
case
MAINTENANCE_OUT
:
case
SERVICE_ACTION_IN_12
:
case
SERVICE_ACTION_OUT_12
:
case
SERVICE_ACTION_IN_16
:
case
SERVICE_ACTION_OUT_16
:
sa
=
cdbp
[
1
]
&
0x1f
;
printk
(
"%scdb[0]=0x%x, sa=0x%x"
,
leadin
,
cdb0
,
sa
);
break
;
default:
if
(
cdb0
<
0xc0
)
printk
(
"%scdb[0]=0x%x"
,
leadin
,
cdb0
);
else
printk
(
"%scdb[0]=0x%x (vendor)"
,
leadin
,
cdb0
);
break
;
}
}
#endif
void
__scsi_print_command
(
unsigned
char
*
command
)
{
int
i
,
s
;
print_opcode
(
command
[
0
]);
for
(
i
=
1
,
s
=
COMMAND_SIZE
(
command
[
0
]);
i
<
s
;
++
i
)
printk
(
"%02x "
,
command
[
i
]);
printk
(
"
\n
"
);
void
__scsi_print_command
(
unsigned
char
*
command
)
{
int
k
,
len
;
print_opcode_name
(
command
,
0
,
1
);
if
(
VARIABLE_LENGTH_CMD
==
command
[
0
])
len
=
command
[
7
]
+
8
;
else
len
=
COMMAND_SIZE
(
command
[
0
]);
/* print out all bytes in cdb */
for
(
k
=
0
;
k
<
len
;
++
k
)
printk
(
" %02x"
,
command
[
k
]);
printk
(
"
\n
"
);
}
/* This function (perhaps with the addition of peripheral device type)
* is more approriate than __scsi_print_command(). Perhaps that static
* can be dropped later if it replaces the __scsi_print_command version.
*/
static
void
scsi_print_cdb
(
unsigned
char
*
cdb
,
int
cdb_len
,
int
start_of_line
)
{
int
k
;
print_opcode_name
(
cdb
,
cdb_len
,
start_of_line
);
/* print out all bytes in cdb */
printk
(
":"
);
for
(
k
=
0
;
k
<
cdb_len
;
++
k
)
printk
(
" %02x"
,
cdb
[
k
]);
printk
(
"
\n
"
);
}
/**
...
...
@@ -177,7 +381,7 @@ void __scsi_print_command (unsigned char *command) {
**/
void
scsi_print_status
(
unsigned
char
scsi_status
)
{
#if
(CONSTANTS & CONST_STATUS)
#if
def CONFIG_SCSI_CONSTANTS
const
char
*
ccp
;
switch
(
scsi_status
)
{
...
...
@@ -194,13 +398,13 @@ scsi_print_status(unsigned char scsi_status) {
case
0x40
:
ccp
=
"Task Aborted"
;
break
;
default:
ccp
=
"Unknown status"
;
}
printk
(
"%s"
,
ccp
);
printk
(
KERN_INFO
"%s"
,
ccp
);
#else
printk
(
"0x%0x"
,
scsi_status
);
printk
(
KERN_INFO
"0x%0x"
,
scsi_status
);
#endif
}
#if
(CONSTANTS & CONST_XSENSE)
#if
def CONFIG_SCSI_CONSTANTS
struct
error_info
{
unsigned
short
code12
;
/* 0x0302 looks better than 0x03,0x02 */
...
...
@@ -253,6 +457,8 @@ static struct error_info additional[] =
{
0x040C
,
"Logical unit not accessible, target port in unavailable "
"state"
},
{
0x0410
,
"Logical unit not ready, auxiliary memory not accessible"
},
{
0x0411
,
"Logical unit not ready, notify (enable spinup) required"
},
{
0x0412
,
"Logical unit not ready, offline"
},
{
0x0500
,
"Logical unit does not respond to selection"
},
...
...
@@ -300,7 +506,14 @@ static struct error_info additional[] =
{
0x0D04
,
"Copy target device data underrun"
},
{
0x0D05
,
"Copy target device data overrun"
},
{
0x0E00
,
"Invalid information unit"
},
{
0x0E01
,
"Information unit too short"
},
{
0x0E02
,
"Information unit too long"
},
{
0x1000
,
"Id CRC or ECC error"
},
{
0x1001
,
"Data block guard check failed"
},
{
0x1002
,
"Data block application tag check failed"
},
{
0x1003
,
"Data block reference tag check failed"
},
{
0x1100
,
"Unrecovered read error"
},
{
0x1101
,
"Read retries exhausted"
},
...
...
@@ -407,8 +620,10 @@ static struct error_info additional[] =
{
0x2400
,
"Invalid field in cdb"
},
{
0x2401
,
"CDB decryption error"
},
{
0x2402
,
"Obsolete"
},
{
0x2403
,
"Obsolete"
},
{
0x2404
,
"Security audit value frozen"
},
{
0x2405
,
"Security working key frozen"
},
{
0x2406
,
"Nonce not unique"
},
{
0x2407
,
"Nonce timestamp out of range"
},
{
0x2500
,
"Logical unit not supported"
},
...
...
@@ -426,6 +641,8 @@ static struct error_info additional[] =
{
0x260B
,
"Inline data length exceeded"
},
{
0x260C
,
"Invalid operation for copy source or destination"
},
{
0x260D
,
"Copy segment granularity violation"
},
{
0x260E
,
"Invalid parameter while port is enabled"
},
{
0x260F
,
"Invalid data-out buffer integrity"
},
{
0x2700
,
"Write protected"
},
{
0x2701
,
"Hardware write protected"
},
...
...
@@ -455,6 +672,8 @@ static struct error_info additional[] =
{
0x2A05
,
"Registrations preempted"
},
{
0x2A06
,
"Asymmetric access state changed"
},
{
0x2A07
,
"Implicit asymmetric access state transition failed"
},
{
0x2A08
,
"Priority changed"
},
{
0x2A09
,
"Capacity data has changed"
},
{
0x2B00
,
"Copy cannot execute since host cannot disconnect"
},
...
...
@@ -468,6 +687,8 @@ static struct error_info additional[] =
{
0x2C07
,
"Previous busy status"
},
{
0x2C08
,
"Previous task set full status"
},
{
0x2C09
,
"Previous reservation conflict status"
},
{
0x2C0A
,
"Partition or collection contains user objects"
},
{
0x2C0B
,
"Not reserved"
},
{
0x2D00
,
"Overwrite error on update in place"
},
...
...
@@ -485,6 +706,8 @@ static struct error_info additional[] =
{
0x3007
,
"Cleaning failure"
},
{
0x3008
,
"Cannot write - application code mismatch"
},
{
0x3009
,
"Current session not fixated for append"
},
{
0x300A
,
"Cleaning request rejected"
},
{
0x300C
,
"WORM medium, overwrite attempted"
},
{
0x3010
,
"Medium not formatted"
},
{
0x3100
,
"Medium format corrupted"
},
...
...
@@ -503,6 +726,7 @@ static struct error_info additional[] =
{
0x3502
,
"Enclosure services unavailable"
},
{
0x3503
,
"Enclosure services transfer failure"
},
{
0x3504
,
"Enclosure services transfer refused"
},
{
0x3505
,
"Enclosure services checksum error"
},
{
0x3600
,
"Ribbon, ink, or toner failure"
},
...
...
@@ -543,6 +767,7 @@ static struct error_info additional[] =
{
0x3B14
,
"Medium magazine locked"
},
{
0x3B15
,
"Medium magazine unlocked"
},
{
0x3B16
,
"Mechanical positioning or changer error"
},
{
0x3B17
,
"Read past end of user object"
},
{
0x3D00
,
"Invalid bits in identify message"
},
...
...
@@ -570,14 +795,12 @@ static struct error_info additional[] =
{
0x3F0F
,
"Echo buffer overwritten"
},
{
0x3F10
,
"Medium loadable"
},
{
0x3F11
,
"Medium auxiliary memory accessible"
},
#if 0
{0x40NN, "Ram failure"},
{0x40NN, "Diagnostic failure on component nn"},
{0x41NN, "Data path failure"},
{0x42NN, "Power-on or self-test failure"},
#endif
/*
* {0x40NN, "Ram failure"},
* {0x40NN, "Diagnostic failure on component nn"},
* {0x41NN, "Data path failure"},
* {0x42NN, "Power-on or self-test failure"},
*/
{
0x4300
,
"Message error"
},
{
0x4400
,
"Internal target failure"
},
...
...
@@ -592,6 +815,7 @@ static struct error_info additional[] =
{
0x4703
,
"Information unit CRC error detected"
},
{
0x4704
,
"Asynchronous information protection error detected"
},
{
0x4705
,
"Protocol service CRC error"
},
{
0x477f
,
"Some commands cleared by iSCSI Protocol event"
},
{
0x4800
,
"Initiator detected error message received"
},
...
...
@@ -600,13 +824,17 @@ static struct error_info additional[] =
{
0x4A00
,
"Command phase error"
},
{
0x4B00
,
"Data phase error"
},
{
0x4B01
,
"Invalid target port transfer tag received"
},
{
0x4B02
,
"Too much write data"
},
{
0x4B03
,
"Ack/nak timeout"
},
{
0x4B04
,
"Nak received"
},
{
0x4B05
,
"Data offset error"
},
{
0x4B06
,
"Initiator response timeout"
},
{
0x4C00
,
"Logical unit failed self-configuration"
},
#if 0
{0x4DNN, "Tagged overlapped commands (nn = queue tag)"},
#endif
/*
* {0x4DNN, "Tagged overlapped commands (nn = queue tag)"},
*/
{
0x4E00
,
"Overlapped commands attempted"
},
{
0x5000
,
"Write append error"
},
...
...
@@ -631,6 +859,7 @@ static struct error_info additional[] =
{
0x5504
,
"Insufficient registration resources"
},
{
0x5505
,
"Insufficient access control resources"
},
{
0x5506
,
"Auxiliary memory out of space"
},
{
0x5507
,
"Quota error"
},
{
0x5700
,
"Unable to recover table-of-contents"
},
...
...
@@ -806,11 +1035,9 @@ static struct error_info additional[] =
{
0x6F03
,
"Read of scrambled sector without authentication"
},
{
0x6F04
,
"Media region code is mismatched to logical unit region"
},
{
0x6F05
,
"Drive region must be permanent/region reset count error"
},
#if 0
{0x70NN, "Decompression exception short algorithm id of nn"},
#endif
/*
* {0x70NN, "Decompression exception short algorithm id of nn"},
*/
{
0x7100
,
"Decompression exception long algorithm id"
},
{
0x7200
,
"Session fixation error"
},
...
...
@@ -845,9 +1072,7 @@ static struct error_info2 additional2[] =
{
0x70
,
0x00
,
0xff
,
"Decompression exception short algorithm id of %x"
},
{
0
,
0
,
0
,
NULL
}
};
#endif
#if (CONSTANTS & CONST_SENSE)
/* description of the sense key values */
static
const
char
*
snstext
[]
=
{
"No Sense"
,
/* 0: There is no sense information */
...
...
@@ -858,11 +1083,11 @@ static const char *snstext[] = {
"Hardware Error"
,
/* 4: Controller or device failure */
"Illegal Request"
,
/* 5: Error in request */
"Unit Attention"
,
/* 6: Removable medium was changed, or
the target has been reset */
the target has been reset
, or ...
*/
"Data Protect"
,
/* 7: Access to the data is blocked */
"Blank Check"
,
/* 8: Reached unexpected written or unwritten
region of the medium */
"Vendor Specific
"
,
/* 9: Vendor specific */
"Vendor Specific
(9)"
,
"Copy Aborted"
,
/* A: COPY or COMPARE was aborted */
"Aborted Command"
,
/* B: The target aborted the command */
"Equal"
,
/* C: A SEARCH DATA command found data equal */
...
...
@@ -875,7 +1100,7 @@ static const char *snstext[] = {
/* Get sense key string or NULL if not available */
const
char
*
scsi_sense_key_string
(
unsigned
char
key
)
{
#if
(CONSTANTS & CONST_SENSE)
#if
def CONFIG_SCSI_CONSTANTS
if
(
key
<=
0xE
)
return
snstext
[
key
];
#endif
...
...
@@ -883,12 +1108,12 @@ scsi_sense_key_string(unsigned char key) {
}
/*
* Get
extended sense key
string or NULL if not available.
* This string may contain a
%x and must
be printed with ascq as arg.
* Get
additional sense code
string or NULL if not available.
* This string may contain a
"%x" and should
be printed with ascq as arg.
*/
const
char
*
scsi_extd_sense_format
(
unsigned
char
asc
,
unsigned
char
ascq
)
{
#if
(CONSTANTS & CONST_XSENSE)
#if
def CONFIG_SCSI_CONSTANTS
int
i
;
unsigned
short
code
=
((
asc
<<
8
)
|
ascq
);
...
...
@@ -904,17 +1129,25 @@ scsi_extd_sense_format(unsigned char asc, unsigned char ascq) {
return
NULL
;
}
/* Print extended sense information */
/* Print extended sense information
; no leadin, no linefeed
*/
static
void
scsi_show_extd_sense
(
unsigned
char
asc
,
unsigned
char
ascq
)
{
scsi_show_extd_sense
(
unsigned
char
asc
,
unsigned
char
ascq
)
{
const
char
*
extd_sense_fmt
=
scsi_extd_sense_format
(
asc
,
ascq
);
if
(
extd_sense_fmt
)
{
printk
(
"Additional sense: "
);
printk
(
extd_sense_fmt
,
ascq
);
printk
(
"
\n
"
);
if
(
strstr
(
extd_sense_fmt
,
"%x"
))
{
printk
(
"Additional sense: "
);
printk
(
extd_sense_fmt
,
ascq
);
}
else
printk
(
"Additional sense: %s"
,
extd_sense_fmt
);
}
else
{
printk
(
"ASC=%2x ASCQ=%2x
\n
"
,
asc
,
ascq
);
if
(
asc
>=
0x80
)
printk
(
"<<vendor>> ASC=0x%x ASCQ=0x%x"
,
asc
,
ascq
);
if
(
ascq
>=
0x80
)
printk
(
"ASC=0x%x <<vendor>> ASCQ=0x%x"
,
asc
,
ascq
);
else
printk
(
"ASC=0x%x ASCQ=0x%x"
,
asc
,
ascq
);
}
}
...
...
@@ -922,112 +1155,115 @@ scsi_show_extd_sense(unsigned char asc, unsigned char ascq) {
static
void
print_sense_internal
(
const
char
*
devclass
,
const
unsigned
char
*
sense_buffer
,
int
sense_len
,
struct
request
*
req
)
{
int
s
,
sense_class
,
valid
,
code
,
info
;
const
char
*
error
=
NULL
;
unsigned
char
asc
,
ascq
;
int
k
,
num
,
res
;
unsigned
int
info
;
const
char
*
error
;
const
char
*
sense_txt
;
const
char
*
name
=
req
->
rq_disk
?
req
->
rq_disk
->
disk_name
:
devclass
;
struct
scsi_sense_hdr
ssh
;
sense_class
=
(
sense_buffer
[
0
]
>>
4
)
&
0x07
;
code
=
sense_buffer
[
0
]
&
0xf
;
valid
=
sense_buffer
[
0
]
&
0x80
;
if
(
sense_class
==
7
)
{
/* extended sense data */
s
=
sense_buffer
[
7
]
+
8
;
if
(
s
>
SCSI_SENSE_BUFFERSIZE
)
s
=
SCSI_SENSE_BUFFERSIZE
;
info
=
((
sense_buffer
[
3
]
<<
24
)
|
(
sense_buffer
[
4
]
<<
16
)
|
(
sense_buffer
[
5
]
<<
8
)
|
sense_buffer
[
6
]);
if
(
info
||
valid
)
{
printk
(
"Info fld=0x%x"
,
info
);
if
(
!
valid
)
/* info data not according to standard */
printk
(
" (nonstd)"
);
printk
(
", "
);
}
if
(
sense_buffer
[
2
]
&
0x80
)
printk
(
"FMK "
);
/* current command has read a filemark */
if
(
sense_buffer
[
2
]
&
0x40
)
printk
(
"EOM "
);
/* end-of-medium condition exists */
if
(
sense_buffer
[
2
]
&
0x20
)
printk
(
"ILI "
);
/* incorrect block length requested */
switch
(
code
)
{
case
0x0
:
error
=
"Current"
;
/* error concerns current command */
break
;
case
0x1
:
error
=
"Deferred"
;
/* error concerns some earlier command */
/* e.g., an earlier write to disk cache succeeded, but
now the disk discovers that it cannot write the data */
break
;
default:
error
=
"Invalid"
;
res
=
scsi_normalize_sense
(
sense_buffer
,
sense_len
,
&
ssh
);
if
(
0
==
res
)
{
/* this may be SCSI-1 sense data */
num
=
(
sense_len
<
32
)
?
sense_len
:
32
;
printk
(
KERN_INFO
"Unrecognized sense data (in hex):"
);
for
(
k
=
0
;
k
<
num
;
++
k
)
{
if
(
0
==
(
k
%
16
))
{
printk
(
"
\n
"
);
printk
(
KERN_INFO
" "
);
}
printk
(
"%02x "
,
sense_buffer
[
k
]);
}
printk
(
"
\n
"
);
return
;
}
printk
(
"%s "
,
error
);
/* An example of deferred is when an earlier write to disk cache
* succeeded, but now the disk discovers that it cannot write the
* data to the magnetic media.
*/
error
=
scsi_sense_is_deferred
(
&
ssh
)
?
"<<DEFERRED>>"
:
"Current"
;
printk
(
KERN_INFO
"%s: %s"
,
name
,
error
);
if
(
ssh
.
response_code
>=
0x72
)
printk
(
" [descriptor]"
);
sense_txt
=
scsi_sense_key_string
(
ssh
.
sense_key
);
if
(
sense_txt
)
printk
(
": sense key: %s
\n
"
,
sense_txt
);
else
printk
(
": sense key=0x%x
\n
"
,
ssh
.
sense_key
);
printk
(
KERN_INFO
" "
);
scsi_show_extd_sense
(
ssh
.
asc
,
ssh
.
ascq
);
printk
(
"
\n
"
);
sense_txt
=
scsi_sense_key_string
(
sense_buffer
[
2
]);
if
(
sense_txt
)
printk
(
"%s: sense key %s
\n
"
,
name
,
sense_txt
);
else
printk
(
"%s: sense = %2x %2x
\n
"
,
name
,
sense_buffer
[
0
],
sense_buffer
[
2
]);
if
(
ssh
.
response_code
<
0x72
)
{
/* only decode extras for "fixed" format now */
char
buff
[
80
];
int
blen
,
fixed_valid
;
asc
=
ascq
=
0
;
if
(
sense_buffer
[
7
]
+
7
>=
13
)
{
asc
=
sense_buffer
[
12
];
ascq
=
sense_buffer
[
13
];
fixed_valid
=
sense_buffer
[
0
]
&
0x80
;
info
=
((
sense_buffer
[
3
]
<<
24
)
|
(
sense_buffer
[
4
]
<<
16
)
|
(
sense_buffer
[
5
]
<<
8
)
|
sense_buffer
[
6
]);
res
=
0
;
memset
(
buff
,
0
,
sizeof
(
buff
));
blen
=
sizeof
(
buff
)
-
1
;
if
(
fixed_valid
)
res
+=
snprintf
(
buff
+
res
,
blen
-
res
,
"Info fld=0x%x"
,
info
);
if
(
sense_buffer
[
2
]
&
0x80
)
{
/* current command has read a filemark */
if
(
res
>
0
)
res
+=
snprintf
(
buff
+
res
,
blen
-
res
,
", "
);
res
+=
snprintf
(
buff
+
res
,
blen
-
res
,
"FMK"
);
}
if
(
asc
||
ascq
)
scsi_show_extd_sense
(
asc
,
ascq
);
}
else
{
/* non-extended sense data */
/*
* Standard says:
* sense_buffer[0] & 0200 : address valid
* sense_buffer[0] & 0177 : vendor-specific error code
* sense_buffer[1] & 0340 : vendor-specific
* sense_buffer[1..3] : 21-bit logical block address
*/
sense_txt
=
scsi_sense_key_string
(
sense_buffer
[
0
]);
if
(
sense_txt
)
printk
(
"%s: old sense key %s
\n
"
,
name
,
sense_txt
);
else
printk
(
"%s: sense = %2x %2x
\n
"
,
name
,
sense_buffer
[
0
],
sense_buffer
[
2
]);
printk
(
"Non-extended sense class %d code 0x%0x
\n
"
,
sense_class
,
code
);
s
=
4
;
}
#if !(CONSTANTS & CONST_SENSE)
{
int
i
;
printk
(
"Raw sense data:"
);
for
(
i
=
0
;
i
<
s
;
++
i
)
printk
(
"0x%02x "
,
sense_buffer
[
i
]);
printk
(
"
\n
"
);
if
(
sense_buffer
[
2
]
&
0x40
)
{
/* end-of-medium condition exists */
if
(
res
>
0
)
res
+=
snprintf
(
buff
+
res
,
blen
-
res
,
", "
);
res
+=
snprintf
(
buff
+
res
,
blen
-
res
,
"EOM"
);
}
if
(
sense_buffer
[
2
]
&
0x20
)
{
/* incorrect block length requested */
if
(
res
>
0
)
res
+=
snprintf
(
buff
+
res
,
blen
-
res
,
", "
);
res
+=
snprintf
(
buff
+
res
,
blen
-
res
,
"ILI"
);
}
if
(
res
>
0
)
printk
(
KERN_INFO
"%s
\n
"
,
buff
);
}
else
if
(
ssh
.
additional_length
>
0
)
{
/* descriptor format with sense descriptors */
num
=
8
+
ssh
.
additional_length
;
num
=
(
sense_len
<
num
)
?
sense_len
:
num
;
printk
(
KERN_INFO
"Descriptor sense data with sense "
"descriptors (in hex):"
);
for
(
k
=
0
;
k
<
num
;
++
k
)
{
if
(
0
==
(
k
%
16
))
{
printk
(
"
\n
"
);
printk
(
KERN_INFO
" "
);
}
printk
(
"%02x "
,
sense_buffer
[
k
]);
}
printk
(
"
\n
"
);
}
#endif
}
void
scsi_print_sense
(
const
char
*
devclass
,
struct
scsi_cmnd
*
cmd
)
{
print_sense_internal
(
devclass
,
cmd
->
sense_buffer
,
cmd
->
request
);
print_sense_internal
(
devclass
,
cmd
->
sense_buffer
,
SCSI_SENSE_BUFFERSIZE
,
cmd
->
request
);
}
void
scsi_print_req_sense
(
const
char
*
devclass
,
struct
scsi_request
*
sreq
)
{
print_sense_internal
(
devclass
,
sreq
->
sr_sense_buffer
,
sreq
->
sr_request
);
print_sense_internal
(
devclass
,
sreq
->
sr_sense_buffer
,
SCSI_SENSE_BUFFERSIZE
,
sreq
->
sr_request
);
}
#if
(CONSTANTS & CONST_MSG)
#if
def CONFIG_SCSI_CONSTANTS
static
const
char
*
one_byte_msgs
[]
=
{
/* 0x00 */
"Command Complete"
,
NULL
,
"Save Pointers"
,
/* 0x03 */
"Restore Pointers"
,
"Disconnect"
,
"Initiator Error"
,
...
...
@@ -1036,161 +1272,164 @@ static const char *one_byte_msgs[] = {
/* 0x0c */
"Bus device reset"
,
"Abort Tag"
,
"Clear Queue"
,
/* 0x0f */
"Initiate Recovery"
,
"Release Recovery"
};
#define NO_ONE_BYTE_MSGS (sizeof(one_byte_msgs) / sizeof (const char *))
static
const
char
*
two_byte_msgs
[]
=
{
/* 0x20 */
"Simple Queue Tag"
,
"Head of Queue Tag"
,
"Ordered Queue Tag"
/* 0x23 */
"Ignore Wide Residue"
};
#define NO_TWO_BYTE_MSGS (sizeof(two_byte_msgs) / sizeof (const char *))
static
const
char
*
extended_msgs
[]
=
{
/* 0x00 */
"Modify Data Pointer"
,
"Synchronous Data Transfer Request"
,
/* 0x02 */
"SCSI-I Extended Identify"
,
"Wide Data Transfer Request"
};
#define NO_EXTENDED_MSGS (sizeof(two_byte_msgs) / sizeof (const char *))
#endif
/* (CONSTANTS & CONST_MSG) */
int
scsi_print_msg
(
const
unsigned
char
*
msg
)
{
int
len
=
0
,
i
;
if
(
msg
[
0
]
==
EXTENDED_MESSAGE
)
{
len
=
3
+
msg
[
1
];
#if (CONSTANTS & CONST_MSG)
if
(
msg
[
2
]
<
NO_EXTENDED_MSGS
)
printk
(
"%s "
,
extended_msgs
[
msg
[
2
]]);
else
printk
(
"Extended Message, reserved code (0x%02x) "
,
(
int
)
msg
[
2
]);
switch
(
msg
[
2
])
{
case
EXTENDED_MODIFY_DATA_POINTER
:
printk
(
"pointer = %d"
,
(
int
)
(
msg
[
3
]
<<
24
)
|
(
msg
[
4
]
<<
16
)
|
(
msg
[
5
]
<<
8
)
|
msg
[
6
]);
break
;
case
EXTENDED_SDTR
:
printk
(
"period = %d ns, offset = %d"
,
(
int
)
msg
[
3
]
*
4
,
(
int
)
msg
[
4
]);
break
;
case
EXTENDED_WDTR
:
printk
(
"width = 2^%d bytes"
,
msg
[
3
]);
break
;
default:
for
(
i
=
2
;
i
<
len
;
++
i
)
printk
(
"%02x "
,
msg
[
i
]);
}
#else
for
(
i
=
0
;
i
<
len
;
++
i
)
printk
(
"%02x "
,
msg
[
i
]);
#endif
int
scsi_print_msg
(
const
unsigned
char
*
msg
)
{
int
len
=
0
,
i
;
if
(
msg
[
0
]
==
EXTENDED_MESSAGE
)
{
len
=
3
+
msg
[
1
];
if
(
msg
[
2
]
<
NO_EXTENDED_MSGS
)
printk
(
"%s "
,
extended_msgs
[
msg
[
2
]]);
else
printk
(
"Extended Message, reserved code (0x%02x) "
,
(
int
)
msg
[
2
]);
switch
(
msg
[
2
])
{
case
EXTENDED_MODIFY_DATA_POINTER
:
printk
(
"pointer = %d"
,
(
int
)
(
msg
[
3
]
<<
24
)
|
(
msg
[
4
]
<<
16
)
|
(
msg
[
5
]
<<
8
)
|
msg
[
6
]);
break
;
case
EXTENDED_SDTR
:
printk
(
"period = %d ns, offset = %d"
,
(
int
)
msg
[
3
]
*
4
,
(
int
)
msg
[
4
]);
break
;
case
EXTENDED_WDTR
:
printk
(
"width = 2^%d bytes"
,
msg
[
3
]);
break
;
default:
for
(
i
=
2
;
i
<
len
;
++
i
)
printk
(
"%02x "
,
msg
[
i
]);
}
/* Identify */
}
else
if
(
msg
[
0
]
&
0x80
)
{
#if (CONSTANTS & CONST_MSG)
printk
(
"Identify disconnect %sallowed %s %d "
,
(
msg
[
0
]
&
0x40
)
?
""
:
"not "
,
(
msg
[
0
]
&
0x20
)
?
"target routine"
:
"lun"
,
msg
[
0
]
&
0x7
);
#else
printk
(
"%02x "
,
msg
[
0
]);
#endif
len
=
1
;
}
else
if
(
msg
[
0
]
&
0x80
)
{
printk
(
"Identify disconnect %sallowed %s %d "
,
(
msg
[
0
]
&
0x40
)
?
""
:
"not "
,
(
msg
[
0
]
&
0x20
)
?
"target routine"
:
"lun"
,
msg
[
0
]
&
0x7
);
len
=
1
;
/* Normal One byte */
}
else
if
(
msg
[
0
]
<
0x1f
)
{
#if (CONSTANTS & CONST_MSG)
if
(
msg
[
0
]
<
NO_ONE_BYTE_MSGS
)
printk
(
one_byte_msgs
[
msg
[
0
]]);
else
printk
(
"reserved (%02x) "
,
msg
[
0
]);
#else
printk
(
"%02x "
,
msg
[
0
]);
#endif
len
=
1
;
}
else
if
(
msg
[
0
]
<
0x1f
)
{
if
(
msg
[
0
]
<
NO_ONE_BYTE_MSGS
)
printk
(
one_byte_msgs
[
msg
[
0
]]);
else
printk
(
"reserved (%02x) "
,
msg
[
0
]);
len
=
1
;
/* Two byte */
}
else
if
(
msg
[
0
]
<=
0x2f
)
{
#if (CONSTANTS & CONST_MSG)
if
((
msg
[
0
]
-
0x20
)
<
NO_TWO_BYTE_MSGS
)
printk
(
"%s %02x "
,
two_byte_msgs
[
msg
[
0
]
-
0x20
],
msg
[
1
]);
else
printk
(
"reserved two byte (%02x %02x) "
,
msg
[
0
],
msg
[
1
]);
#else
printk
(
"%02x %02x"
,
msg
[
0
],
msg
[
1
]);
#endif
len
=
2
;
}
else
#if (CONSTANTS & CONST_MSG)
printk
(
reserved
);
#else
printk
(
"%02x "
,
msg
[
0
]);
#endif
return
len
;
}
else
if
(
msg
[
0
]
<=
0x2f
)
{
if
((
msg
[
0
]
-
0x20
)
<
NO_TWO_BYTE_MSGS
)
printk
(
"%s %02x "
,
two_byte_msgs
[
msg
[
0
]
-
0x20
],
msg
[
1
]);
else
printk
(
"reserved two byte (%02x %02x) "
,
msg
[
0
],
msg
[
1
]);
len
=
2
;
}
else
printk
(
"reserved"
);
return
len
;
}
#else
/* ifndef CONFIG_SCSI_CONSTANTS */
int
scsi_print_msg
(
const
unsigned
char
*
msg
)
{
int
len
=
0
,
i
;
if
(
msg
[
0
]
==
EXTENDED_MESSAGE
)
{
len
=
3
+
msg
[
1
];
for
(
i
=
0
;
i
<
len
;
++
i
)
printk
(
"%02x "
,
msg
[
i
]);
/* Identify */
}
else
if
(
msg
[
0
]
&
0x80
)
{
printk
(
"%02x "
,
msg
[
0
]);
len
=
1
;
/* Normal One byte */
}
else
if
(
msg
[
0
]
<
0x1f
)
{
printk
(
"%02x "
,
msg
[
0
]);
len
=
1
;
/* Two byte */
}
else
if
(
msg
[
0
]
<=
0x2f
)
{
printk
(
"%02x %02x"
,
msg
[
0
],
msg
[
1
]);
len
=
2
;
}
else
printk
(
"%02x "
,
msg
[
0
]);
return
len
;
}
#endif
/* ! CONFIG_SCSI_CONSTANTS */
void
scsi_print_command
(
struct
scsi_cmnd
*
cmd
)
{
printk
(
"scsi%d : destination target %d, lun %d
\n
"
,
cmd
->
device
->
host
->
host_no
,
cmd
->
device
->
id
,
cmd
->
device
->
lun
);
printk
(
" command = "
);
__scsi_print_command
(
cmd
->
cmnd
);
void
scsi_print_command
(
struct
scsi_cmnd
*
cmd
)
{
/* Assume appended output (i.e. not at start of line) */
printk
(
"scsi%d : destination target %d, lun %d
\n
"
,
cmd
->
device
->
host
->
host_no
,
cmd
->
device
->
id
,
cmd
->
device
->
lun
);
printk
(
KERN_INFO
" command: "
);
scsi_print_cdb
(
cmd
->
cmnd
,
cmd
->
cmd_len
,
0
);
}
#if (CONSTANTS & CONST_HOST)
#ifdef CONFIG_SCSI_CONSTANTS
static
const
char
*
hostbyte_table
[]
=
{
"DID_OK"
,
"DID_NO_CONNECT"
,
"DID_BUS_BUSY"
,
"DID_TIME_OUT"
,
"DID_BAD_TARGET"
,
"DID_ABORT"
,
"DID_PARITY"
,
"DID_ERROR"
,
"DID_RESET"
,
"DID_BAD_INTR"
,
"DID_PASSTHROUGH"
,
"DID_SOFT_ERROR"
,
"DID_IMM_RETRY"
,
NULL
};
"DID_PASSTHROUGH"
,
"DID_SOFT_ERROR"
,
"DID_IMM_RETRY"
};
#define NUM_HOSTBYTE_STRS (sizeof(hostbyte_table) / sizeof(const char *))
void
scsi_print_hostbyte
(
int
scsiresult
)
{
static
int
maxcode
=
0
;
int
i
;
if
(
!
maxcode
)
{
for
(
i
=
0
;
hostbyte_table
[
i
];
i
++
)
;
maxcode
=
i
-
1
;
}
printk
(
"Hostbyte=0x%02x"
,
host_byte
(
scsiresult
));
if
(
host_byte
(
scsiresult
)
>
maxcode
)
{
printk
(
"is invalid "
);
return
;
}
printk
(
"(%s) "
,
hostbyte_table
[
host_byte
(
scsiresult
)]);
{
int
hb
=
host_byte
(
scsiresult
);
printk
(
"Hostbyte=0x%02x"
,
hb
);
if
(
hb
<
NUM_HOSTBYTE_STRS
)
printk
(
"(%s) "
,
hostbyte_table
[
hb
]);
else
printk
(
"is invalid "
);
}
#else
void
scsi_print_hostbyte
(
int
scsiresult
)
{
printk
(
"Hostbyte=0x%02x "
,
host_byte
(
scsiresult
));
{
printk
(
"Hostbyte=0x%02x "
,
host_byte
(
scsiresult
));
}
#endif
#if (CONSTANTS & CONST_DRIVER)
#ifdef CONFIG_SCSI_CONSTANTS
static
const
char
*
driverbyte_table
[]
=
{
"DRIVER_OK"
,
"DRIVER_BUSY"
,
"DRIVER_SOFT"
,
"DRIVER_MEDIA"
,
"DRIVER_ERROR"
,
"DRIVER_INVALID"
,
"DRIVER_TIMEOUT"
,
"DRIVER_HARD"
,
NULL
};
"DRIVER_INVALID"
,
"DRIVER_TIMEOUT"
,
"DRIVER_HARD"
,
"DRIVER_SENSE"
};
#define NUM_DRIVERBYTE_STRS (sizeof(driverbyte_table) / sizeof(const char *))
static
const
char
*
driversuggest_table
[]
=
{
"SUGGEST_OK"
,
"SUGGEST_RETRY"
,
"SUGGEST_ABORT"
,
"SUGGEST_REMAP"
,
"SUGGEST_DIE"
,
unknown
,
unknown
,
unknown
,
"SUGGEST_SENSE"
,
NULL
};
"SUGGEST_5"
,
"SUGGEST_6"
,
"SUGGEST_7"
,
"SUGGEST_SENSE"
};
#define NUM_SUGGEST_STRS (sizeof(driversuggest_table) / sizeof(const char *))
void
scsi_print_driverbyte
(
int
scsiresult
)
{
static
int
driver_max
=
0
,
suggest_max
=
0
;
int
i
,
dr
=
driver_byte
(
scsiresult
)
&
DRIVER_MASK
,
su
=
(
driver_byte
(
scsiresult
)
&
SUGGEST_MASK
)
>>
4
;
if
(
!
driver_max
)
{
for
(
i
=
0
;
driverbyte_table
[
i
];
i
++
)
;
driver_max
=
i
;
for
(
i
=
0
;
driversuggest_table
[
i
];
i
++
)
;
suggest_max
=
i
;
}
printk
(
"Driverbyte=0x%02x"
,
driver_byte
(
scsiresult
));
printk
(
"(%s,%s) "
,
dr
<
driver_max
?
driverbyte_table
[
dr
]
:
"invalid"
,
su
<
suggest_max
?
driversuggest_table
[
su
]
:
"invalid"
);
{
int
dr
=
(
driver_byte
(
scsiresult
)
&
DRIVER_MASK
);
int
su
=
((
driver_byte
(
scsiresult
)
&
SUGGEST_MASK
)
>>
4
);
printk
(
"Driverbyte=0x%02x "
,
driver_byte
(
scsiresult
));
printk
(
"(%s,%s) "
,
(
dr
<
NUM_DRIVERBYTE_STRS
?
driverbyte_table
[
dr
]
:
"invalid"
),
(
su
<
NUM_SUGGEST_STRS
?
driversuggest_table
[
su
]
:
"invalid"
));
}
#else
void
scsi_print_driverbyte
(
int
scsiresult
)
{
printk
(
"Driverbyte=0x%02x "
,
driver_byte
(
scsiresult
));
{
printk
(
"Driverbyte=0x%02x "
,
driver_byte
(
scsiresult
));
}
#endif
drivers/scsi/hosts.c
View file @
ac4646f7
...
...
@@ -79,6 +79,8 @@ void scsi_remove_host(struct Scsi_Host *shost)
set_bit
(
SHOST_DEL
,
&
shost
->
shost_state
);
if
(
shost
->
transportt
->
host_destroy
)
shost
->
transportt
->
host_destroy
(
shost
);
class_device_unregister
(
&
shost
->
shost_classdev
);
if
(
shost
->
transport_classdev
.
class
)
class_device_unregister
(
&
shost
->
transport_classdev
);
...
...
@@ -133,11 +135,14 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
error
=
scsi_sysfs_add_host
(
shost
);
if
(
error
)
goto
out_de
l_classdev
;
goto
out_de
stroy_host
;
scsi_proc_host_add
(
shost
);
return
error
;
out_destroy_host:
if
(
shost
->
transportt
->
host_destroy
)
shost
->
transportt
->
host_destroy
(
shost
);
out_del_classdev:
class_device_del
(
&
shost
->
shost_classdev
);
out_del_gendev:
...
...
drivers/scsi/scsi_debug.c
View file @
ac4646f7
...
...
@@ -55,8 +55,8 @@
#include "scsi_logging.h"
#include "scsi_debug.h"
#define SCSI_DEBUG_VERSION "1.7
4
"
static
const
char
*
scsi_debug_version_date
=
"2004
0829
"
;
#define SCSI_DEBUG_VERSION "1.7
5
"
static
const
char
*
scsi_debug_version_date
=
"2004
1023
"
;
/* Additional Sense Code (ASC) used */
#define NO_ADDED_SENSE 0x0
...
...
@@ -82,7 +82,7 @@ static const char * scsi_debug_version_date = "20040829";
#define DEF_EVERY_NTH 0
#define DEF_NUM_PARTS 0
#define DEF_OPTS 0
#define DEF_SCSI_LEVEL
4
/* SPC-2
*/
#define DEF_SCSI_LEVEL
5
/* INQUIRY, byte2 [5->SPC-3]
*/
#define DEF_PTYPE 0
#define DEF_D_SENSE 0
...
...
@@ -95,6 +95,13 @@ static const char * scsi_debug_version_date = "20040829";
* - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
* - a RECOVERED_ERROR is simulated on successful read and write
* commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
*
* When "every_nth" < 0 then after "- 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
* commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
* This will continue until some other action occurs (e.g. the user
* writing a new value (other than -1 or 1) to every_nth via sysfs).
*/
/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
...
...
@@ -195,14 +202,12 @@ static Scsi_Host_Template sdebug_driver_template = {
.
cmd_per_lun
=
3
,
.
max_sectors
=
4096
,
.
unchecked_isa_dma
=
0
,
.
use_clustering
=
EN
ABLE_CLUSTERING
,
.
use_clustering
=
DIS
ABLE_CLUSTERING
,
.
module
=
THIS_MODULE
,
};
static
unsigned
char
*
fake_storep
;
/* ramdisk storage */
static
unsigned
char
spare_buff
[
SDEBUG_SENSE_LEN
];
static
int
num_aborts
=
0
;
static
int
num_dev_resets
=
0
;
static
int
num_bus_resets
=
0
;
...
...
@@ -228,21 +233,28 @@ static const int check_condition_result =
(
DRIVER_SENSE
<<
24
)
|
SAM_STAT_CHECK_CONDITION
;
/* function declarations */
static
int
resp_inquiry
(
unsigned
char
*
cmd
,
int
target
,
unsigned
char
*
buff
,
int
bufflen
,
struct
sdebug_dev_info
*
devip
);
static
int
resp_mode_sense
(
unsigned
char
*
cmd
,
int
target
,
unsigned
char
*
buff
,
int
bufflen
,
static
int
resp_inquiry
(
struct
scsi_cmnd
*
SCpnt
,
int
target
,
struct
sdebug_dev_info
*
devip
);
static
int
resp_requests
(
struct
scsi_cmnd
*
SCpnt
,
struct
sdebug_dev_info
*
devip
);
static
int
resp_readcap
(
struct
scsi_cmnd
*
SCpnt
,
struct
sdebug_dev_info
*
devip
);
static
int
resp_mode_sense
(
struct
scsi_cmnd
*
SCpnt
,
int
target
,
struct
sdebug_dev_info
*
devip
);
static
int
resp_read
(
struct
scsi_cmnd
*
SCpnt
,
int
upper_blk
,
int
block
,
int
num
,
struct
sdebug_dev_info
*
devip
);
static
int
resp_write
(
struct
scsi_cmnd
*
SCpnt
,
int
upper_blk
,
int
block
,
int
num
,
struct
sdebug_dev_info
*
devip
);
static
int
resp_report_luns
(
unsigned
char
*
cmd
,
unsigned
char
*
buff
,
int
bufflen
,
struct
sdebug_dev_info
*
devip
);
static
int
resp_report_luns
(
struct
scsi_cmnd
*
SCpnt
,
struct
sdebug_dev_info
*
devip
);
static
int
fill_from_dev_buffer
(
struct
scsi_cmnd
*
scp
,
unsigned
char
*
arr
,
int
arr_len
);
static
int
fetch_to_dev_buffer
(
struct
scsi_cmnd
*
scp
,
unsigned
char
*
arr
,
int
max_arr_len
);
static
void
timer_intr_handler
(
unsigned
long
);
static
struct
sdebug_dev_info
*
devInfoReg
(
struct
scsi_device
*
sdev
);
static
void
mk_sense_buffer
(
struct
sdebug_dev_info
*
devip
,
int
key
,
int
asc
,
int
asq
,
int
inbandLen
);
int
asc
,
int
asq
);
static
int
check_reset
(
struct
scsi_cmnd
*
SCpnt
,
struct
sdebug_dev_info
*
devip
);
static
int
schedule_resp
(
struct
scsi_cmnd
*
cmnd
,
...
...
@@ -264,49 +276,20 @@ static void sdebug_max_tgts_luns(void);
static
struct
device
pseudo_primary
;
static
struct
bus_type
pseudo_lld_bus
;
static
unsigned
char
*
scatg2virt
(
const
struct
scatterlist
*
sclp
)
{
if
(
NULL
==
sclp
)
return
NULL
;
else
if
(
sclp
->
page
)
return
(
unsigned
char
*
)
page_address
(
sclp
->
page
)
+
sclp
->
offset
;
else
return
NULL
;
}
static
int
scsi_debug_queuecommand
(
struct
scsi_cmnd
*
SCpnt
,
done_funct_t
done
)
{
unsigned
char
*
cmd
=
(
unsigned
char
*
)
SCpnt
->
cmnd
;
int
block
,
upper_blk
,
num
,
k
;
unsigned
char
*
buff
;
int
errsts
=
0
;
int
target
=
SCpnt
->
device
->
id
;
int
bufflen
=
SCpnt
->
request_bufflen
;
unsigned
long
capac
;
struct
sdebug_dev_info
*
devip
=
NULL
;
unsigned
char
*
sbuff
;
int
inj_recovered
=
0
;
if
(
done
==
NULL
)
return
0
;
/* assume mid level reprocessing command */
if
(
SCpnt
->
use_sg
)
{
/* just use first element */
struct
scatterlist
*
sgpnt
=
(
struct
scatterlist
*
)
SCpnt
->
request_buffer
;
buff
=
scatg2virt
(
&
sgpnt
[
0
]);
bufflen
=
sgpnt
[
0
].
length
;
/* READ and WRITE process scatterlist themselves */
}
else
buff
=
(
unsigned
char
*
)
SCpnt
->
request_buffer
;
if
(
NULL
==
buff
)
{
buff
=
spare_buff
;
/* assume cmd moves no data */
bufflen
=
SDEBUG_SENSE_LEN
;
}
if
((
SCSI_DEBUG_OPT_NOISE
&
scsi_debug_opts
)
&&
cmd
)
{
printk
(
KERN_INFO
"scsi_debug: cmd "
);
for
(
k
=
0
,
num
=
SCpnt
->
cmd_len
;
k
<
num
;
++
k
)
...
...
@@ -328,9 +311,11 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
return
schedule_resp
(
SCpnt
,
NULL
,
done
,
DID_NO_CONNECT
<<
16
,
0
);
if
((
scsi_debug_every_nth
>
0
)
&&
(
++
scsi_debug_cmnd_count
>=
scsi_debug_every_nth
))
{
scsi_debug_cmnd_count
=
0
;
if
((
scsi_debug_every_nth
!=
0
)
&&
(
++
scsi_debug_cmnd_count
>=
abs
(
scsi_debug_every_nth
)))
{
scsi_debug_cmnd_count
=
0
;
if
(
scsi_debug_every_nth
<
-
1
)
scsi_debug_every_nth
=
-
1
;
if
(
SCSI_DEBUG_OPT_TIMEOUT
&
scsi_debug_opts
)
return
0
;
/* ignore command causing timeout */
else
if
(
SCSI_DEBUG_OPT_RECOVERED_ERR
&
scsi_debug_opts
)
...
...
@@ -339,23 +324,14 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
switch
(
*
cmd
)
{
case
INQUIRY
:
/* mandatory, ignore unit attention */
errsts
=
resp_inquiry
(
cmd
,
target
,
buff
,
bufflen
,
devip
);
errsts
=
resp_inquiry
(
SCpnt
,
target
,
devip
);
break
;
case
REQUEST_SENSE
:
/* mandatory, ignore unit attention */
if
(
devip
)
{
sbuff
=
devip
->
sense_buff
;
memcpy
(
buff
,
sbuff
,
(
bufflen
<
SDEBUG_SENSE_LEN
)
?
bufflen
:
SDEBUG_SENSE_LEN
);
mk_sense_buffer
(
devip
,
0
,
NO_ADDED_SENSE
,
0
,
7
);
}
else
{
memset
(
buff
,
0
,
bufflen
);
buff
[
0
]
=
0x70
;
}
errsts
=
resp_requests
(
SCpnt
,
devip
);
break
;
case
REZERO_UNIT
:
/* actually this is REWIND for SSC */
case
START_STOP
:
errsts
=
check_reset
(
SCpnt
,
devip
);
memset
(
buff
,
0
,
bufflen
);
break
;
case
ALLOW_MEDIUM_REMOVAL
:
if
((
errsts
=
check_reset
(
SCpnt
,
devip
)))
...
...
@@ -366,40 +342,24 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
break
;
case
SEND_DIAGNOSTIC
:
/* mandatory */
errsts
=
check_reset
(
SCpnt
,
devip
);
memset
(
buff
,
0
,
bufflen
);
break
;
case
TEST_UNIT_READY
:
/* mandatory */
errsts
=
check_reset
(
SCpnt
,
devip
);
memset
(
buff
,
0
,
bufflen
);
break
;
case
RESERVE
:
errsts
=
check_reset
(
SCpnt
,
devip
);
memset
(
buff
,
0
,
bufflen
);
break
;
case
RESERVE_10
:
errsts
=
check_reset
(
SCpnt
,
devip
);
memset
(
buff
,
0
,
bufflen
);
break
;
case
RELEASE
:
errsts
=
check_reset
(
SCpnt
,
devip
);
memset
(
buff
,
0
,
bufflen
);
break
;
case
RELEASE_10
:
errsts
=
check_reset
(
SCpnt
,
devip
);
memset
(
buff
,
0
,
bufflen
);
break
;
case
READ_CAPACITY
:
errsts
=
check_reset
(
SCpnt
,
devip
);
memset
(
buff
,
0
,
bufflen
);
if
(
bufflen
>
7
)
{
capac
=
(
unsigned
long
)
sdebug_capacity
-
1
;
buff
[
0
]
=
(
capac
>>
24
);
buff
[
1
]
=
(
capac
>>
16
)
&
0xff
;
buff
[
2
]
=
(
capac
>>
8
)
&
0xff
;
buff
[
3
]
=
capac
&
0xff
;
buff
[
6
]
=
(
SECT_SIZE_PER
(
target
)
>>
8
)
&
0xff
;
buff
[
7
]
=
SECT_SIZE_PER
(
target
)
&
0xff
;
}
errsts
=
resp_readcap
(
SCpnt
,
devip
);
break
;
case
READ_16
:
case
READ_12
:
...
...
@@ -432,12 +392,15 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
errsts
=
resp_read
(
SCpnt
,
upper_blk
,
block
,
num
,
devip
);
if
(
inj_recovered
&&
(
0
==
errsts
))
{
mk_sense_buffer
(
devip
,
RECOVERED_ERROR
,
THRESHHOLD_EXCEEDED
,
0
,
18
);
THRESHHOLD_EXCEEDED
,
0
);
errsts
=
check_condition_result
;
}
break
;
case
REPORT_LUNS
:
/* mandatory, ignore unit attention */
errsts
=
resp_report_luns
(
cmd
,
buff
,
bufflen
,
devip
);
errsts
=
resp_report_luns
(
SCpnt
,
devip
);
break
;
case
VERIFY
:
/* 10 byte SBC-2 command */
errsts
=
check_reset
(
SCpnt
,
devip
);
break
;
case
WRITE_16
:
case
WRITE_12
:
...
...
@@ -470,19 +433,16 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
errsts
=
resp_write
(
SCpnt
,
upper_blk
,
block
,
num
,
devip
);
if
(
inj_recovered
&&
(
0
==
errsts
))
{
mk_sense_buffer
(
devip
,
RECOVERED_ERROR
,
THRESHHOLD_EXCEEDED
,
0
,
18
);
THRESHHOLD_EXCEEDED
,
0
);
errsts
=
check_condition_result
;
}
break
;
case
MODE_SENSE
:
case
MODE_SENSE_10
:
if
((
errsts
=
check_reset
(
SCpnt
,
devip
)))
break
;
errsts
=
resp_mode_sense
(
cmd
,
target
,
buff
,
bufflen
,
devip
);
errsts
=
resp_mode_sense
(
SCpnt
,
target
,
devip
);
break
;
case
SYNCHRONIZE_CACHE
:
errsts
=
check_reset
(
SCpnt
,
devip
);
memset
(
buff
,
0
,
bufflen
);
break
;
default:
if
(
SCSI_DEBUG_OPT_NOISE
&
scsi_debug_opts
)
...
...
@@ -490,7 +450,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
"supported
\n
"
,
*
cmd
);
if
((
errsts
=
check_reset
(
SCpnt
,
devip
)))
break
;
/* Unit attention takes precedence */
mk_sense_buffer
(
devip
,
ILLEGAL_REQUEST
,
INVALID_OPCODE
,
0
,
18
);
mk_sense_buffer
(
devip
,
ILLEGAL_REQUEST
,
INVALID_OPCODE
,
0
);
errsts
=
check_condition_result
;
break
;
}
...
...
@@ -513,18 +473,105 @@ static int check_reset(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip)
printk
(
KERN_INFO
"scsi_debug: Reporting Unit "
"attention: power on reset
\n
"
);
devip
->
reset
=
0
;
mk_sense_buffer
(
devip
,
UNIT_ATTENTION
,
POWERON_RESET
,
0
,
18
);
mk_sense_buffer
(
devip
,
UNIT_ATTENTION
,
POWERON_RESET
,
0
);
return
check_condition_result
;
}
return
0
;
}
#define SDEBUG_LONG_INQ_SZ 96
#define SDEBUG_MAX_INQ_ARR_SZ 128
/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
static
int
fill_from_dev_buffer
(
struct
scsi_cmnd
*
scp
,
unsigned
char
*
arr
,
int
arr_len
)
{
int
k
,
req_len
,
act_len
,
len
,
active
;
void
*
kaddr
;
void
*
kaddr_off
;
struct
scatterlist
*
sgpnt
;
static
const
char
*
vendor_id
=
"Linux "
;
static
const
char
*
product_id
=
"scsi_debug "
;
static
const
char
*
product_rev
=
"0004"
;
if
(
0
==
scp
->
request_bufflen
)
return
0
;
if
(
NULL
==
scp
->
request_buffer
)
return
(
DID_ERROR
<<
16
);
if
(
!
((
scp
->
sc_data_direction
==
DMA_BIDIRECTIONAL
)
||
(
scp
->
sc_data_direction
==
DMA_FROM_DEVICE
)))
return
(
DID_ERROR
<<
16
);
if
(
0
==
scp
->
use_sg
)
{
req_len
=
scp
->
request_bufflen
;
act_len
=
(
req_len
<
arr_len
)
?
req_len
:
arr_len
;
memcpy
(
scp
->
request_buffer
,
arr
,
act_len
);
scp
->
resid
=
req_len
-
act_len
;
return
0
;
}
sgpnt
=
(
struct
scatterlist
*
)
scp
->
request_buffer
;
active
=
1
;
for
(
k
=
0
,
req_len
=
0
,
act_len
=
0
;
k
<
scp
->
use_sg
;
++
k
,
++
sgpnt
)
{
if
(
active
)
{
kaddr
=
(
unsigned
char
*
)
kmap_atomic
(
sgpnt
->
page
,
KM_USER0
);
if
(
NULL
==
kaddr
)
return
(
DID_ERROR
<<
16
);
kaddr_off
=
(
unsigned
char
*
)
kaddr
+
sgpnt
->
offset
;
len
=
sgpnt
->
length
;
if
((
req_len
+
len
)
>
arr_len
)
{
active
=
0
;
len
=
arr_len
-
req_len
;
}
memcpy
(
kaddr_off
,
arr
+
req_len
,
len
);
kunmap_atomic
(
kaddr
,
KM_USER0
);
act_len
+=
len
;
}
req_len
+=
sgpnt
->
length
;
}
scp
->
resid
=
req_len
-
act_len
;
return
0
;
}
/* Returns number of bytes fetched into 'arr' or -1 if error. */
static
int
fetch_to_dev_buffer
(
struct
scsi_cmnd
*
scp
,
unsigned
char
*
arr
,
int
max_arr_len
)
{
int
k
,
req_len
,
len
,
fin
;
void
*
kaddr
;
void
*
kaddr_off
;
struct
scatterlist
*
sgpnt
;
if
(
0
==
scp
->
request_bufflen
)
return
0
;
if
(
NULL
==
scp
->
request_buffer
)
return
-
1
;
if
(
!
((
scp
->
sc_data_direction
==
DMA_BIDIRECTIONAL
)
||
(
scp
->
sc_data_direction
==
DMA_TO_DEVICE
)))
return
-
1
;
if
(
0
==
scp
->
use_sg
)
{
req_len
=
scp
->
request_bufflen
;
len
=
(
req_len
<
max_arr_len
)
?
req_len
:
max_arr_len
;
memcpy
(
arr
,
scp
->
request_buffer
,
len
);
return
len
;
}
sgpnt
=
(
struct
scatterlist
*
)
scp
->
request_buffer
;
for
(
k
=
0
,
req_len
=
0
,
fin
=
0
;
k
<
scp
->
use_sg
;
++
k
,
++
sgpnt
)
{
kaddr
=
(
unsigned
char
*
)
kmap_atomic
(
sgpnt
->
page
,
KM_USER0
);
if
(
NULL
==
kaddr
)
return
-
1
;
kaddr_off
=
(
unsigned
char
*
)
kaddr
+
sgpnt
->
offset
;
len
=
sgpnt
->
length
;
if
((
req_len
+
len
)
>
max_arr_len
)
{
len
=
max_arr_len
-
req_len
;
fin
=
1
;
}
memcpy
(
arr
+
req_len
,
kaddr_off
,
len
);
kunmap_atomic
(
kaddr
,
KM_USER0
);
if
(
fin
)
return
req_len
+
len
;
req_len
+=
sgpnt
->
length
;
}
return
req_len
;
}
static
const
char
*
inq_vendor_id
=
"Linux "
;
static
const
char
*
inq_product_id
=
"scsi_debug "
;
static
const
char
*
inq_product_rev
=
"0004"
;
static
int
inquiry_evpd_83
(
unsigned
char
*
arr
,
int
dev_id_num
,
const
char
*
dev_id_str
,
int
dev_id_str_len
)
...
...
@@ -536,8 +583,8 @@ static int inquiry_evpd_83(unsigned char * arr, int dev_id_num,
arr
[
0
]
=
0x2
;
/* ASCII */
arr
[
1
]
=
0x1
;
arr
[
2
]
=
0x0
;
memcpy
(
&
arr
[
4
],
vendor_id
,
8
);
memcpy
(
&
arr
[
12
],
product_id
,
16
);
memcpy
(
&
arr
[
4
],
inq_
vendor_id
,
8
);
memcpy
(
&
arr
[
12
],
inq_
product_id
,
16
);
memcpy
(
&
arr
[
28
],
dev_id_str
,
dev_id_str_len
);
num
=
8
+
16
+
dev_id_str_len
;
arr
[
3
]
=
num
;
...
...
@@ -558,24 +605,25 @@ static int inquiry_evpd_83(unsigned char * arr, int dev_id_num,
return
num
+
12
;
}
static
int
resp_inquiry
(
unsigned
char
*
cmd
,
int
target
,
unsigned
char
*
buff
,
int
bufflen
,
struct
sdebug_dev_info
*
devip
)
#define SDEBUG_LONG_INQ_SZ 96
#define SDEBUG_MAX_INQ_ARR_SZ 128
static
int
resp_inquiry
(
struct
scsi_cmnd
*
scp
,
int
target
,
struct
sdebug_dev_info
*
devip
)
{
unsigned
char
pq_pdt
;
unsigned
char
arr
[
SDEBUG_MAX_INQ_ARR_SZ
];
int
min_len
=
bufflen
>
SDEBUG_MAX_INQ_ARR_SZ
?
SDEBUG_MAX_INQ_ARR_SZ
:
buff
len
;
unsigned
char
*
cmd
=
(
unsigned
char
*
)
scp
->
cmnd
;
int
alloc_
len
;
if
(
bufflen
<
cmd
[
4
])
printk
(
KERN_INFO
"scsi_debug: inquiry: bufflen=%d "
"< alloc_length=%d
\n
"
,
bufflen
,
(
int
)
cmd
[
4
]);
memset
(
buff
,
0
,
bufflen
);
alloc_len
=
(
cmd
[
3
]
<<
8
)
+
cmd
[
4
];
memset
(
arr
,
0
,
SDEBUG_MAX_INQ_ARR_SZ
);
pq_pdt
=
(
scsi_debug_ptype
&
0x1f
);
arr
[
0
]
=
pq_pdt
;
if
(
0x2
&
cmd
[
1
])
{
/* CMDDT bit set */
mk_sense_buffer
(
devip
,
ILLEGAL_REQUEST
,
INVALID_FIELD_IN_CDB
,
0
,
18
);
0
);
return
check_condition_result
;
}
else
if
(
0x1
&
cmd
[
1
])
{
/* EVPD bit set */
int
dev_id_num
,
len
;
...
...
@@ -600,11 +648,11 @@ static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff,
}
else
{
/* Illegal request, invalid field in cdb */
mk_sense_buffer
(
devip
,
ILLEGAL_REQUEST
,
INVALID_FIELD_IN_CDB
,
0
,
18
);
INVALID_FIELD_IN_CDB
,
0
);
return
check_condition_result
;
}
memcpy
(
buff
,
arr
,
min_len
);
return
0
;
return
fill_from_dev_buffer
(
scp
,
arr
,
min
(
alloc_len
,
SDEBUG_MAX_INQ_ARR_SZ
))
;
}
/* drops through here for a standard inquiry */
arr
[
1
]
=
DEV_REMOVEABLE
(
target
)
?
0x80
:
0
;
/* Removable disk */
...
...
@@ -612,20 +660,67 @@ static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff,
arr
[
3
]
=
2
;
/* response_data_format==2 */
arr
[
4
]
=
SDEBUG_LONG_INQ_SZ
-
5
;
arr
[
6
]
=
0x1
;
/* claim: ADDR16 */
/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
arr
[
7
]
=
0x3a
;
/* claim: WBUS16, SYNC, LINKED + CMDQUE */
memcpy
(
&
arr
[
8
],
vendor_id
,
8
);
memcpy
(
&
arr
[
16
],
product_id
,
16
);
memcpy
(
&
arr
[
32
],
product_rev
,
4
);
memcpy
(
&
arr
[
8
],
inq_
vendor_id
,
8
);
memcpy
(
&
arr
[
16
],
inq_
product_id
,
16
);
memcpy
(
&
arr
[
32
],
inq_
product_rev
,
4
);
/* version descriptors (2 bytes each) follow */
arr
[
58
]
=
0x0
;
arr
[
59
]
=
0x40
;
/* SAM-2 */
arr
[
60
]
=
0x
2
;
arr
[
61
]
=
0x60
;
/* SPC-2
*/
arr
[
60
]
=
0x
3
;
arr
[
61
]
=
0x0
;
/* SPC-3
*/
if
(
scsi_debug_ptype
==
0
)
{
arr
[
62
]
=
0x1
;
arr
[
63
]
=
0x80
;
/* SBC */
arr
[
62
]
=
0x1
;
arr
[
63
]
=
0x80
;
/* SBC */
}
else
if
(
scsi_debug_ptype
==
1
)
{
arr
[
62
]
=
0x2
;
arr
[
63
]
=
0x00
;
/* SSC */
arr
[
62
]
=
0x2
;
arr
[
63
]
=
0x00
;
/* SSC */
}
memcpy
(
buff
,
arr
,
min_len
);
return
0
;
return
fill_from_dev_buffer
(
scp
,
arr
,
min
(
alloc_len
,
SDEBUG_LONG_INQ_SZ
));
}
static
int
resp_requests
(
struct
scsi_cmnd
*
scp
,
struct
sdebug_dev_info
*
devip
)
{
unsigned
char
*
sbuff
;
unsigned
char
*
cmd
=
(
unsigned
char
*
)
scp
->
cmnd
;
unsigned
char
arr
[
SDEBUG_SENSE_LEN
];
int
len
=
18
;
memset
(
arr
,
0
,
SDEBUG_SENSE_LEN
);
if
(
devip
->
reset
==
1
)
mk_sense_buffer
(
devip
,
0
,
NO_ADDED_SENSE
,
0
);
sbuff
=
devip
->
sense_buff
;
if
((
cmd
[
1
]
&
1
)
&&
(
!
scsi_debug_dsense
))
{
/* DESC bit set and sense_buff in fixed format */
arr
[
0
]
=
0x72
;
arr
[
1
]
=
sbuff
[
2
];
/* sense key */
arr
[
2
]
=
sbuff
[
12
];
/* asc */
arr
[
3
]
=
sbuff
[
13
];
/* ascq */
len
=
8
;
}
else
memcpy
(
arr
,
sbuff
,
SDEBUG_SENSE_LEN
);
mk_sense_buffer
(
devip
,
0
,
NO_ADDED_SENSE
,
0
);
return
fill_from_dev_buffer
(
scp
,
arr
,
len
);
}
#define SDEBUG_READCAP_ARR_SZ 8
static
int
resp_readcap
(
struct
scsi_cmnd
*
scp
,
struct
sdebug_dev_info
*
devip
)
{
unsigned
char
arr
[
SDEBUG_READCAP_ARR_SZ
];
unsigned
long
capac
;
int
errsts
;
if
((
errsts
=
check_reset
(
scp
,
devip
)))
return
errsts
;
memset
(
arr
,
0
,
SDEBUG_READCAP_ARR_SZ
);
capac
=
(
unsigned
long
)
sdebug_capacity
-
1
;
arr
[
0
]
=
(
capac
>>
24
);
arr
[
1
]
=
(
capac
>>
16
)
&
0xff
;
arr
[
2
]
=
(
capac
>>
8
)
&
0xff
;
arr
[
3
]
=
capac
&
0xff
;
arr
[
6
]
=
(
SECT_SIZE_PER
(
target
)
>>
8
)
&
0xff
;
arr
[
7
]
=
SECT_SIZE_PER
(
target
)
&
0xff
;
return
fill_from_dev_buffer
(
scp
,
arr
,
SDEBUG_READCAP_ARR_SZ
);
}
/* <<Following mode page info copied from ST318451LW>> */
...
...
@@ -706,34 +801,29 @@ static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
#define SDEBUG_MAX_MSENSE_SZ 256
static
int
resp_mode_sense
(
unsigned
char
*
cmd
,
int
target
,
unsigned
char
*
buff
,
int
bufflen
,
static
int
resp_mode_sense
(
struct
scsi_cmnd
*
scp
,
int
target
,
struct
sdebug_dev_info
*
devip
)
{
unsigned
char
dbd
;
int
pcontrol
,
pcode
,
subpcode
;
unsigned
char
dev_spec
;
int
alloc_len
,
msense_6
,
offset
,
len
;
int
alloc_len
,
msense_6
,
offset
,
len
,
errsts
;
unsigned
char
*
ap
;
unsigned
char
arr
[
SDEBUG_MAX_MSENSE_SZ
];
int
min_len
=
bufflen
>
SDEBUG_MAX_MSENSE_SZ
?
SDEBUG_MAX_MSENSE_SZ
:
bufflen
;
unsigned
char
*
cmd
=
(
unsigned
char
*
)
scp
->
cmnd
;
SCSI_LOG_LLQUEUE
(
3
,
printk
(
"Mode sense ...(%p %d)
\n
"
,
buff
,
bufflen
));
if
((
errsts
=
check_reset
(
scp
,
devip
)))
return
errsts
;
dbd
=
cmd
[
1
]
&
0x8
;
pcontrol
=
(
cmd
[
2
]
&
0xc0
)
>>
6
;
pcode
=
cmd
[
2
]
&
0x3f
;
subpcode
=
cmd
[
3
];
msense_6
=
(
MODE_SENSE
==
cmd
[
0
]);
alloc_len
=
msense_6
?
cmd
[
4
]
:
((
cmd
[
7
]
<<
8
)
|
cmd
[
8
]);
if
(
bufflen
<
alloc_len
)
printk
(
KERN_INFO
"scsi_debug: mode_sense: bufflen=%d "
"< alloc_length=%d
\n
"
,
bufflen
,
alloc_len
);
memset
(
buff
,
0
,
bufflen
);
memset
(
arr
,
0
,
SDEBUG_MAX_MSENSE_SZ
);
if
(
0x3
==
pcontrol
)
{
/* Saving values not supported */
mk_sense_buffer
(
devip
,
ILLEGAL_REQUEST
,
SAVING_PARAMS_UNSUP
,
0
,
18
);
0
);
return
check_condition_result
;
}
dev_spec
=
DEV_READONLY
(
target
)
?
0x80
:
0x0
;
...
...
@@ -748,7 +838,7 @@ static int resp_mode_sense(unsigned char * cmd, int target,
if
(
0
!=
subpcode
)
{
/* TODO: Control Extension page */
mk_sense_buffer
(
devip
,
ILLEGAL_REQUEST
,
INVALID_FIELD_IN_CDB
,
0
,
18
);
0
);
return
check_condition_result
;
}
switch
(
pcode
)
{
...
...
@@ -787,146 +877,104 @@ static int resp_mode_sense(unsigned char * cmd, int target,
break
;
default:
mk_sense_buffer
(
devip
,
ILLEGAL_REQUEST
,
INVALID_FIELD_IN_CDB
,
0
,
18
);
0
);
return
check_condition_result
;
}
if
(
msense_6
)
arr
[
0
]
=
offset
-
1
;
else
{
offset
-=
2
;
arr
[
0
]
=
(
offset
>>
8
)
&
0xff
;
arr
[
1
]
=
offset
&
0xff
;
arr
[
0
]
=
((
offset
-
2
)
>>
8
)
&
0xff
;
arr
[
1
]
=
(
offset
-
2
)
&
0xff
;
}
memcpy
(
buff
,
arr
,
min_len
);
return
0
;
return
fill_from_dev_buffer
(
scp
,
arr
,
min
(
alloc_len
,
offset
));
}
static
int
resp_read
(
struct
scsi_cmnd
*
SCpnt
,
int
upper_blk
,
int
block
,
int
num
,
struct
sdebug_dev_info
*
devip
)
{
unsigned
char
*
buff
=
(
unsigned
char
*
)
SCpnt
->
request_buffer
;
int
nbytes
,
sgcount
;
struct
scatterlist
*
sgpnt
=
NULL
;
int
bufflen
=
SCpnt
->
request_bufflen
;
unsigned
long
iflags
;
int
ret
;
if
(
upper_blk
||
(
block
+
num
>
sdebug_capacity
))
{
mk_sense_buffer
(
devip
,
ILLEGAL_REQUEST
,
ADDR_OUT_OF_RANGE
,
0
,
18
);
0
);
return
check_condition_result
;
}
if
((
SCSI_DEBUG_OPT_MEDIUM_ERR
&
scsi_debug_opts
)
&&
(
block
<=
OPT_MEDIUM_ERR_ADDR
)
&&
((
block
+
num
)
>
OPT_MEDIUM_ERR_ADDR
))
{
mk_sense_buffer
(
devip
,
MEDIUM_ERROR
,
UNRECOVERED_READ_ERR
,
0
,
18
);
0
);
/* claim unrecoverable read error */
return
check_condition_result
;
}
read_lock_irqsave
(
&
atomic_rw
,
iflags
);
sgcount
=
0
;
nbytes
=
bufflen
;
/* printk(KERN_INFO "scsi_debug_read: block=%d, tot_bufflen=%d\n",
block, bufflen); */
if
(
SCpnt
->
use_sg
)
{
sgcount
=
0
;
sgpnt
=
(
struct
scatterlist
*
)
buff
;
buff
=
scatg2virt
(
&
sgpnt
[
sgcount
]);
bufflen
=
sgpnt
[
sgcount
].
length
;
}
do
{
memcpy
(
buff
,
fake_storep
+
(
block
*
SECT_SIZE
),
bufflen
);
nbytes
-=
bufflen
;
if
(
SCpnt
->
use_sg
)
{
block
+=
bufflen
>>
POW2_SECT_SIZE
;
sgcount
++
;
if
(
nbytes
)
{
buff
=
scatg2virt
(
&
sgpnt
[
sgcount
]);
bufflen
=
sgpnt
[
sgcount
].
length
;
}
}
else
if
(
nbytes
>
0
)
printk
(
KERN_WARNING
"scsi_debug:resp_read: unexpected "
"nbytes=%d
\n
"
,
nbytes
);
}
while
(
nbytes
);
ret
=
fill_from_dev_buffer
(
SCpnt
,
fake_storep
+
(
block
*
SECT_SIZE
),
num
*
SECT_SIZE
);
read_unlock_irqrestore
(
&
atomic_rw
,
iflags
);
return
0
;
return
ret
;
}
static
int
resp_write
(
struct
scsi_cmnd
*
SCpnt
,
int
upper_blk
,
int
block
,
int
num
,
struct
sdebug_dev_info
*
devip
)
{
unsigned
char
*
buff
=
(
unsigned
char
*
)
SCpnt
->
request_buffer
;
int
nbytes
,
sgcount
;
struct
scatterlist
*
sgpnt
=
NULL
;
int
bufflen
=
SCpnt
->
request_bufflen
;
unsigned
long
iflags
;
int
res
;
if
(
upper_blk
||
(
block
+
num
>
sdebug_capacity
))
{
mk_sense_buffer
(
devip
,
ILLEGAL_REQUEST
,
ADDR_OUT_OF_RANGE
,
0
,
18
);
0
);
return
check_condition_result
;
}
write_lock_irqsave
(
&
atomic_rw
,
iflags
);
sgcount
=
0
;
nbytes
=
bufflen
;
if
(
SCpnt
->
use_sg
)
{
sgcount
=
0
;
sgpnt
=
(
struct
scatterlist
*
)
buff
;
buff
=
scatg2virt
(
&
sgpnt
[
sgcount
]);
bufflen
=
sgpnt
[
sgcount
].
length
;
}
do
{
memcpy
(
fake_storep
+
(
block
*
SECT_SIZE
),
buff
,
bufflen
);
nbytes
-=
bufflen
;
if
(
SCpnt
->
use_sg
)
{
block
+=
bufflen
>>
POW2_SECT_SIZE
;
sgcount
++
;
if
(
nbytes
)
{
buff
=
scatg2virt
(
&
sgpnt
[
sgcount
]);
bufflen
=
sgpnt
[
sgcount
].
length
;
}
}
else
if
(
nbytes
>
0
)
printk
(
KERN_WARNING
"scsi_debug:resp_write: "
"unexpected nbytes=%d
\n
"
,
nbytes
);
}
while
(
nbytes
);
res
=
fetch_to_dev_buffer
(
SCpnt
,
fake_storep
+
(
block
*
SECT_SIZE
),
num
*
SECT_SIZE
);
write_unlock_irqrestore
(
&
atomic_rw
,
iflags
);
if
(
-
1
==
res
)
return
(
DID_ERROR
<<
16
);
else
if
((
res
<
(
num
*
SECT_SIZE
))
&&
(
SCSI_DEBUG_OPT_NOISE
&
scsi_debug_opts
))
printk
(
KERN_INFO
"scsi_debug: write: cdb indicated=%d, "
" IO sent=%d bytes
\n
"
,
num
*
SECT_SIZE
,
res
);
return
0
;
}
static
int
resp_report_luns
(
unsigned
char
*
cmd
,
unsigned
char
*
buff
,
int
bufflen
,
struct
sdebug_dev_info
*
devip
)
#define SDEBUG_RLUN_ARR_SZ 128
static
int
resp_report_luns
(
struct
scsi_cmnd
*
scp
,
struct
sdebug_dev_info
*
devip
)
{
unsigned
int
alloc_len
;
int
lun_cnt
,
i
,
upper
;
unsigned
char
*
cmd
=
(
unsigned
char
*
)
scp
->
cmnd
;
int
select_report
=
(
int
)
cmd
[
2
];
struct
scsi_lun
*
one_lun
;
unsigned
char
arr
[
SDEBUG_RLUN_ARR_SZ
];
alloc_len
=
cmd
[
9
]
+
(
cmd
[
8
]
<<
8
)
+
(
cmd
[
7
]
<<
16
)
+
(
cmd
[
6
]
<<
24
);
if
((
alloc_len
<
16
)
||
(
select_report
>
2
))
{
mk_sense_buffer
(
devip
,
ILLEGAL_REQUEST
,
INVALID_FIELD_IN_CDB
,
0
,
18
);
0
);
return
check_condition_result
;
}
if
(
bufflen
>
8
)
{
/* can produce response with up to 16k luns
(lun 0 to lun 16383) */
memset
(
buff
,
0
,
bufflen
);
lun_cnt
=
scsi_debug_max_luns
;
buff
[
2
]
=
((
sizeof
(
struct
scsi_lun
)
*
lun_cnt
)
>>
8
)
&
0xff
;
buff
[
3
]
=
(
sizeof
(
struct
scsi_lun
)
*
lun_cnt
)
&
0xff
;
lun_cnt
=
min
((
int
)((
bufflen
-
8
)
/
sizeof
(
struct
scsi_lun
)),
lun_cnt
);
one_lun
=
(
struct
scsi_lun
*
)
&
buff
[
8
];
for
(
i
=
0
;
i
<
lun_cnt
;
i
++
)
{
upper
=
(
i
>>
8
)
&
0x3f
;
if
(
upper
)
one_lun
[
i
].
scsi_lun
[
0
]
=
(
upper
|
(
SAM2_LUN_ADDRESS_METHOD
<<
6
));
one_lun
[
i
].
scsi_lun
[
1
]
=
i
&
0xff
;
}
/* can produce response with up to 16k luns (lun 0 to lun 16383) */
memset
(
arr
,
0
,
SDEBUG_RLUN_ARR_SZ
);
lun_cnt
=
scsi_debug_max_luns
;
arr
[
2
]
=
((
sizeof
(
struct
scsi_lun
)
*
lun_cnt
)
>>
8
)
&
0xff
;
arr
[
3
]
=
(
sizeof
(
struct
scsi_lun
)
*
lun_cnt
)
&
0xff
;
lun_cnt
=
min
((
int
)((
SDEBUG_RLUN_ARR_SZ
-
8
)
/
sizeof
(
struct
scsi_lun
)),
lun_cnt
);
one_lun
=
(
struct
scsi_lun
*
)
&
arr
[
8
];
for
(
i
=
0
;
i
<
lun_cnt
;
i
++
)
{
upper
=
(
i
>>
8
)
&
0x3f
;
if
(
upper
)
one_lun
[
i
].
scsi_lun
[
0
]
=
(
upper
|
(
SAM2_LUN_ADDRESS_METHOD
<<
6
));
one_lun
[
i
].
scsi_lun
[
1
]
=
i
&
0xff
;
}
return
0
;
return
fill_from_dev_buffer
(
scp
,
arr
,
min
((
int
)
alloc_len
,
SDEBUG_RLUN_ARR_SZ
));
}
/* When timer goes off this function is called. */
...
...
@@ -1041,14 +1089,19 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
open_devip
->
reset
=
1
;
open_devip
->
used
=
1
;
memset
(
open_devip
->
sense_buff
,
0
,
SDEBUG_SENSE_LEN
);
open_devip
->
sense_buff
[
0
]
=
0x70
;
if
(
scsi_debug_dsense
)
open_devip
->
sense_buff
[
0
]
=
0x72
;
else
{
open_devip
->
sense_buff
[
0
]
=
0x70
;
open_devip
->
sense_buff
[
7
]
=
0xa
;
}
return
open_devip
;
}
return
NULL
;
}
static
void
mk_sense_buffer
(
struct
sdebug_dev_info
*
devip
,
int
key
,
int
asc
,
int
asq
,
int
inbandLen
)
int
asc
,
int
asq
)
{
unsigned
char
*
sbuff
;
...
...
@@ -1060,11 +1113,9 @@ static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
sbuff
[
2
]
=
asc
;
sbuff
[
3
]
=
asq
;
}
else
{
if
(
inbandLen
>
SDEBUG_SENSE_LEN
)
inbandLen
=
SDEBUG_SENSE_LEN
;
sbuff
[
0
]
=
0x70
;
/* fixed, current */
sbuff
[
2
]
=
key
;
sbuff
[
7
]
=
(
inbandLen
>
7
)
?
(
inbandLen
-
8
)
:
0
;
sbuff
[
7
]
=
0xa
;
/* implies 18 byte sense buffer */
sbuff
[
12
]
=
asc
;
sbuff
[
13
]
=
asq
;
}
...
...
@@ -1355,7 +1406,7 @@ MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
MODULE_PARM_DESC
(
num_tgts
,
"number of SCSI targets per host to simulate"
);
MODULE_PARM_DESC
(
opts
,
"1->noise, 2->medium_error, 4->..."
);
MODULE_PARM_DESC
(
ptype
,
"SCSI peripheral type(def=0[disk])"
);
MODULE_PARM_DESC
(
scsi_level
,
"SCSI level to simulate(def=
4[SPC-2
])"
);
MODULE_PARM_DESC
(
scsi_level
,
"SCSI level to simulate(def=
5[SPC-3
])"
);
static
char
sdebug_info
[
256
];
...
...
@@ -1391,7 +1442,7 @@ static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **sta
if
(
1
!=
sscanf
(
arr
,
"%d"
,
&
pos
))
return
-
EINVAL
;
scsi_debug_opts
=
pos
;
if
(
scsi_debug_every_nth
>
0
)
if
(
scsi_debug_every_nth
!=
0
)
scsi_debug_cmnd_count
=
0
;
return
length
;
}
...
...
@@ -1547,7 +1598,7 @@ static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
{
int
nth
;
if
((
count
>
0
)
&&
(
1
==
sscanf
(
buf
,
"%d"
,
&
nth
))
&&
(
nth
>=
0
)
)
{
if
((
count
>
0
)
&&
(
1
==
sscanf
(
buf
,
"%d"
,
&
nth
)))
{
scsi_debug_every_nth
=
nth
;
scsi_debug_cmnd_count
=
0
;
return
count
;
...
...
drivers/scsi/scsi_error.c
View file @
ac4646f7
...
...
@@ -268,16 +268,42 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
*
* Return value:
* SUCCESS or FAILED or NEEDS_RETRY
*
* Notes:
* When a deferred error is detected the current command has
* not been executed and needs retrying.
**/
static
int
scsi_check_sense
(
struct
scsi_cmnd
*
scmd
)
{
if
(
!
SCSI_SENSE_VALID
(
scmd
))
return
FAILED
;
struct
scsi_sense_hdr
sshdr
;
if
(
scmd
->
sense_buffer
[
2
]
&
0xe0
)
return
SUCCESS
;
if
(
!
scsi_command_normalize_sense
(
scmd
,
&
sshdr
)
)
return
FAILED
;
/* no valid sense data */
switch
(
scmd
->
sense_buffer
[
2
]
&
0xf
)
{
if
(
scsi_sense_is_deferred
(
&
sshdr
))
return
NEEDS_RETRY
;
/*
* Previous logic looked for FILEMARK, EOM or ILI which are
* mainly associated with tapes and returned SUCCESS.
*/
if
(
sshdr
.
response_code
==
0x70
)
{
/* fixed format */
if
(
scmd
->
sense_buffer
[
2
]
&
0xe0
)
return
SUCCESS
;
}
else
{
/*
* descriptor format: look for "stream commands sense data
* descriptor" (see SSC-3). Assume single sense data
* descriptor. Ignore ILI from SBC-2 READ LONG and WRITE LONG.
*/
if
((
sshdr
.
additional_length
>
3
)
&&
(
scmd
->
sense_buffer
[
8
]
==
0x4
)
&&
(
scmd
->
sense_buffer
[
11
]
&
0xe0
))
return
SUCCESS
;
}
switch
(
sshdr
.
sense_key
)
{
case
NO_SENSE
:
return
SUCCESS
;
case
RECOVERED_ERROR
:
...
...
@@ -301,19 +327,15 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
* if the device is in the process of becoming ready, we
* should retry.
*/
if
((
scmd
->
sense_buffer
[
12
]
==
0x04
)
&&
(
scmd
->
sense_buffer
[
13
]
==
0x01
))
{
if
((
sshdr
.
asc
==
0x04
)
&&
(
sshdr
.
ascq
==
0x01
))
return
NEEDS_RETRY
;
}
/*
* if the device is not started, we need to wake
* the error handler to start the motor
*/
if
(
scmd
->
device
->
allow_restart
&&
(
scmd
->
sense_buffer
[
12
]
==
0x04
)
&&
(
scmd
->
sense_buffer
[
13
]
==
0x02
))
{
(
sshdr
.
asc
==
0x04
)
&&
(
sshdr
.
ascq
==
0x02
))
return
FAILED
;
}
return
SUCCESS
;
/* these three are not supported */
...
...
@@ -1358,7 +1380,8 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
return
SUCCESS
;
case
RESERVATION_CONFLICT
:
printk
(
"scsi%d (%d,%d,%d) : reservation conflict
\n
"
,
printk
(
KERN_INFO
"scsi: reservation conflict: host"
" %d channel %d id %d lun %d
\n
"
,
scmd
->
device
->
host
->
host_no
,
scmd
->
device
->
channel
,
scmd
->
device
->
id
,
scmd
->
device
->
lun
);
return
SUCCESS
;
/* causes immediate i/o error */
...
...
drivers/scsi/scsi_ioctl.c
View file @
ac4646f7
...
...
@@ -21,6 +21,7 @@
#include <scsi/scsi_ioctl.h>
#include <scsi/scsi_request.h>
#include <scsi/sg.h>
#include <scsi/scsi_dbg.h>
#include "scsi_logging.h"
...
...
@@ -94,12 +95,13 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd,
{
struct
scsi_request
*
sreq
;
int
result
;
struct
scsi_sense_hdr
sshdr
;
SCSI_LOG_IOCTL
(
1
,
printk
(
"Trying ioctl with scsi command %d
\n
"
,
*
cmd
));
sreq
=
scsi_allocate_request
(
sdev
,
GFP_KERNEL
);
if
(
!
sreq
)
{
printk
(
"SCSI internal ioctl failed, no memory
\n
"
);
printk
(
KERN_WARNING
"SCSI internal ioctl failed, no memory
\n
"
);
return
-
ENOMEM
;
}
...
...
@@ -108,17 +110,21 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd,
SCSI_LOG_IOCTL
(
2
,
printk
(
"Ioctl returned 0x%x
\n
"
,
sreq
->
sr_result
));
if
(
driver_byte
(
sreq
->
sr_result
))
{
switch
(
sreq
->
sr_sense_buffer
[
2
]
&
0xf
)
{
if
((
driver_byte
(
sreq
->
sr_result
)
&
DRIVER_SENSE
)
&&
(
scsi_request_normalize_sense
(
sreq
,
&
sshdr
)))
{
switch
(
sshdr
.
sense_key
)
{
case
ILLEGAL_REQUEST
:
if
(
cmd
[
0
]
==
ALLOW_MEDIUM_REMOVAL
)
sdev
->
lockable
=
0
;
else
printk
(
"SCSI device (ioctl) reports ILLEGAL REQUEST.
\n
"
);
printk
(
KERN_INFO
"ioctl_internal_command: "
"ILLEGAL REQUEST asc=0x%x ascq=0x%x
\n
"
,
sshdr
.
asc
,
sshdr
.
ascq
);
break
;
case
NOT_READY
:
/* This happens if there is no disc in drive */
if
(
sdev
->
removable
&&
(
cmd
[
0
]
!=
TEST_UNIT_READY
))
{
printk
(
KERN_INFO
"Device not ready. Make sure there is a disc in the drive.
\n
"
);
printk
(
KERN_INFO
"Device not ready. Make sure"
" there is a disc in the drive.
\n
"
);
break
;
}
case
UNIT_ATTENTION
:
...
...
@@ -128,16 +134,15 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd,
break
;
}
default:
/* Fall through for non-removable media */
printk
(
"SCSI error: host %d id %d lun %d return code = %x
\n
"
,
printk
(
KERN_INFO
"ioctl_internal_command: <%d %d %d "
"%d> return code = %x
\n
"
,
sdev
->
host
->
host_no
,
sdev
->
channel
,
sdev
->
id
,
sdev
->
lun
,
sreq
->
sr_result
);
printk
(
"
\t
Sense class %x, sense error %x, extended sense %x
\n
"
,
sense_class
(
sreq
->
sr_sense_buffer
[
0
]),
sense_error
(
sreq
->
sr_sense_buffer
[
0
]),
sreq
->
sr_sense_buffer
[
2
]
&
0xf
);
scsi_print_req_sense
(
" "
,
sreq
);
break
;
}
}
...
...
@@ -401,7 +406,8 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
case
SCSI_IOCTL_SYNC
:
case
SCSI_IOCTL_START_UNIT
:
case
SCSI_IOCTL_STOP_UNIT
:
printk
(
KERN_WARNING
"program %s is using a deprecated SCSI ioctl, please convert it to SG_IO
\n
"
,
current
->
comm
);
printk
(
KERN_WARNING
"program %s is using a deprecated SCSI "
"ioctl, please convert it to SG_IO
\n
"
,
current
->
comm
);
break
;
default:
break
;
...
...
drivers/scsi/scsi_lib.c
View file @
ac4646f7
...
...
@@ -718,7 +718,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
clear_errors
=
0
;
if
(
scsi_command_normalize_sense
(
cmd
,
&
sshdr
))
{
/*
* SG_IO wants
to know about
deferred errors
* SG_IO wants
current and
deferred errors
*/
int
len
=
8
+
cmd
->
sense_buffer
[
7
];
...
...
@@ -844,9 +844,10 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
cmd
=
scsi_end_request
(
cmd
,
0
,
this_count
,
1
);
return
;
case
VOLUME_OVERFLOW
:
printk
(
"scsi%d: ERROR on channel %d, id %d, lun %d, CDB: "
,
cmd
->
device
->
host
->
host_no
,
(
int
)
cmd
->
device
->
channel
,
(
int
)
cmd
->
device
->
id
,
(
int
)
cmd
->
device
->
lun
);
printk
(
KERN_INFO
"Volume overflow <%d %d %d %d> CDB: "
,
cmd
->
device
->
host
->
host_no
,
(
int
)
cmd
->
device
->
channel
,
(
int
)
cmd
->
device
->
id
,
(
int
)
cmd
->
device
->
lun
);
__scsi_print_command
(
cmd
->
data_cmnd
);
scsi_print_sense
(
""
,
cmd
);
cmd
=
scsi_end_request
(
cmd
,
0
,
block_bytes
,
1
);
...
...
@@ -865,8 +866,8 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
return
;
}
if
(
result
)
{
printk
(
"SCSI error : <%d %d %d %d> return code = 0x%x
\n
"
,
cmd
->
device
->
host
->
host_no
,
printk
(
KERN_INFO
"SCSI error : <%d %d %d %d> return code "
"= 0x%x
\n
"
,
cmd
->
device
->
host
->
host_no
,
cmd
->
device
->
channel
,
cmd
->
device
->
id
,
cmd
->
device
->
lun
,
result
);
...
...
@@ -1604,12 +1605,15 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries)
sreq
->
sr_data_direction
=
DMA_NONE
;
scsi_wait_req
(
sreq
,
cmd
,
NULL
,
0
,
timeout
,
retries
);
if
((
driver_byte
(
sreq
->
sr_result
)
&
DRIVER_SENSE
)
&&
((
sreq
->
sr_sense_buffer
[
2
]
&
0x0f
)
==
UNIT_ATTENTION
||
(
sreq
->
sr_sense_buffer
[
2
]
&
0x0f
)
==
NOT_READY
)
&&
sdev
->
removable
)
{
sdev
->
changed
=
1
;
sreq
->
sr_result
=
0
;
if
((
driver_byte
(
sreq
->
sr_result
)
&
DRIVER_SENSE
)
&&
sdev
->
removable
)
{
struct
scsi_sense_hdr
sshdr
;
if
((
scsi_request_normalize_sense
(
sreq
,
&
sshdr
))
&&
((
sshdr
.
sense_key
==
UNIT_ATTENTION
)
||
(
sshdr
.
sense_key
==
NOT_READY
)))
{
sdev
->
changed
=
1
;
sreq
->
sr_result
=
0
;
}
}
result
=
sreq
->
sr_result
;
scsi_release_request
(
sreq
);
...
...
@@ -1668,6 +1672,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
case
SDEV_CREATED
:
case
SDEV_RUNNING
:
case
SDEV_QUIESCE
:
case
SDEV_BLOCK
:
break
;
default:
goto
illegal
;
...
...
drivers/scsi/scsi_scan.c
View file @
ac4646f7
...
...
@@ -39,6 +39,7 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_request.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_eh.h>
#include "scsi_priv.h"
#include "scsi_logging.h"
...
...
@@ -253,6 +254,11 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
sdev
->
request_queue
->
queuedata
=
sdev
;
scsi_adjust_queue_depth
(
sdev
,
0
,
sdev
->
host
->
cmd_per_lun
);
if
(
shost
->
transportt
->
device_setup
)
{
if
(
shost
->
transportt
->
device_setup
(
sdev
))
goto
out_free_queue
;
}
if
(
shost
->
hostt
->
slave_alloc
)
{
ret
=
shost
->
hostt
->
slave_alloc
(
sdev
);
if
(
ret
)
{
...
...
@@ -262,15 +268,10 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
*/
if
(
ret
==
-
ENXIO
)
display_failure_msg
=
0
;
goto
out_
free_queue
;
goto
out_
device_destroy
;
}
}
if
(
shost
->
transportt
->
device_setup
)
{
if
(
shost
->
transportt
->
device_setup
(
sdev
))
goto
out_cleanup_slave
;
}
if
(
scsi_sysfs_device_initialize
(
sdev
)
!=
0
)
goto
out_cleanup_slave
;
...
...
@@ -290,6 +291,9 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
out_cleanup_slave:
if
(
shost
->
hostt
->
slave_destroy
)
shost
->
hostt
->
slave_destroy
(
sdev
);
out_device_destroy:
if
(
shost
->
transportt
->
device_destroy
)
shost
->
transportt
->
device_destroy
(
sdev
);
out_free_queue:
scsi_free_queue
(
sdev
->
request_queue
);
out_free_dev:
...
...
@@ -322,6 +326,7 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result,
int
first_inquiry_len
,
try_inquiry_len
,
next_inquiry_len
;
int
response_len
=
0
;
int
pass
,
count
;
struct
scsi_sense_hdr
sshdr
;
*
bflags
=
0
;
...
...
@@ -357,17 +362,20 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result,
sreq
->
sr_result
));
if
(
sreq
->
sr_result
)
{
/* not-ready to ready transition or power-on - good */
/* dpg: bogus? INQUIRY never returns UNIT_ATTENTION */
/* Supposedly, but many buggy devices do so anyway. */
/*
* not-ready to ready transition [asc/ascq=0x28/0x0]
* or power-on, reset [asc/ascq=0x29/0x0], continue.
* INQUIRY should not yield UNIT_ATTENTION
* but many buggy devices do so anyway.
*/
if
((
driver_byte
(
sreq
->
sr_result
)
&
DRIVER_SENSE
)
&&
(
sreq
->
sr_sense_buffer
[
2
]
&
0xf
)
==
UNIT_ATTENTION
&&
(
sreq
->
sr_sense_buffer
[
12
]
==
0x28
||
sreq
->
sr_sense_buffer
[
12
]
==
0x29
)
&&
sreq
->
sr_sense_buffer
[
13
]
==
0
)
continue
;
scsi_request_normalize_sense
(
sreq
,
&
sshdr
))
{
if
((
sshdr
.
sense_key
==
UNIT_ATTENTION
)
&&
((
sshdr
.
asc
==
0x28
)
||
(
sshdr
.
asc
==
0x29
))
&&
(
sshdr
.
ascq
==
0
))
continue
;
}
}
break
;
}
...
...
@@ -741,6 +749,8 @@ static int scsi_probe_and_add_lun(struct Scsi_Host *host,
}
else
{
if
(
sdev
->
host
->
hostt
->
slave_destroy
)
sdev
->
host
->
hostt
->
slave_destroy
(
sdev
);
if
(
sdev
->
host
->
transportt
->
device_destroy
)
sdev
->
host
->
transportt
->
device_destroy
(
sdev
);
put_device
(
&
sdev
->
sdev_gendev
);
}
out:
...
...
@@ -893,6 +903,7 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
struct
scsi_lun
*
lunp
,
*
lun_data
;
struct
scsi_request
*
sreq
;
u8
*
data
;
struct
scsi_sense_hdr
sshdr
;
/*
* Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set.
...
...
@@ -970,9 +981,12 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
" %s (try %d) result 0x%x
\n
"
,
sreq
->
sr_result
?
"failed"
:
"successful"
,
retries
,
sreq
->
sr_result
));
if
(
sreq
->
sr_result
==
0
||
sreq
->
sr_sense_buffer
[
2
]
!=
UNIT_ATTENTION
)
if
(
sreq
->
sr_result
==
0
)
break
;
else
if
(
scsi_request_normalize_sense
(
sreq
,
&
sshdr
))
{
if
(
sshdr
.
sense_key
!=
UNIT_ATTENTION
)
break
;
}
}
if
(
sreq
->
sr_result
)
{
...
...
@@ -1299,5 +1313,7 @@ void scsi_free_host_dev(struct scsi_device *sdev)
if
(
sdev
->
host
->
hostt
->
slave_destroy
)
sdev
->
host
->
hostt
->
slave_destroy
(
sdev
);
if
(
sdev
->
host
->
transportt
->
device_destroy
)
sdev
->
host
->
transportt
->
device_destroy
(
sdev
);
put_device
(
&
sdev
->
sdev_gendev
);
}
drivers/scsi/scsi_sysfs.c
View file @
ac4646f7
...
...
@@ -169,7 +169,10 @@ void scsi_device_dev_release(struct device *dev)
if
(
delete
)
{
struct
scsi_target
*
starget
=
to_scsi_target
(
parent
);
struct
Scsi_Host
*
shost
=
dev_to_shost
(
starget
->
dev
.
parent
);
if
(
!
starget
->
create
)
{
if
(
shost
->
transportt
->
target_destroy
)
shost
->
transportt
->
target_destroy
(
starget
);
device_del
(
parent
);
if
(
starget
->
transport_classdev
.
class
)
class_device_unregister
(
&
starget
->
transport_classdev
);
...
...
@@ -601,6 +604,8 @@ void scsi_remove_device(struct scsi_device *sdev)
scsi_device_set_state
(
sdev
,
SDEV_DEL
);
if
(
sdev
->
host
->
hostt
->
slave_destroy
)
sdev
->
host
->
hostt
->
slave_destroy
(
sdev
);
if
(
sdev
->
host
->
transportt
->
device_destroy
)
sdev
->
host
->
transportt
->
device_destroy
(
sdev
);
put_device
(
&
sdev
->
sdev_gendev
);
out:
...
...
drivers/scsi/scsi_transport_fc.c
View file @
ac4646f7
...
...
@@ -29,6 +29,8 @@
static
void
transport_class_release
(
struct
class_device
*
class_dev
);
static
void
host_class_release
(
struct
class_device
*
class_dev
);
static
void
fc_timeout_blocked_host
(
void
*
data
);
static
void
fc_timeout_blocked_tgt
(
void
*
data
);
#define FC_STARGET_NUM_ATTRS 4
/* increase this if you add attributes */
#define FC_STARGET_OTHER_ATTRS 0
/* increase this if you add "always on"
...
...
@@ -87,10 +89,18 @@ static int fc_setup_starget_transport_attrs(struct scsi_target *starget)
fc_starget_port_name
(
starget
)
=
-
1
;
fc_starget_port_id
(
starget
)
=
-
1
;
fc_starget_dev_loss_tmo
(
starget
)
=
-
1
;
init_timer
(
&
fc_starget_dev_loss_timer
(
starget
));
INIT_WORK
(
&
fc_starget_dev_loss_work
(
starget
),
fc_timeout_blocked_tgt
,
starget
);
return
0
;
}
static
void
fc_destroy_starget
(
struct
scsi_target
*
starget
)
{
/* Stop the target timer */
if
(
cancel_delayed_work
(
&
fc_starget_dev_loss_work
(
starget
)))
flush_scheduled_work
();
}
static
int
fc_setup_host_transport_attrs
(
struct
Scsi_Host
*
shost
)
{
/*
...
...
@@ -99,10 +109,18 @@ static int fc_setup_host_transport_attrs(struct Scsi_Host *shost)
* all transport attributes to valid values per host.
*/
fc_host_link_down_tmo
(
shost
)
=
-
1
;
init_timer
(
&
fc_host_link_down_timer
(
shost
));
INIT_WORK
(
&
fc_host_link_down_work
(
shost
),
fc_timeout_blocked_host
,
shost
);
return
0
;
}
static
void
fc_destroy_host
(
struct
Scsi_Host
*
shost
)
{
/* Stop the host timer */
if
(
cancel_delayed_work
(
&
fc_host_link_down_work
(
shost
)))
flush_scheduled_work
();
}
static
void
transport_class_release
(
struct
class_device
*
class_dev
)
{
struct
scsi_target
*
starget
=
transport_class_to_starget
(
class_dev
);
...
...
@@ -277,11 +295,13 @@ fc_attach_transport(struct fc_function_template *ft)
i
->
t
.
target_attrs
=
&
i
->
starget_attrs
[
0
];
i
->
t
.
target_class
=
&
fc_transport_class
;
i
->
t
.
target_setup
=
&
fc_setup_starget_transport_attrs
;
i
->
t
.
target_destroy
=
&
fc_destroy_starget
;
i
->
t
.
target_size
=
sizeof
(
struct
fc_starget_attrs
);
i
->
t
.
host_attrs
=
&
i
->
host_attrs
[
0
];
i
->
t
.
host_class
=
&
fc_host_class
;
i
->
t
.
host_setup
=
&
fc_setup_host_transport_attrs
;
i
->
t
.
host_destroy
=
&
fc_destroy_host
;
i
->
t
.
host_size
=
sizeof
(
struct
fc_host_attrs
);
i
->
f
=
ft
;
...
...
@@ -353,7 +373,7 @@ static int fc_device_unblock(struct device *dev, void *data)
* that fail to recover in the alloted time.
* @data: scsi target that failed to reappear in the alloted time.
**/
static
void
fc_timeout_blocked_tgt
(
unsigned
long
data
)
static
void
fc_timeout_blocked_tgt
(
void
*
data
)
{
struct
scsi_target
*
starget
=
(
struct
scsi_target
*
)
data
;
...
...
@@ -388,7 +408,7 @@ int
fc_target_block
(
struct
scsi_target
*
starget
)
{
int
timeout
=
fc_starget_dev_loss_tmo
(
starget
);
struct
timer_list
*
timer
=
&
fc_starget_dev_loss_timer
(
starget
);
struct
work_struct
*
work
=
&
fc_starget_dev_loss_work
(
starget
);
if
(
timeout
<
0
||
timeout
>
SCSI_DEVICE_BLOCK_MAX_TIMEOUT
)
return
-
EINVAL
;
...
...
@@ -396,10 +416,7 @@ fc_target_block(struct scsi_target *starget)
device_for_each_child
(
&
starget
->
dev
,
NULL
,
fc_device_block
);
/* The scsi lld blocks this target for the timeout period only. */
timer
->
data
=
(
unsigned
long
)
starget
;
timer
->
expires
=
jiffies
+
timeout
*
HZ
;
timer
->
function
=
fc_timeout_blocked_tgt
;
add_timer
(
timer
);
schedule_delayed_work
(
work
,
timeout
*
HZ
);
return
0
;
}
...
...
@@ -424,7 +441,8 @@ fc_target_unblock(struct scsi_target *starget)
* failure as the state machine state change will validate the
* transaction.
*/
del_timer_sync
(
&
fc_starget_dev_loss_timer
(
starget
));
if
(
cancel_delayed_work
(
&
fc_starget_dev_loss_work
(
starget
)))
flush_scheduled_work
();
device_for_each_child
(
&
starget
->
dev
,
NULL
,
fc_device_unblock
);
}
...
...
@@ -436,7 +454,7 @@ EXPORT_SYMBOL(fc_target_unblock);
* @data: scsi host that failed to recover its devices in the alloted
* time.
**/
static
void
fc_timeout_blocked_host
(
unsigned
long
data
)
static
void
fc_timeout_blocked_host
(
void
*
data
)
{
struct
Scsi_Host
*
shost
=
(
struct
Scsi_Host
*
)
data
;
struct
scsi_device
*
sdev
;
...
...
@@ -475,7 +493,7 @@ fc_host_block(struct Scsi_Host *shost)
{
struct
scsi_device
*
sdev
;
int
timeout
=
fc_host_link_down_tmo
(
shost
);
struct
timer_list
*
timer
=
&
fc_host_link_down_timer
(
shost
);
struct
work_struct
*
work
=
&
fc_host_link_down_work
(
shost
);
if
(
timeout
<
0
||
timeout
>
SCSI_DEVICE_BLOCK_MAX_TIMEOUT
)
return
-
EINVAL
;
...
...
@@ -484,11 +502,7 @@ fc_host_block(struct Scsi_Host *shost)
scsi_internal_device_block
(
sdev
);
}
/* The scsi lld blocks this host for the timeout period only. */
timer
->
data
=
(
unsigned
long
)
shost
;
timer
->
expires
=
jiffies
+
timeout
*
HZ
;
timer
->
function
=
fc_timeout_blocked_host
;
add_timer
(
timer
);
schedule_delayed_work
(
work
,
timeout
*
HZ
);
return
0
;
}
...
...
@@ -516,7 +530,9 @@ fc_host_unblock(struct Scsi_Host *shost)
* failure as the state machine state change will validate the
* transaction.
*/
del_timer_sync
(
&
fc_host_link_down_timer
(
shost
));
if
(
cancel_delayed_work
(
&
fc_host_link_down_work
(
shost
)))
flush_scheduled_work
();
shost_for_each_device
(
sdev
,
shost
)
{
scsi_internal_device_unblock
(
sdev
);
}
...
...
drivers/scsi/scsi_transport_iscsi.c
0 → 100644
View file @
ac4646f7
/*
* iSCSI transport class definitions
*
* Copyright (C) IBM Corporation, 2004
* Copyright (C) Mike Christie, 2004
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/module.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_iscsi.h>
#define ISCSI_SESSION_ATTRS 20
#define ISCSI_HOST_ATTRS 2
struct
iscsi_internal
{
struct
scsi_transport_template
t
;
struct
iscsi_function_template
*
fnt
;
/*
* We do not have any private or other attrs.
*/
struct
class_device_attribute
*
session_attrs
[
ISCSI_SESSION_ATTRS
+
1
];
struct
class_device_attribute
*
host_attrs
[
ISCSI_HOST_ATTRS
+
1
];
};
#define to_iscsi_internal(tmpl) container_of(tmpl, struct iscsi_internal, t)
static
void
iscsi_transport_class_release
(
struct
class_device
*
class_dev
)
{
struct
scsi_target
*
starget
=
transport_class_to_starget
(
class_dev
);
put_device
(
&
starget
->
dev
);
}
struct
class
iscsi_transport_class
=
{
.
name
=
"iscsi_transport_class"
,
.
release
=
iscsi_transport_class_release
,
};
static
void
iscsi_host_class_release
(
struct
class_device
*
class_dev
)
{
struct
Scsi_Host
*
shost
=
transport_class_to_shost
(
class_dev
);
put_device
(
&
shost
->
shost_gendev
);
}
struct
class
iscsi_host_class
=
{
.
name
=
"iscsi_host"
,
.
release
=
iscsi_host_class_release
,
};
/*
* iSCSI target and session attrs
*/
#define iscsi_session_show_fn(field, format) \
\
static ssize_t \
show_session_##field(struct class_device *cdev, char *buf) \
{ \
struct scsi_target *starget = transport_class_to_starget(cdev); \
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
\
if (i->fnt->get_##field) \
i->fnt->get_##field(starget); \
return snprintf(buf, 20, format"\n", iscsi_##field(starget)); \
}
#define iscsi_session_rd_attr(field, format) \
iscsi_session_show_fn(field, format) \
static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_##field, NULL);
iscsi_session_rd_attr
(
tpgt
,
"%hu"
);
iscsi_session_rd_attr
(
tsih
,
"%2x"
);
iscsi_session_rd_attr
(
max_recv_data_segment_len
,
"%u"
);
iscsi_session_rd_attr
(
max_burst_len
,
"%u"
);
iscsi_session_rd_attr
(
first_burst_len
,
"%u"
);
iscsi_session_rd_attr
(
def_time2wait
,
"%hu"
);
iscsi_session_rd_attr
(
def_time2retain
,
"%hu"
);
iscsi_session_rd_attr
(
max_outstanding_r2t
,
"%hu"
);
iscsi_session_rd_attr
(
erl
,
"%d"
);
#define iscsi_session_show_bool_fn(field) \
\
static ssize_t \
show_session_bool_##field(struct class_device *cdev, char *buf) \
{ \
struct scsi_target *starget = transport_class_to_starget(cdev); \
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
\
if (i->fnt->get_##field) \
i->fnt->get_##field(starget); \
\
if (iscsi_##field(starget)) \
return sprintf(buf, "Yes\n"); \
return sprintf(buf, "No\n"); \
}
#define iscsi_session_rd_bool_attr(field) \
iscsi_session_show_bool_fn(field) \
static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_bool_##field, NULL);
iscsi_session_rd_bool_attr
(
initial_r2t
);
iscsi_session_rd_bool_attr
(
immediate_data
);
iscsi_session_rd_bool_attr
(
data_pdu_in_order
);
iscsi_session_rd_bool_attr
(
data_sequence_in_order
);
#define iscsi_session_show_digest_fn(field) \
\
static ssize_t \
show_##field(struct class_device *cdev, char *buf) \
{ \
struct scsi_target *starget = transport_class_to_starget(cdev); \
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
\
if (i->fnt->get_##field) \
i->fnt->get_##field(starget); \
\
if (iscsi_##field(starget)) \
return sprintf(buf, "CRC32C\n"); \
return sprintf(buf, "None\n"); \
}
#define iscsi_session_rd_digest_attr(field) \
iscsi_session_show_digest_fn(field) \
static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
iscsi_session_rd_digest_attr
(
header_digest
);
iscsi_session_rd_digest_attr
(
data_digest
);
static
ssize_t
show_port
(
struct
class_device
*
cdev
,
char
*
buf
)
{
struct
scsi_target
*
starget
=
transport_class_to_starget
(
cdev
);
struct
Scsi_Host
*
shost
=
dev_to_shost
(
starget
->
dev
.
parent
);
struct
iscsi_internal
*
i
=
to_iscsi_internal
(
shost
->
transportt
);
if
(
i
->
fnt
->
get_port
)
i
->
fnt
->
get_port
(
starget
);
return
snprintf
(
buf
,
20
,
"%hu
\n
"
,
ntohs
(
iscsi_port
(
starget
)));
}
static
CLASS_DEVICE_ATTR
(
port
,
S_IRUGO
,
show_port
,
NULL
);
static
ssize_t
show_ip_address
(
struct
class_device
*
cdev
,
char
*
buf
)
{
struct
scsi_target
*
starget
=
transport_class_to_starget
(
cdev
);
struct
Scsi_Host
*
shost
=
dev_to_shost
(
starget
->
dev
.
parent
);
struct
iscsi_internal
*
i
=
to_iscsi_internal
(
shost
->
transportt
);
if
(
i
->
fnt
->
get_ip_address
)
i
->
fnt
->
get_ip_address
(
starget
);
if
(
iscsi_addr_type
(
starget
)
==
AF_INET
)
return
sprintf
(
buf
,
"%u.%u.%u.%u
\n
"
,
NIPQUAD
(
iscsi_sin_addr
(
starget
)));
else
if
(
iscsi_addr_type
(
starget
)
==
AF_INET6
)
return
sprintf
(
buf
,
"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x
\n
"
,
NIP6
(
iscsi_sin6_addr
(
starget
)));
return
-
EINVAL
;
}
static
CLASS_DEVICE_ATTR
(
ip_address
,
S_IRUGO
,
show_ip_address
,
NULL
);
static
ssize_t
show_isid
(
struct
class_device
*
cdev
,
char
*
buf
)
{
struct
scsi_target
*
starget
=
transport_class_to_starget
(
cdev
);
struct
Scsi_Host
*
shost
=
dev_to_shost
(
starget
->
dev
.
parent
);
struct
iscsi_internal
*
i
=
to_iscsi_internal
(
shost
->
transportt
);
if
(
i
->
fnt
->
get_isid
)
i
->
fnt
->
get_isid
(
starget
);
return
sprintf
(
buf
,
"%02x%02x%02x%02x%02x%02x
\n
"
,
iscsi_isid
(
starget
)[
0
],
iscsi_isid
(
starget
)[
1
],
iscsi_isid
(
starget
)[
2
],
iscsi_isid
(
starget
)[
3
],
iscsi_isid
(
starget
)[
4
],
iscsi_isid
(
starget
)[
5
]);
}
static
CLASS_DEVICE_ATTR
(
isid
,
S_IRUGO
,
show_isid
,
NULL
);
/*
* This is used for iSCSI names. Normally, we follow
* the transport class convention of having the lld
* set the field, but in these cases the value is
* too large.
*/
#define iscsi_session_show_str_fn(field) \
\
static ssize_t \
show_session_str_##field(struct class_device *cdev, char *buf) \
{ \
ssize_t ret = 0; \
struct scsi_target *starget = transport_class_to_starget(cdev); \
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
\
if (i->fnt->get_##field) \
ret = i->fnt->get_##field(starget, buf, PAGE_SIZE); \
return ret; \
}
#define iscsi_session_rd_str_attr(field) \
iscsi_session_show_str_fn(field) \
static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_str_##field, NULL);
iscsi_session_rd_str_attr
(
target_name
);
iscsi_session_rd_str_attr
(
target_alias
);
/*
* iSCSI host attrs
*/
/*
* Again, this is used for iSCSI names. Normally, we follow
* the transport class convention of having the lld set
* the field, but in these cases the value is too large.
*/
#define iscsi_host_show_str_fn(field) \
\
static ssize_t \
show_host_str_##field(struct class_device *cdev, char *buf) \
{ \
int ret = 0; \
struct Scsi_Host *shost = transport_class_to_shost(cdev); \
struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
\
if (i->fnt->get_##field) \
ret = i->fnt->get_##field(shost, buf, PAGE_SIZE); \
return ret; \
}
#define iscsi_host_rd_str_attr(field) \
iscsi_host_show_str_fn(field) \
static CLASS_DEVICE_ATTR(field, S_IRUGO, show_host_str_##field, NULL);
iscsi_host_rd_str_attr
(
initiator_name
);
iscsi_host_rd_str_attr
(
initiator_alias
);
#define SETUP_SESSION_RD_ATTR(field) \
if (i->fnt->show_##field) { \
i->session_attrs[count] = &class_device_attr_##field; \
count++; \
}
#define SETUP_HOST_RD_ATTR(field) \
if (i->fnt->show_##field) { \
i->host_attrs[count] = &class_device_attr_##field; \
count++; \
}
struct
scsi_transport_template
*
iscsi_attach_transport
(
struct
iscsi_function_template
*
fnt
)
{
struct
iscsi_internal
*
i
=
kmalloc
(
sizeof
(
struct
iscsi_internal
),
GFP_KERNEL
);
int
count
=
0
;
if
(
unlikely
(
!
i
))
return
NULL
;
memset
(
i
,
0
,
sizeof
(
struct
iscsi_internal
));
i
->
fnt
=
fnt
;
i
->
t
.
target_attrs
=
&
i
->
session_attrs
[
0
];
i
->
t
.
target_class
=
&
iscsi_transport_class
;
i
->
t
.
target_setup
=
NULL
;
i
->
t
.
target_size
=
sizeof
(
struct
iscsi_class_session
);
SETUP_SESSION_RD_ATTR
(
tsih
);
SETUP_SESSION_RD_ATTR
(
isid
);
SETUP_SESSION_RD_ATTR
(
header_digest
);
SETUP_SESSION_RD_ATTR
(
data_digest
);
SETUP_SESSION_RD_ATTR
(
target_name
);
SETUP_SESSION_RD_ATTR
(
target_alias
);
SETUP_SESSION_RD_ATTR
(
port
);
SETUP_SESSION_RD_ATTR
(
tpgt
);
SETUP_SESSION_RD_ATTR
(
ip_address
);
SETUP_SESSION_RD_ATTR
(
initial_r2t
);
SETUP_SESSION_RD_ATTR
(
immediate_data
);
SETUP_SESSION_RD_ATTR
(
max_recv_data_segment_len
);
SETUP_SESSION_RD_ATTR
(
max_burst_len
);
SETUP_SESSION_RD_ATTR
(
first_burst_len
);
SETUP_SESSION_RD_ATTR
(
def_time2wait
);
SETUP_SESSION_RD_ATTR
(
def_time2retain
);
SETUP_SESSION_RD_ATTR
(
max_outstanding_r2t
);
SETUP_SESSION_RD_ATTR
(
data_pdu_in_order
);
SETUP_SESSION_RD_ATTR
(
data_sequence_in_order
);
SETUP_SESSION_RD_ATTR
(
erl
);
BUG_ON
(
count
>
ISCSI_SESSION_ATTRS
);
i
->
session_attrs
[
count
]
=
NULL
;
i
->
t
.
host_attrs
=
&
i
->
host_attrs
[
0
];
i
->
t
.
host_class
=
&
iscsi_host_class
;
i
->
t
.
host_setup
=
NULL
;
i
->
t
.
host_size
=
0
;
count
=
0
;
SETUP_HOST_RD_ATTR
(
initiator_name
);
SETUP_HOST_RD_ATTR
(
initiator_alias
);
BUG_ON
(
count
>
ISCSI_HOST_ATTRS
);
i
->
host_attrs
[
count
]
=
NULL
;
return
&
i
->
t
;
}
EXPORT_SYMBOL
(
iscsi_attach_transport
);
void
iscsi_release_transport
(
struct
scsi_transport_template
*
t
)
{
struct
iscsi_internal
*
i
=
to_iscsi_internal
(
t
);
kfree
(
i
);
}
EXPORT_SYMBOL
(
iscsi_release_transport
);
static
__init
int
iscsi_transport_init
(
void
)
{
int
err
=
class_register
(
&
iscsi_transport_class
);
if
(
err
)
return
err
;
return
class_register
(
&
iscsi_host_class
);
}
static
void
__exit
iscsi_transport_exit
(
void
)
{
class_unregister
(
&
iscsi_host_class
);
class_unregister
(
&
iscsi_transport_class
);
}
module_init
(
iscsi_transport_init
);
module_exit
(
iscsi_transport_exit
);
MODULE_AUTHOR
(
"Mike Christie"
);
MODULE_DESCRIPTION
(
"iSCSI Transport Attributes"
);
MODULE_LICENSE
(
"GPL"
);
include/scsi/scsi_transport.h
View file @
ac4646f7
...
...
@@ -40,6 +40,11 @@ struct scsi_transport_template {
int
(
*
target_setup
)(
struct
scsi_target
*
);
int
(
*
host_setup
)(
struct
Scsi_Host
*
);
/* Destructor functions */
void
(
*
device_destroy
)(
struct
scsi_device
*
);
void
(
*
target_destroy
)(
struct
scsi_target
*
);
void
(
*
host_destroy
)(
struct
Scsi_Host
*
);
/* The size of the specific transport attribute structure (a
* space of this size will be left at the end of the
* scsi_* structure */
...
...
include/scsi/scsi_transport_fc.h
View file @
ac4646f7
...
...
@@ -29,7 +29,7 @@ struct fc_starget_attrs { /* aka fc_target_attrs */
uint64_t
node_name
;
uint64_t
port_name
;
uint32_t
dev_loss_tmo
;
/* Remote Port loss timeout in seconds. */
struct
timer_list
dev_loss_timer
;
struct
work_struct
dev_loss_work
;
};
#define fc_starget_port_id(x) \
...
...
@@ -40,18 +40,18 @@ struct fc_starget_attrs { /* aka fc_target_attrs */
(((struct fc_starget_attrs *)&(x)->starget_data)->port_name)
#define fc_starget_dev_loss_tmo(x) \
(((struct fc_starget_attrs *)&(x)->starget_data)->dev_loss_tmo)
#define fc_starget_dev_loss_
timer
(x) \
(((struct fc_starget_attrs *)&(x)->starget_data)->dev_loss_
timer
)
#define fc_starget_dev_loss_
work
(x) \
(((struct fc_starget_attrs *)&(x)->starget_data)->dev_loss_
work
)
struct
fc_host_attrs
{
uint32_t
link_down_tmo
;
/* Link Down timeout in seconds. */
struct
timer_list
link_down_timer
;
struct
work_struct
link_down_work
;
};
#define fc_host_link_down_tmo(x) \
(((struct fc_host_attrs *)(x)->shost_data)->link_down_tmo)
#define fc_host_link_down_
timer
(x) \
(((struct fc_host_attrs *)(x)->shost_data)->link_down_
timer
)
#define fc_host_link_down_
work
(x) \
(((struct fc_host_attrs *)(x)->shost_data)->link_down_
work
)
/* The functions by which the transport class and the driver communicate */
...
...
include/scsi/scsi_transport_iscsi.h
0 → 100644
View file @
ac4646f7
/*
* iSCSI transport class definitions
*
* Copyright (C) IBM Corporation, 2004
* Copyright (C) Mike Christie, 2004
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef SCSI_TRANSPORT_ISCSI_H
#define SCSI_TRANSPORT_ISCSI_H
#include <linux/config.h>
#include <linux/in6.h>
#include <linux/in.h>
struct
scsi_transport_template
;
struct
iscsi_class_session
{
uint8_t
isid
[
6
];
uint16_t
tsih
;
int
header_digest
;
/* 1 CRC32, 0 None */
int
data_digest
;
/* 1 CRC32, 0 None */
uint16_t
tpgt
;
union
{
struct
in6_addr
sin6_addr
;
struct
in_addr
sin_addr
;
}
u
;
sa_family_t
addr_type
;
/* must be AF_INET or AF_INET6 */
uint16_t
port
;
/* must be in network byte order */
int
initial_r2t
;
/* 1 Yes, 0 No */
int
immediate_data
;
/* 1 Yes, 0 No */
uint32_t
max_recv_data_segment_len
;
uint32_t
max_burst_len
;
uint32_t
first_burst_len
;
uint16_t
def_time2wait
;
uint16_t
def_time2retain
;
uint16_t
max_outstanding_r2t
;
int
data_pdu_in_order
;
/* 1 Yes, 0 No */
int
data_sequence_in_order
;
/* 1 Yes, 0 No */
int
erl
;
};
/*
* accessor macros
*/
#define iscsi_isid(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->isid)
#define iscsi_tsih(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->tsih)
#define iscsi_header_digest(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->header_digest)
#define iscsi_data_digest(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->data_digest)
#define iscsi_port(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->port)
#define iscsi_addr_type(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->addr_type)
#define iscsi_sin_addr(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->u.sin_addr)
#define iscsi_sin6_addr(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->u.sin6_addr)
#define iscsi_tpgt(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->tpgt)
#define iscsi_initial_r2t(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->initial_r2t)
#define iscsi_immediate_data(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->immediate_data)
#define iscsi_max_recv_data_segment_len(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->max_recv_data_segment_len)
#define iscsi_max_burst_len(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->max_burst_len)
#define iscsi_first_burst_len(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->first_burst_len)
#define iscsi_def_time2wait(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->def_time2wait)
#define iscsi_def_time2retain(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->def_time2retain)
#define iscsi_max_outstanding_r2t(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->max_outstanding_r2t)
#define iscsi_data_pdu_in_order(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->data_pdu_in_order)
#define iscsi_data_sequence_in_order(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->data_sequence_in_order)
#define iscsi_erl(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->erl)
/*
* The functions by which the transport class and the driver communicate
*/
struct
iscsi_function_template
{
/*
* target attrs
*/
void
(
*
get_isid
)(
struct
scsi_target
*
);
void
(
*
get_tsih
)(
struct
scsi_target
*
);
void
(
*
get_header_digest
)(
struct
scsi_target
*
);
void
(
*
get_data_digest
)(
struct
scsi_target
*
);
void
(
*
get_port
)(
struct
scsi_target
*
);
void
(
*
get_tpgt
)(
struct
scsi_target
*
);
/*
* In get_ip_address the lld must set the address and
* the address type
*/
void
(
*
get_ip_address
)(
struct
scsi_target
*
);
/*
* The lld should snprintf the name or alias to the buffer
*/
ssize_t
(
*
get_target_name
)(
struct
scsi_target
*
,
char
*
,
ssize_t
);
ssize_t
(
*
get_target_alias
)(
struct
scsi_target
*
,
char
*
,
ssize_t
);
void
(
*
get_initial_r2t
)(
struct
scsi_target
*
);
void
(
*
get_immediate_data
)(
struct
scsi_target
*
);
void
(
*
get_max_recv_data_segment_len
)(
struct
scsi_target
*
);
void
(
*
get_max_burst_len
)(
struct
scsi_target
*
);
void
(
*
get_first_burst_len
)(
struct
scsi_target
*
);
void
(
*
get_def_time2wait
)(
struct
scsi_target
*
);
void
(
*
get_def_time2retain
)(
struct
scsi_target
*
);
void
(
*
get_max_outstanding_r2t
)(
struct
scsi_target
*
);
void
(
*
get_data_pdu_in_order
)(
struct
scsi_target
*
);
void
(
*
get_data_sequence_in_order
)(
struct
scsi_target
*
);
void
(
*
get_erl
)(
struct
scsi_target
*
);
/*
* host atts
*/
/*
* The lld should snprintf the name or alias to the buffer
*/
ssize_t
(
*
get_initiator_alias
)(
struct
Scsi_Host
*
,
char
*
,
ssize_t
);
ssize_t
(
*
get_initiator_name
)(
struct
Scsi_Host
*
,
char
*
,
ssize_t
);
/*
* The driver sets these to tell the transport class it
* wants the attributes displayed in sysfs. If the show_ flag
* is not set, the attribute will be private to the transport
* class. We could probably just test if a get_ fn was set
* since we only use the values for sysfs but this is how
* fc does it too.
*/
unsigned
long
show_isid
:
1
;
unsigned
long
show_tsih
:
1
;
unsigned
long
show_header_digest
:
1
;
unsigned
long
show_data_digest
:
1
;
unsigned
long
show_port
:
1
;
unsigned
long
show_tpgt
:
1
;
unsigned
long
show_ip_address
:
1
;
unsigned
long
show_target_name
:
1
;
unsigned
long
show_target_alias
:
1
;
unsigned
long
show_initial_r2t
:
1
;
unsigned
long
show_immediate_data
:
1
;
unsigned
long
show_max_recv_data_segment_len
:
1
;
unsigned
long
show_max_burst_len
:
1
;
unsigned
long
show_first_burst_len
:
1
;
unsigned
long
show_def_time2wait
:
1
;
unsigned
long
show_def_time2retain
:
1
;
unsigned
long
show_max_outstanding_r2t
:
1
;
unsigned
long
show_data_pdu_in_order
:
1
;
unsigned
long
show_data_sequence_in_order
:
1
;
unsigned
long
show_erl
:
1
;
unsigned
long
show_initiator_name
:
1
;
unsigned
long
show_initiator_alias
:
1
;
};
struct
scsi_transport_template
*
iscsi_attach_transport
(
struct
iscsi_function_template
*
);
void
iscsi_release_transport
(
struct
scsi_transport_template
*
);
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment