-
Notifications
You must be signed in to change notification settings - Fork 0
/
controller_fabric.go
182 lines (146 loc) · 5.94 KB
/
controller_fabric.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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
package nvme
import (
"fmt"
"github.com/thirdmartini/go-nvme/internal/serialize"
"github.com/thirdmartini/go-nvme/pkg/tracer"
"github.com/thirdmartini/go-nvme/protocol"
)
const (
SQFlowControlDisabled = 1 << 2
)
func (c *Controller) handleFabricCommand(w *NVMEResponse, r *NVMERequest) error {
capsule := r.Capsule()
c.Log.Trace(tracer.TraceFabric, "%s", capsule)
switch capsule.FCType {
// 3.3 Connect Command and Response
case protocol.FabricCmdConnect:
// When fabric connects, it should always connect with controller set to 0xFFFF and QID set to 0
// This is the admin queue
// we will then be probed for setings and configuration and will get a connection for
// a specific controller and Queue ID. ...
// this wil then be an IO connection
// reinterpret the command
fcc := protocol.ConnectCommand{}
if r.ReinterpretCapsule(&fcc) != nil {
tracer.Fatal("reinterpret error")
}
ds := serialize.NewDeserializer(r.Payload())
fcd := protocol.ConnectData{}
if err := ds.Deserialize(&fcd); err != nil {
tracer.Fatal("deserialize error:" + err.Error())
}
//utilPrettyPrint(fcc)
c.Log.Trace(tracer.TraceCapsuleDetail, " SQSIZE: %d", fcc.QueueSize+1) // zero based
c.Log.Trace(tracer.TraceCapsuleDetail, " CATTR: %x", fcc.CATTR)
c.Log.Trace(tracer.TraceCapsuleDetail, " KATO: %d", fcc.KATO)
c.Log.Trace(tracer.TraceCapsuleDetail, " CNTLID/QID: 0x%x (%d) / %d", fcd.CNTLID, fcd.CNTLID, fcc.QueueID)
c.Log.Trace(tracer.TraceCapsuleDetail, " HOST NQN: %s", fcd.HostNQN)
c.Log.Trace(tracer.TraceCapsuleDetail, " SUB NQN: %s", fcd.SubNQN)
c.ConnectedHostNQN = fcd.HostNQN
c.ConnectedSubNQN = fcd.SubNQN
// TODO: rework this, we will alias ourselves to this queue now
// if queue is 0 its ALWAYS the admin queue
c.QueueID = fcc.QueueID
// did not find the subsystem we need
subsys := c.Server.GetSubSystem(c.ConnectedSubNQN)
if subsys == nil {
offset := uint64(256) | 0x10000 // offset of NQN in request + set the start of data
w.SetStatus(protocol.SCNamespaceNotReady)
sm := serialize.New(w.Response.FabricResponse[0:])
sm.Serialize(&offset)
return nil
}
// New
c.Subsystem = subsys
// we can resize past our controller limits!
if int(fcc.QueueSize+1) > len(c.Queue) {
tracer.Fatal("protocol.FabricCmdConnect: cant resize past queue size: %+v", capsule)
}
c.QueueSize = fcc.QueueSize + 1
// Controller ID (CNTLID): Specifies the controller ID allocated to the host. If a
// particular controller was specified in the CNTLID field of the Connect command,
// then this field shall contain the same value
if fcd.CNTLID == 0xFFFF {
if c.ControllerID == 0 {
c.ControllerID = 7
//atomic.AddInt32(controllersAvailable)
//controllersAvailable++
val := uint32(c.ControllerID)
sm := serialize.New(w.Response.FabricResponse[:])
sm.Serialize(&val)
fmt.Printf("C: %d FCR: %+v\n", c.ControllerID, w.Response.FabricResponse)
}
} else {
// FIXME: this may not be the correct thing to do
c.ControllerID = fcd.CNTLID
}
if fcc.CATTR&SQFlowControlDisabled == SQFlowControlDisabled {
c.FlowControlDisabled = true
}
w.Response.QueueID = c.QueueID
// w.Response.QueueID = 0
// 3.5 Property Get Command and Response
case protocol.FabricCmdPropertyGet:
// D10 contains the size: 000:4bytes | 001:8bytes
c.Log.Trace(tracer.TraceCommands, " Property: 0x%0x (Size:%x)", capsule.D11, capsule.D10&0x7)
val := uint64(0)
switch capsule.D11 {
case protocol.PropertyControllerCapabilities: // Controller Capabilities Register
val = c.REGCtrlCaps
case protocol.PropertyVersion: // Controller Version Register
val = uint64(c.Version)
case protocol.PropertyControllerStatus: // Controller Status Register (0x1c)
c.Log.Trace(tracer.TraceAll, "Get: protocol.PropertyControllerStatus: 0x%x\n", c.REGCtrlStatus)
val = uint64(c.REGCtrlStatus)
case protocol.PropertyControllerConfiguration: // Controller Configuration
val = uint64(c.REGCtrlConfig)
case protocol.PropertySubsystemReset: // RESET
// FIXME: pretend we reset
default:
tracer.Fatal("protocol.FabricCmdPropertyGet %+v", capsule)
}
sm := serialize.New(w.Response.FabricResponse[:])
sm.Serialize(&val)
case protocol.FabricCmdPropertySet:
c.Log.Trace(tracer.TraceCapsuleDetail, " Property: 0x%0x Value: 0x%x", capsule.D11, capsule.D12)
switch capsule.D11 {
case protocol.PropertyControllerConfiguration: // Controller Configuration
// bits 04:06 000 (NVM Command Set) | 111 Admin Command Set
// bits 07:10 MPS (2 ^ (12 + MPS)).
// RW bits 11:13 AMS
// RW bits 14:15 SHN (00 no notification, 01 normal, 10 Abrupt )
// RW bits 16:19 IO Q Size ( 2^n )
// RW Completion Q Size (2^n)
c.REGCtrlConfig = capsule.D12
if c.REGCtrlConfig&0xc000 != 0 {
// we instantly go to shutdown mode
c.REGCtrlStatus |= 0x2 << 2
c.REGCtrlStatus &= ^uint32(1) // clear ready bit
// We're being asked for a shutdown
c.Log.Trace(tracer.TraceCommands, " Shutdown: %x", c.REGCtrlStatus)
//w.Shutdown = true
return nil
}
// 1.0 The controller starts with REGCtrlStatus:0 indicating the controller is offline
if c.REGCtrlStatus == 0 {
// (1.1) host has to first set REGCtrlConfig:1 indicating it wants to enable the controller
if c.REGCtrlConfig&0x1 == 0x1 {
// (1.2) in response the controller (we) set c.REGCtrlStatus |= 0x1
c.REGCtrlStatus |= 0x1 // enable controller
}
}
default:
tracer.Fatal("protocol.FabricCmdPropertySet %+v", capsule)
}
case protocol.FabricCmdAuthenticationReceive:
c.Log.Todo("protocol.FabricCmdAuthenticationReceive: %+v", capsule)
// Nothing to do here
case protocol.FabricCmdDisconnect:
c.Log.Todo("protocol.FabricCmdDisconnect %+v", capsule)
// Nothing to do here, target about to close the session
default:
c.Log.Todo("protocol.FabricCmdAuthenticationReceive: %+v", capsule)
tracer.Fatal("unknown fabric command %x", capsule.FCType)
}
return nil
}