Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
cta
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container Registry
Harbor Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
dCache
cta
Commits
c0d7039b
Commit
c0d7039b
authored
11 years ago
by
Steven Murray
Committed by
Steven Murray
7 years ago
Browse files
Options
Downloads
Patches
Plain Diff
Copied tape/sendscsicmd.c to rmc/rmc_send_scsi_cmd.c
parent
7ed1d80e
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
mediachanger/castorrmc/rmc/rmc_send_scsi_cmd.c
+310
-0
310 additions, 0 deletions
mediachanger/castorrmc/rmc/rmc_send_scsi_cmd.c
with
310 additions
and
0 deletions
mediachanger/castorrmc/rmc/rmc_send_scsi_cmd.c
0 → 100644
+
310
−
0
View file @
c0d7039b
/*
* Copyright (C) 1996-2000 by CERN/IT/PDP/DM
* All rights reserved
*/
/* send_scsi_cmd - Send a SCSI command to a device */
/* return -5 if not supported on this platform (serrno = SEOPNOTSUP)
* -4 if SCSI error (serrno = EIO)
* -3 if CAM error (serrno = EIO)
* -2 if ioctl fails with errno (serrno = errno)
* -1 if open/stat fails with errno (message fully formatted)
* 0 if successful with no data transfer
* >0 number of bytes transferred
*/
#include
<unistd.h>
#include
<sys/ioctl.h>
#include
<stdio.h>
#include
<string.h>
#include
<errno.h>
#include
<sys/types.h>
#include
<fcntl.h>
#include
<stdlib.h>
#include
<dirent.h>
#include
<sys/stat.h>
#include
<linux/version.h>
#include
<sys/param.h>
/* Impossible unless very very old kernels: */
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
#endif
#include
"/usr/include/scsi/sg.h"
#include
<sys/stat.h>
#include
"scsictl.h"
#include
"serrno.h"
#include
"Ctape.h"
static
char
tp_err_msgbuf
[
132
];
static
char
*
sk_msg
[]
=
{
"No sense"
,
"Recovered error"
,
"Not ready"
,
"Medium error"
,
"Hardware error"
,
"Illegal request"
,
"Unit attention"
,
"Data protect"
,
"Blank check"
,
"Vendor unique"
,
"Copy aborted"
,
"Aborted command"
,
"Equal"
,
"Volume overflow"
,
"Miscompare"
,
"Reserved"
,
};
struct
scsi_info
{
int
status
;
char
*
text
;
};
struct
scsi_info
scsi_codmsg
[]
=
{
{
SCSI_STATUS_CHECK_CONDITION
,
"Check condition"
},
{
SCSI_STATUS_BUSY
,
"Target busy"
},
{
SCSI_STATUS_RESERVATION_CONFLICT
,
"Reservation conflict"
},
{
0xFF
,
NULL
}
};
#define PROCBUFSZ 80
static
void
find_sgpath
(
char
*
sgpath
,
int
maj
,
int
min
)
{
/*
Find the sg device for a pair of major and minor device IDs
of a tape device. The match is done by
. identifying the tape's st device node
. getting the device's unique ID from sysfs
. searching the sg device with the same ID (in sysfs)
If no match is found, the returned sg path will be an empty
string.
*/
char
systape
[]
=
"/sys/class/scsi_tape"
;
char
sysgen
[]
=
"/sys/class/scsi_generic"
;
char
syspath
[
256
];
char
tlink
[
256
];
char
glink
[
256
];
int
match
=
0
;
DIR
*
dir_tape
,
*
dir_gen
;
struct
dirent
*
dirent
;
char
st_dev
[
64
];
struct
stat
sbuf
;
sgpath
[
0
]
=
'\0'
;
/* find the st sysfs entry */
if
(
!
(
dir_tape
=
opendir
(
systape
)))
return
;
while
((
dirent
=
readdir
(
dir_tape
)))
{
if
(
0
==
strcmp
(
"."
,
dirent
->
d_name
))
continue
;
if
(
0
==
strcmp
(
".."
,
dirent
->
d_name
))
continue
;
sprintf
(
st_dev
,
"/dev/%s"
,
dirent
->
d_name
);
stat
(
st_dev
,
&
sbuf
);
if
(
maj
==
(
int
)
major
(
sbuf
.
st_rdev
)
&&
min
==
(
int
)
minor
(
sbuf
.
st_rdev
))
{
sprintf
(
syspath
,
"%s/%s/device"
,
systape
,
dirent
->
d_name
);
match
=
1
;
break
;
}
}
closedir
(
dir_tape
);
if
(
0
==
match
)
return
;
memset
(
tlink
,
0
,
256
);
readlink
(
syspath
,
tlink
,
256
);
/* find the corresponding sg sysfs entry */
if
(
!
(
dir_gen
=
opendir
(
sysgen
)))
return
;
while
((
dirent
=
readdir
(
dir_gen
)))
{
if
(
0
==
strcmp
(
"."
,
dirent
->
d_name
))
continue
;
if
(
0
==
strcmp
(
".."
,
dirent
->
d_name
))
continue
;
sprintf
(
syspath
,
"%s/%s/device"
,
sysgen
,
dirent
->
d_name
);
memset
(
glink
,
0
,
256
);
readlink
(
syspath
,
glink
,
256
);
if
(
0
==
strcmp
(
glink
,
tlink
))
{
sprintf
(
sgpath
,
"/dev/%s"
,
dirent
->
d_name
);
goto
out
;
}
}
out:
closedir
(
dir_gen
);
return
;
}
int
send_scsi_cmd
(
const
int
tapefd
,
const
char
*
const
path
,
const
int
do_not_open
,
const
unsigned
char
*
const
cdb
,
const
int
cdblen
,
unsigned
char
*
const
buffer
,
const
int
buflen
,
char
*
const
sense
,
const
int
senselen
,
const
int
timeout
,
/* in milliseconds */
const
int
flags
,
int
*
const
nb_sense_ret
,
char
**
const
msgaddr
)
{
int
fd
;
FILE
*
fopen
();
int
n
;
int
resid
=
0
;
struct
stat
sbuf
;
struct
stat
sbufa
;
static
char
*
sg_buffer
;
static
int
sg_bufsiz
=
0
;
struct
sg_header
*
sg_hd
;
char
sgpath
[
80
];
int
timeout_in_jiffies
=
0
;
int
sg_big_buff_val
=
SG_BIG_BUFF
;
int
procfd
,
nbread
;
char
procbuf
[
PROCBUFSZ
];
(
void
)
senselen
;
/* First the value in /proc of the max buffer size for the sg driver */
procfd
=
open
(
"/proc/scsi/sg/def_reserved_size"
,
O_RDONLY
);
if
(
procfd
>=
0
)
{
memset
(
procbuf
,
0
,
PROCBUFSZ
);
nbread
=
read
(
procfd
,
procbuf
,
PROCBUFSZ
-
1
);
if
(
nbread
>
0
)
{
long
int
tmp
;
char
*
endptr
=
NULL
;
tmp
=
strtol
(
procbuf
,
&
endptr
,
10
);
if
(
endptr
==
NULL
||
*
endptr
==
'\n'
)
{
sg_big_buff_val
=
(
int
)
tmp
;
}
}
close
(
procfd
);
}
if
((
int
)
sizeof
(
struct
sg_header
)
+
cdblen
+
buflen
>
sg_big_buff_val
)
{
sprintf
(
tp_err_msgbuf
,
"blocksize too large (max %zd)
\n
"
,
sg_big_buff_val
-
sizeof
(
struct
sg_header
)
-
cdblen
);
*
msgaddr
=
tp_err_msgbuf
;
serrno
=
EINVAL
;
return
(
-
1
);
}
if
((
int
)
sizeof
(
struct
sg_header
)
+
cdblen
+
buflen
>
sg_bufsiz
)
{
if
(
sg_bufsiz
>
0
)
free
(
sg_buffer
);
if
((
sg_buffer
=
malloc
(
sizeof
(
struct
sg_header
)
+
cdblen
+
buflen
))
==
NULL
)
{
serrno
=
errno
;
sprintf
(
tp_err_msgbuf
,
TP005
);
*
msgaddr
=
tp_err_msgbuf
;
return
(
-
1
);
}
sg_bufsiz
=
sizeof
(
struct
sg_header
)
+
cdblen
+
buflen
;
}
if
(
do_not_open
)
{
fd
=
tapefd
;
strcpy
(
sgpath
,
path
);
}
else
{
if
(
stat
(
path
,
&
sbuf
)
<
0
)
{
serrno
=
errno
;
snprintf
(
tp_err_msgbuf
,
sizeof
(
tp_err_msgbuf
),
TP042
,
path
,
"stat"
,
strerror
(
errno
));
tp_err_msgbuf
[
sizeof
(
tp_err_msgbuf
)
-
1
]
=
'\0'
;
*
msgaddr
=
tp_err_msgbuf
;
return
(
-
1
);
}
/* get the major device ID of the sg devices ... */
if
(
stat
(
"/dev/sg0"
,
&
sbufa
)
<
0
)
{
serrno
=
errno
;
snprintf
(
tp_err_msgbuf
,
sizeof
(
tp_err_msgbuf
),
TP042
,
"/dev/sg0"
,
"stat"
,
strerror
(
errno
));
tp_err_msgbuf
[
sizeof
(
tp_err_msgbuf
)
-
1
]
=
'\0'
;
*
msgaddr
=
tp_err_msgbuf
;
return
(
-
1
);
}
/* ... to detect links and use the path directly! */
if
(
major
(
sbuf
.
st_rdev
)
==
major
(
sbufa
.
st_rdev
))
{
strcpy
(
sgpath
,
path
);
}
else
{
find_sgpath
(
sgpath
,
major
(
sbuf
.
st_rdev
),
minor
(
sbuf
.
st_rdev
));
}
if
((
fd
=
open
(
sgpath
,
O_RDWR
))
<
0
)
{
serrno
=
errno
;
snprintf
(
tp_err_msgbuf
,
sizeof
(
tp_err_msgbuf
),
TP042
,
sgpath
,
"open"
,
strerror
(
errno
));
tp_err_msgbuf
[
sizeof
(
tp_err_msgbuf
)
-
1
]
=
'\0'
;
*
msgaddr
=
tp_err_msgbuf
;
return
(
-
1
);
}
}
/* set the sg timeout (in jiffies) */
timeout_in_jiffies
=
timeout
*
HZ
/
1000
;
ioctl
(
fd
,
SG_SET_TIMEOUT
,
&
timeout_in_jiffies
);
memset
(
sg_buffer
,
0
,
sizeof
(
struct
sg_header
));
sg_hd
=
(
struct
sg_header
*
)
sg_buffer
;
sg_hd
->
reply_len
=
sizeof
(
struct
sg_header
)
+
((
flags
&
SCSI_IN
)
?
buflen
:
0
);
sg_hd
->
twelve_byte
=
cdblen
==
12
;
memcpy
(
sg_buffer
+
sizeof
(
struct
sg_header
),
cdb
,
cdblen
);
n
=
sizeof
(
struct
sg_header
)
+
cdblen
;
if
(
buflen
&&
(
flags
&
SCSI_OUT
))
{
memcpy
(
sg_buffer
+
n
,
buffer
,
buflen
);
n
+=
buflen
;
}
if
(
write
(
fd
,
sg_buffer
,
n
)
<
0
)
{
*
msgaddr
=
(
char
*
)
strerror
(
errno
);
serrno
=
errno
;
snprintf
(
tp_err_msgbuf
,
sizeof
(
tp_err_msgbuf
),
TP042
,
sgpath
,
"write"
,
*
msgaddr
);
tp_err_msgbuf
[
sizeof
(
tp_err_msgbuf
)
-
1
]
=
'\0'
;
*
msgaddr
=
tp_err_msgbuf
;
if
(
!
do_not_open
)
close
(
fd
);
return
(
-
2
);
}
if
((
n
=
read
(
fd
,
sg_buffer
,
sizeof
(
struct
sg_header
)
+
((
flags
&
SCSI_IN
)
?
buflen
:
0
)))
<
0
)
{
*
msgaddr
=
(
char
*
)
strerror
(
errno
);
serrno
=
errno
;
snprintf
(
tp_err_msgbuf
,
sizeof
(
tp_err_msgbuf
),
TP042
,
sgpath
,
"read"
,
*
msgaddr
);
tp_err_msgbuf
[
sizeof
(
tp_err_msgbuf
)
-
1
]
=
'\0'
;
*
msgaddr
=
tp_err_msgbuf
;
if
(
!
do_not_open
)
close
(
fd
);
return
(
-
2
);
}
if
(
!
do_not_open
)
close
(
fd
);
if
(
sg_hd
->
sense_buffer
[
0
])
{
memcpy
(
sense
,
sg_hd
->
sense_buffer
,
sizeof
(
sg_hd
->
sense_buffer
));
*
nb_sense_ret
=
sizeof
(
sg_hd
->
sense_buffer
);
}
if
(
sg_hd
->
sense_buffer
[
0
]
&
0x80
)
{
/* valid */
resid
=
sg_hd
->
sense_buffer
[
3
]
<<
24
|
sg_hd
->
sense_buffer
[
4
]
<<
16
|
sg_hd
->
sense_buffer
[
5
]
<<
8
|
sg_hd
->
sense_buffer
[
6
];
}
if
((
sg_hd
->
sense_buffer
[
0
]
&
0x70
)
&&
((
sg_hd
->
sense_buffer
[
2
]
&
0xE0
)
==
0
||
(
sg_hd
->
sense_buffer
[
2
]
&
0xF
)
!=
0
))
{
char
tmp_msgbuf
[
132
];
snprintf
(
tmp_msgbuf
,
sizeof
(
tmp_msgbuf
),
"%s ASC=%X ASCQ=%X"
,
sk_msg
[
*
(
sense
+
2
)
&
0xF
],
*
(
sense
+
12
),
*
(
sense
+
13
));
tmp_msgbuf
[
sizeof
(
tmp_msgbuf
)
-
1
]
=
'\0'
;
serrno
=
EIO
;
snprintf
(
tp_err_msgbuf
,
sizeof
(
tp_err_msgbuf
),
TP042
,
sgpath
,
"scsi"
,
tmp_msgbuf
);
tp_err_msgbuf
[
sizeof
(
tp_err_msgbuf
)
-
1
]
=
'\0'
;
*
msgaddr
=
tp_err_msgbuf
;
return
(
-
4
);
}
else
if
(
sg_hd
->
result
)
{
*
msgaddr
=
(
char
*
)
strerror
(
sg_hd
->
result
);
serrno
=
sg_hd
->
result
;
snprintf
(
tp_err_msgbuf
,
sizeof
(
tp_err_msgbuf
),
TP042
,
sgpath
,
"read"
,
*
msgaddr
);
tp_err_msgbuf
[
sizeof
(
tp_err_msgbuf
)
-
1
]
=
'\0'
;
*
msgaddr
=
tp_err_msgbuf
;
return
(
-
2
);
}
if
(
n
)
n
-=
sizeof
(
struct
sg_header
)
+
resid
;
if
(
n
&&
(
flags
&
SCSI_IN
))
memcpy
(
buffer
,
sg_buffer
+
sizeof
(
struct
sg_header
),
n
);
return
((
flags
&
SCSI_IN
)
?
n
:
buflen
-
resid
);
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment