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
nexedi
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