-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathsg.go
160 lines (148 loc) · 4.4 KB
/
sg.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package sgio
import (
"bytes"
"fmt"
"os"
"syscall"
"unsafe"
)
const (
SG_GET_VERSION_NUM = 0x2282
SG_IO = 0x2285
SG_INFO_OK_MASK = 0x1
SG_INFO_OK = 0x0
SG_DXFER_TO_DEV = -2
SG_DXFER_FROM_DEV = -3
SG_DXFER_TO_FROM_DEV = -4
INQ_CMD_CODE = 0x12
INQ_REPLY_LEN = 96
SENSE_BUF_LEN = 32
TIMEOUT_20_SECS = 20000
)
// pahole for sg_io_hdr_t on amd64
/*
* struct sg_io_hdr {
* int interface_id; // 0 4
* int dxfer_direction; // 4 4
* unsigned char cmd_len; // 8 1
* unsigned char mx_sb_len; // 9 1
* short unsigned int iovec_count; // 10 2
* unsigned int dxfer_len; // 12 4
* void * dxferp; // 16 8
* unsigned char * cmdp; // 24 8
* unsigned char * sbp; // 32 8
* unsigned int timeout; // 40 4
* unsigned int flags; // 44 4
* int pack_id; // 48 4
*
* // XXX 4 bytes hole, try to pack
*
* void * usr_ptr; // 56 8
* // --- cacheline 1 boundary (64 bytes) ---
* unsigned char status; // 64 1
* unsigned char masked_status; // 65 1
* unsigned char msg_status; // 66 1
* unsigned char sb_len_wr; // 67 1
* short unsigned int host_status; // 68 2
* short unsigned int driver_status; // 70 2
* int resid; // 72 4
* unsigned int duration; // 76 4
* unsigned int info; // 80 4
*
* // size: 88, cachelines: 2, members: 22
* // sum members: 80, holes: 1, sum holes: 4
* // padding: 4
* // last cacheline: 24 bytes
* };
*/
// SgIoHdr is our version of sg_io_hdr_t that gets passed to the SG_IO ioctl
type SgIoHdr struct {
InterfaceID int32
DxferDirection int32
CmdLen uint8
MxSbLen uint8
IovecCount uint16
DxferLen uint32
Dxferp *byte
Cmdp *uint8
Sbp *byte
Timeout uint32
Flags uint32
PackID int32
pad0 [4]byte
UsrPtr *byte
Status uint8
MaskedStatus uint8
MsgStatus uint8
SbLenWr uint8
HostStatus uint16
DriverStatus uint16
Resid int32
Duration uint32
Info uint32
}
func TestUnitReady(f *os.File) error {
senseBuf := make([]byte, SENSE_BUF_LEN)
inqCmdBlk := []uint8{0, 0, 0, 0, 0, 0}
ioHdr := &SgIoHdr{
InterfaceID: int32('S'),
CmdLen: uint8(len(inqCmdBlk)),
MxSbLen: SENSE_BUF_LEN,
DxferDirection: SG_DXFER_FROM_DEV,
Cmdp: &inqCmdBlk[0],
Sbp: &senseBuf[0],
Timeout: TIMEOUT_20_SECS,
}
err := SgioSyscall(f, ioHdr)
if err != nil {
return err
}
err = CheckSense(ioHdr, &senseBuf)
if err != nil {
return err
}
return nil
}
func CheckSense(i *SgIoHdr, s *[]byte) error {
var b bytes.Buffer
if (i.Info & SG_INFO_OK_MASK) != SG_INFO_OK {
_, err := b.WriteString(
fmt.Sprintf("SCSI response not ok\n"+
"SCSI status: %v host status: %v driver status: %v",
i.Status, i.HostStatus, i.DriverStatus))
if err != nil {
return err
}
if i.SbLenWr > 0 {
_, err := b.WriteString(
fmt.Sprintf("\nSENSE:\n%v\n%v",
dumpHex(*s), GetErrString((*s)[12], (*s)[13])))
if err != nil {
return err
}
}
return fmt.Errorf(b.String())
}
return nil
}
func SgioSyscall(f *os.File, i *SgIoHdr) error {
return ioctl(f.Fd(), SG_IO, uintptr(unsafe.Pointer(i)))
}
func ioctl(fd, cmd, ptr uintptr) error {
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, cmd, ptr)
if err != 0 {
return err
}
return nil
}
func OpenScsiDevice(fname string) (*os.File, error) {
f, err := os.OpenFile(fname, os.O_RDWR, 0)
if err != nil {
return nil, err
}
var version uint32
if (ioctl(f.Fd(), SG_GET_VERSION_NUM, uintptr(unsafe.Pointer(&version))) != nil) || (version < 30000) {
return nil, fmt.Errorf("device does not appear to be an sg device")
}
return f, nil
}