iSCSI/SCSI multi port/ALUA support

fix ALUA flag issue
fix NNA flag issue
fix fixed format sense data builder issue
This commit is contained in:
Le Zhang
2016-10-14 16:46:34 +08:00
parent b9b9508817
commit 547faf684d
17 changed files with 333 additions and 107 deletions

View File

@@ -16,6 +16,10 @@ limitations under the License.
package scsi
import (
"github.com/gostor/gotgt/pkg/util"
)
type SCSIPRServiceAction byte
type SCSIPRType byte
@@ -73,3 +77,39 @@ const (
func SCSICDBGroupID(opcode byte) byte {
return ((opcode >> 5) & 0x7)
}
/*
* Transfer Length (if any)
* Parameter List Length (if any)
* Allocation Length (if any)
*/
func SCSICDBBufXLength(scb []byte) (int64, bool) {
var (
opcode byte
length int64
group byte
ok bool = true
)
opcode = scb[0]
group = SCSICDBGroupID(opcode)
switch group {
case CBD_GROUPID_0:
length = int64(scb[4])
case CBD_GROUPID_1, CBD_GROUPID_2:
length = int64(util.GetUnalignedUint16(scb[7:9]))
case CBD_GROUPID_3:
if opcode == 0x7F {
length = int64(scb[7])
} else {
ok = false
}
case CBD_GROUPID_4:
length = int64(util.GetUnalignedUint32(scb[6:10]))
case CBD_GROUPID_5:
length = int64(util.GetUnalignedUint32(scb[10:14]))
default:
ok = false
}
return length, ok
}

View File

@@ -158,8 +158,8 @@ func NewSBCDevice(deviceType api.SCSIDeviceType) api.SCSIDeviceProtocol {
sbc.SCSIDeviceOps[api.MODE_SELECT_10] = NewSCSIDeviceOperation(SBCModeSelect, nil, PR_WE_FA|PR_EA_FA|PR_EA_FN|PR_WE_FN)
sbc.SCSIDeviceOps[api.MODE_SENSE_10] = NewSCSIDeviceOperation(SBCModeSense, nil, PR_WE_FA|PR_WE_FN|PR_EA_FA|PR_EA_FN)
sbc.SCSIDeviceOps[api.PERSISTENT_RESERVE_IN] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0)
sbc.SCSIDeviceOps[api.PERSISTENT_RESERVE_OUT] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0)
sbc.SCSIDeviceOps[api.PERSISTENT_RESERVE_IN] = NewSCSIDeviceOperation(SPCIllegalOp, nil, 0)
sbc.SCSIDeviceOps[api.PERSISTENT_RESERVE_OUT] = NewSCSIDeviceOperation(SPCIllegalOp, nil, 0)
sbc.SCSIDeviceOps[api.READ_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
sbc.SCSIDeviceOps[api.WRITE_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN|PR_WE_FA|PR_WE_FN)

View File

@@ -124,6 +124,7 @@ func NewSCSIDeviceOperation(fn api.CommandFunc, sa *SCSIServiceAction, pr uint8)
func BuildSenseData(cmd *api.SCSICommand, key byte, asc SCSISubError) {
senseBuffer := &bytes.Buffer{}
inBufLen, ok := SCSICDBBufXLength(cmd.SCB.Bytes())
if cmd.Device.Attrs.SenseFormat {
// descriptor format
@@ -149,8 +150,19 @@ func BuildSenseData(cmd *api.SCSICommand, key byte, asc SCSISubError) {
}
senseBuffer.WriteByte((byte(asc) >> 8) & 0xff)
senseBuffer.WriteByte(byte(asc) & 0xff)
senseBuffer.WriteByte(0x00)
senseBuffer.WriteByte(0x00)
senseBuffer.WriteByte(0x00)
senseBuffer.WriteByte(0x00)
cmd.SenseLength = length + 8
}
if ok {
if int64(len(senseBuffer.Bytes())) > inBufLen {
senseBuffer.Truncate(int(inBufLen))
}
} else {
glog.V(2).Infof("cannot calc cbd alloc length. truncate failed")
}
cmd.Result = key
cmd.SenseBuffer = senseBuffer
}

View File

@@ -76,7 +76,7 @@ func InitSCSILUMap(config *config.Config) error {
globalSCSILUMap.AllDevices[bs.DeviceID] = lu
}
for tgtName, tgt := range config.Targets {
for tgtName, tgt := range config.ISCSITargets {
for lunstr, deviceID := range tgt.LUNs {
lun, err := strconv.ParseUint(lunstr, 10, 64)
if err != nil {

View File

@@ -122,8 +122,8 @@ const (
INQUIRY_SCCS = byte(0x80)
INQUIRY_AAC = byte(0x40)
INQUIRY_TPGS_NO = byte(0x00)
INQUIRY_TPGS_IMPLICIT = byte(0x20)
INQUIRY_TPGS_EXPLICIT = byte(0x10)
INQUIRY_TPGS_IMPLICIT = byte(0x10)
INQUIRY_TPGS_EXPLICIT = byte(0x20)
INQUIRY_TPGS_BOTH = byte(0x30)
INQUIRY_3PC = byte(0x08)
INQUIRY_Reserved = byte(0x06)
@@ -189,11 +189,12 @@ const (
const (
SCSI_VendorID = "GOSTOR"
SCSI_ProductID = "GOTGT-VDISK"
SCSI_ProductID = "GOTGT"
)
func SPCIllegalOp(host int, cmd *api.SCSICommand) api.SAMStat {
return api.SAMStatGood
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
return api.SAMStatCheckCondition
}
func SPCLuOffline(lu *api.SCSILu) error {
@@ -282,12 +283,16 @@ func InquiryPage0x83(host int, cmd *api.SCSICommand) (*bytes.Buffer, uint16) {
buf = &bytes.Buffer{}
descBuf = &bytes.Buffer{}
data []byte = []byte{}
pageLength uint16 = 0
portName []byte
pageLength uint16 = 0
portID uint16 = cmd.RelTargetPortID
portGroup uint16 = FindTargetGroup(cmd.Target, portID)
targetPort *api.SCSITargetPort = FindTargetPort(cmd.Target, portID)
)
//DESCRIPTOR 1 TARGET NAME
descBuf.WriteByte((PIV_ISCSI << 4) | INQ_CODE_ASCII)
descBuf.WriteByte(0x80 | ASS_TGT_PORT | DESG_VENDOR)
descBuf.WriteByte(0x80 | (ASS_TGT_PORT << 4) | DESG_VENDOR)
descBuf.WriteByte(0x00)
//length
descBuf.WriteByte(byte(len([]byte(cmd.Target.Name))))
@@ -296,7 +301,7 @@ func InquiryPage0x83(host int, cmd *api.SCSICommand) (*bytes.Buffer, uint16) {
//DESCRIPTOR 2 NNA Locally
descBuf.WriteByte((PIV_ISCSI << 4) | INQ_CODE_BIN)
descBuf.WriteByte(0x80 | ASS_TGT_PORT | DESG_NAA)
descBuf.WriteByte(0x80 | (ASS_LU << 4) | DESG_NAA)
descBuf.WriteByte(0x00)
//length
descBuf.WriteByte(0x08)
@@ -305,25 +310,37 @@ func InquiryPage0x83(host int, cmd *api.SCSICommand) (*bytes.Buffer, uint16) {
//TODO: Target Port Group(0x05), Relative Target port identifier(0x04)
/*
//DESCRIPTOR 3 TPG
descBuf.WriteByte((PIV_ISCSI << 4) | INQ_CODE_BIN)
descBuf.WriteByte(0x80 | ASS_TGT_PORT | DESG_REL_TGT_PORT)
descBuf.WriteByte(0x00)
//length
descBuf.WriteByte(0x08)
//TPG
binary.Write(descBuf, binary.BigEndian,)
//DESCRIPTOR 3 TPG
descBuf.WriteByte((PIV_ISCSI << 4) | INQ_CODE_BIN)
descBuf.WriteByte(0x80 | (ASS_TGT_PORT << 4) | DESG_TGT_PORT_GRP)
descBuf.WriteByte(0x00)
//length
descBuf.WriteByte(0x04)
//TPG
descBuf.WriteByte(0x00)
descBuf.WriteByte(0x00)
binary.Write(descBuf, binary.BigEndian, portGroup)
//DESCRIPTOR 4 RTPI
descBuf.WriteByte((PIV_ISCSI << 4) | INQ_CODE_BIN)
descBuf.WriteByte(0x80 | ASS_TGT_PORT | DESG_NAA)
descBuf.WriteByte(0x00)
//length
descBuf.WriteByte(0x08)
//RTPGI
binary.Write(descBuf, binary.BigEndian,)
*/
//DESCRIPTOR 4 Relative Target Port ID
descBuf.WriteByte((PIV_ISCSI << 4) | INQ_CODE_BIN)
descBuf.WriteByte(0x80 | (ASS_TGT_PORT << 4) | DESG_REL_TGT_PORT)
descBuf.WriteByte(0x00)
//length
descBuf.WriteByte(0x04)
//RTPGI
descBuf.WriteByte(0x00)
descBuf.WriteByte(0x00)
binary.Write(descBuf, binary.BigEndian, portID)
//DESCRIPTOR 5 SCSI Name,Port
portName = util.StringToByte(targetPort.TargetPortName, 4, 256)
descBuf.WriteByte((PIV_ISCSI << 4) | INQ_CODE_UTF8)
descBuf.WriteByte(0x80 | (ASS_TGT_PORT << 4) | DESG_SCSI)
descBuf.WriteByte(0x00)
//length
descBuf.WriteByte(byte(len(portName)))
//RTPGI
descBuf.Write(portName)
data = descBuf.Bytes()
pageLength = uint16(len(data))
@@ -395,7 +412,7 @@ func SPCInquiry(host int, cmd *api.SCSICommand) api.SAMStat {
} else {
//byte 5
//SCCS(0) AAC(0) TPGS(0) 3PC(0) PROTECT(0)
addBuf.WriteByte(0x00)
addBuf.WriteByte(INQUIRY_TPGS_IMPLICIT)
//byte 6
//ENCSERV(0) VS(0) MULTIP(0) ADDR16(0)
addBuf.WriteByte(0x00)

View File

@@ -31,15 +31,40 @@ func (s *SCSITargetService) NewSCSITarget(tid int, driverName, name string) (*ap
// verify the low level driver
var target = &api.SCSITarget{
Name: name,
TID: tid,
Name: name,
TID: tid,
TargetPortGroups: []*api.TargetPortGroup{},
}
tpg := &api.TargetPortGroup{0, []*api.SCSITargetPort{}}
s.Targets = append(s.Targets, target)
target.Devices = GetTargetLUNMap(target.Name)
target.LUN0 = NewLUN0()
target.TargetPortGroups = append(target.TargetPortGroups, tpg)
return target, nil
}
func FindTargetGroup(target *api.SCSITarget, relPortID uint16) uint16 {
for _, tpg := range target.TargetPortGroups {
for _, port := range tpg.TargetPortGroup {
if port.RelativeTargetPortID == relPortID {
return tpg.GroupID
}
}
}
return 0
}
func FindTargetPort(target *api.SCSITarget, relPortID uint16) *api.SCSITargetPort {
for _, tpg := range target.TargetPortGroups {
for _, port := range tpg.TargetPortGroup {
if port.RelativeTargetPortID == relPortID {
return port
}
}
}
return nil
}
func deviceReserve(cmd *api.SCSICommand) error {
var lu *api.SCSILu
lun := *(*uint64)(unsafe.Pointer(&cmd.Lun))