fix bugs and make it run basically
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2015 The GoStor Authors All rights reserved.
|
||||
Copyright 2016 The GoStor Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,13 +16,133 @@ limitations under the License.
|
||||
|
||||
package iscsit
|
||||
|
||||
import "crypto/rand"
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
SESSION_NORMAL int = 0
|
||||
SESSION_DISCOVERY int = 1
|
||||
)
|
||||
|
||||
var DIGEST_CRC32C uint = 1 << 1
|
||||
var DIGEST_NONE uint = 1 << 0
|
||||
var DIGEST_ALL uint = DIGEST_NONE | DIGEST_CRC32C
|
||||
var BHS_SIZE = 48
|
||||
|
||||
const (
|
||||
MAX_QUEUE_CMD_MIN = 1
|
||||
MAX_QUEUE_CMD_DEF = 128
|
||||
MAX_QUEUE_CMD_MAX = 512
|
||||
)
|
||||
|
||||
const (
|
||||
ISCSI_PARAM_MAX_RECV_DLENGTH = iota
|
||||
ISCSI_PARAM_HDRDGST_EN
|
||||
ISCSI_PARAM_DATADGST_EN
|
||||
ISCSI_PARAM_INITIAL_R2T_EN
|
||||
ISCSI_PARAM_MAX_R2T
|
||||
ISCSI_PARAM_IMM_DATA_EN
|
||||
ISCSI_PARAM_FIRST_BURST
|
||||
ISCSI_PARAM_MAX_BURST
|
||||
ISCSI_PARAM_PDU_INORDER_EN
|
||||
ISCSI_PARAM_DATASEQ_INORDER_EN
|
||||
ISCSI_PARAM_ERL
|
||||
ISCSI_PARAM_IFMARKER_EN
|
||||
ISCSI_PARAM_OFMARKER_EN
|
||||
ISCSI_PARAM_DEFAULTTIME2WAIT
|
||||
ISCSI_PARAM_DEFAULTTIME2RETAIN
|
||||
ISCSI_PARAM_OFMARKINT
|
||||
ISCSI_PARAM_IFMARKINT
|
||||
ISCSI_PARAM_MAXCONNECTIONS
|
||||
/* iSCSI Extensions for RDMA (RFC5046) */
|
||||
ISCSI_PARAM_RDMA_EXTENSIONS
|
||||
ISCSI_PARAM_TARGET_RDSL
|
||||
ISCSI_PARAM_INITIATOR_RDSL
|
||||
ISCSI_PARAM_MAX_OUTST_PDU
|
||||
/* "local" parmas, never sent to the initiator */
|
||||
ISCSI_PARAM_FIRST_LOCAL
|
||||
ISCSI_PARAM_MAX_XMIT_DLENGTH = ISCSI_PARAM_FIRST_LOCAL
|
||||
ISCSI_PARAM_MAX_QUEUE_CMD
|
||||
/* must always be last */
|
||||
ISCSI_PARAM_MAX
|
||||
)
|
||||
|
||||
type ISCSISessionParam struct {
|
||||
State int
|
||||
Value uint
|
||||
}
|
||||
|
||||
/*
|
||||
* The defaults here are according to the spec and must not be changed,
|
||||
* otherwise the initiator may make the wrong assumption. If you want
|
||||
* to change a value, edit the value in iscsi_target_create.
|
||||
*
|
||||
* The param MaxXmitDataSegmentLength doesn't really exist. It's a way
|
||||
* to remember the RDSL of the initiator, which defaults to 8k if he has
|
||||
* not told us otherwise.
|
||||
*/
|
||||
type iscsiSessionKeys struct {
|
||||
name string
|
||||
def uint
|
||||
min uint
|
||||
max uint
|
||||
}
|
||||
|
||||
var sessionKeys []iscsiSessionKeys = []iscsiSessionKeys{
|
||||
// ISCSI_PARAM_MAX_RECV_DLENGTH
|
||||
{"MaxRecvDataSegmentLength", 8192, 512, 16777215},
|
||||
// ISCSI_PARAM_HDRDGST_EN
|
||||
{"HeaderDigest", DIGEST_NONE, DIGEST_NONE, DIGEST_ALL},
|
||||
// ISCSI_PARAM_DATADGST_EN
|
||||
{"DataDigest", DIGEST_NONE, DIGEST_NONE, DIGEST_ALL},
|
||||
// ISCSI_PARAM_INITIAL_R2T_EN
|
||||
{"InitialR2T", 1, 0, 1},
|
||||
// ISCSI_PARAM_MAX_R2T
|
||||
{"MaxOutstandingR2T", 1, 1, 65535},
|
||||
// ISCSI_PARAM_IMM_DATA_EN
|
||||
{"ImmediateData", 1, 0, 1},
|
||||
// ISCSI_PARAM_FIRST_BURST
|
||||
{"FirstBurstLength", 65536, 512, 16777215},
|
||||
// ISCSI_PARAM_MAX_BURST
|
||||
{"MaxBurstLength", 262144, 512, 16777215},
|
||||
// ISCSI_PARAM_PDU_INORDER_EN
|
||||
{"DataPDUInOrder", 1, 0, 1},
|
||||
// ISCSI_PARAM_DATASEQ_INORDER_EN
|
||||
{"DataSequenceInOrder", 1, 0, 1},
|
||||
// ISCSI_PARAM_ERL
|
||||
{"ErrorRecoveryLevel", 0, 0, 2},
|
||||
// ISCSI_PARAM_IFMARKER_EN
|
||||
{"IFMarker", 0, 0, 1},
|
||||
// ISCSI_PARAM_OFMARKER_EN
|
||||
{"OFMarker", 0, 0, 1},
|
||||
// ISCSI_PARAM_DEFAULTTIME2WAIT
|
||||
{"DefaultTime2Wait", 2, 0, 3600},
|
||||
// ISCSI_PARAM_DEFAULTTIME2RETAIN
|
||||
{"DefaultTime2Retain", 20, 0, 3600},
|
||||
// ISCSI_PARAM_OFMARKINT
|
||||
{"OFMarkInt", 2048, 1, 65535},
|
||||
// ISCSI_PARAM_IFMARKINT
|
||||
{"IFMarkInt", 2048, 1, 65535},
|
||||
// ISCSI_PARAM_MAXCONNECTIONS
|
||||
{"MaxConnections", 1, 1, 65535},
|
||||
// ISCSI_PARAM_RDMA_EXTENSIONS
|
||||
{"RDMAExtensions", 0, 0, 1},
|
||||
// ISCSI_PARAM_TARGET_RDSL
|
||||
{"TargetRecvDataSegmentLength", 8192, 512, 16777215},
|
||||
// ISCSI_PARAM_INITIATOR_RDSL
|
||||
{"InitiatorRecvDataSegmentLength", 8192, 512, 16777215},
|
||||
// ISCSI_PARAM_MAX_OUTST_PDU
|
||||
{"MaxOutstandingUnexpectedPDUs", 0, 2, 4294967295},
|
||||
// "local" parmas, never sent to the initiator
|
||||
// ISCSI_PARAM_MAX_XMIT_DLENGTH
|
||||
{"MaxXmitDataSegmentLength", 8192, 512, 16777215},
|
||||
// ISCSI_PARAM_MAX_QUEUE_CMD
|
||||
{"MaxQueueCmd", MAX_QUEUE_CMD_DEF, MAX_QUEUE_CMD_MIN, MAX_QUEUE_CMD_MAX},
|
||||
}
|
||||
|
||||
// Session is an iSCSI session.
|
||||
type ISCSISession struct {
|
||||
Refcount int
|
||||
@@ -30,58 +150,112 @@ type ISCSISession struct {
|
||||
InitiatorAlias string
|
||||
Target *ISCSITarget
|
||||
Isid uint64
|
||||
Tsih uint16
|
||||
Tsih uint64
|
||||
|
||||
ExpCmdSN uint32
|
||||
// only one connection per session
|
||||
Connections []*ISCSIConnection
|
||||
Commands []*ISCSICommand
|
||||
PendingCommands []*ISCSICommand
|
||||
ExpectionCommandSN uint32
|
||||
MaxQueueCommand uint32
|
||||
SessionParam []ISCSISessionParam
|
||||
Info string
|
||||
Rdma int
|
||||
Connections []*iscsiConnection
|
||||
Commands []*ISCSICommand
|
||||
PendingTasks taskQueue
|
||||
MaxQueueCommand uint32
|
||||
SessionParam []ISCSISessionParam
|
||||
Info string
|
||||
Rdma int
|
||||
}
|
||||
|
||||
type ISCSIHeader struct {
|
||||
type taskQueue []*iscsiTask
|
||||
|
||||
func (tq taskQueue) Len() int { return len(tq) }
|
||||
|
||||
func (tq taskQueue) Less(i, j int) bool {
|
||||
// We want Pop to give us the highest, not lowest, priority so we use greater than here.
|
||||
return tq[i].cmd.CmdSN > tq[j].cmd.CmdSN
|
||||
}
|
||||
|
||||
type ISCSIPdu struct {
|
||||
Bhs ISCSIHeader
|
||||
AhsSize uint
|
||||
DataSize uint
|
||||
func (tq taskQueue) Swap(i, j int) {
|
||||
tq[i], tq[j] = tq[j], tq[i]
|
||||
}
|
||||
|
||||
type ISCSIConnection struct {
|
||||
State int
|
||||
RxIostate int
|
||||
TxIostate int
|
||||
Refcount int
|
||||
func (tq *taskQueue) Push(x interface{}) {
|
||||
item := x.(*iscsiTask)
|
||||
*tq = append(*tq, item)
|
||||
}
|
||||
|
||||
Session *ISCSISession
|
||||
func (tq *taskQueue) Pop() interface{} {
|
||||
old := *tq
|
||||
n := len(old)
|
||||
item := old[n-1]
|
||||
*tq = old[0 : n-1]
|
||||
return item
|
||||
}
|
||||
|
||||
TID int
|
||||
CID int
|
||||
Auth AuthMethod
|
||||
StatSN uint32
|
||||
ExpectionStatSN uint32
|
||||
CommandSN uint32
|
||||
ExpectionCommandSN uint32
|
||||
MaxCommandSN uint32
|
||||
Request ISCSIPdu
|
||||
Response ISCSIPdu
|
||||
// The BHS is 48 bytes long. The Opcode and DataSegmentLength fields
|
||||
// appear in all iSCSI PDUs. In addition, when used, the Initiator Task
|
||||
// Tag and Logical Unit Number always appear in the same location in the
|
||||
// header.
|
||||
type iscsiHeader struct {
|
||||
opcode uint8
|
||||
flags uint8 // Final bit
|
||||
rsvd2 [2]uint8
|
||||
hlength uint8 // AHSs total length
|
||||
dlength [3]uint8 // Data length
|
||||
lun [8]uint8
|
||||
itt uint8 // Initiator Task Tag
|
||||
ttt uint8 // Target Task Tag
|
||||
statsn uint8
|
||||
expStatSN uint8
|
||||
maxStatSN uint8
|
||||
other [12]uint8
|
||||
}
|
||||
|
||||
type iscsiPdu struct {
|
||||
bhs iscsiHeader
|
||||
ahsSize uint
|
||||
dataSize uint
|
||||
}
|
||||
|
||||
// New creates a new session.
|
||||
func NewISCSISession() (*ISCSISession, error) {
|
||||
var tsih uint16
|
||||
b := make([]byte, 2)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tsih += uint16(b[0]) << 8
|
||||
tsih += uint16(b[1])
|
||||
func (s *ISCSITargetService) NewISCSISession(conn *iscsiConnection) (*ISCSISession, error) {
|
||||
var (
|
||||
target *ISCSITarget
|
||||
tsih uint64
|
||||
)
|
||||
|
||||
return &ISCSISession{
|
||||
Tsih: tsih,
|
||||
}, nil
|
||||
for _, t := range s.Targets {
|
||||
if t.TID == conn.tid {
|
||||
target = t
|
||||
break
|
||||
}
|
||||
}
|
||||
if target == nil {
|
||||
return nil, fmt.Errorf("No target found with tid(%d)", conn.tid)
|
||||
}
|
||||
|
||||
for {
|
||||
rand.Seed(int64(time.Now().UTC().Nanosecond()))
|
||||
tsih = uint64(rand.Uint32())
|
||||
for _, s := range target.Sessions {
|
||||
if s.Tsih == tsih {
|
||||
tsih = 0
|
||||
break
|
||||
}
|
||||
}
|
||||
if tsih != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
sess := &ISCSISession{
|
||||
Tsih: tsih,
|
||||
Initiator: conn.initiator,
|
||||
InitiatorAlias: conn.initiatorAlias,
|
||||
Target: target,
|
||||
Connections: []*iscsiConnection{conn},
|
||||
SessionParam: conn.sessionParam,
|
||||
MaxQueueCommand: uint32(conn.sessionParam[ISCSI_PARAM_MAX_QUEUE_CMD].Value),
|
||||
Rdma: 0,
|
||||
ExpCmdSN: conn.expCmdSN,
|
||||
}
|
||||
conn.session = sess
|
||||
return sess, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user