Merge pull request #60 from carmark/mode_sense

update mode sense command
This commit is contained in:
Lei Xue
2017-07-11 20:33:33 +08:00
committed by GitHub
9 changed files with 199 additions and 75 deletions

View File

@@ -43,7 +43,9 @@ script:
- ./test-tool/iscsi-test-cu -d -A --test=ALL.Inquiry.MandatoryVPDSBC iscsi://127.0.0.1:3260/${TARGET}/0
- ./test-tool/iscsi-test-cu -d -A --test=ALL.Inquiry.SupportedVPD iscsi://127.0.0.1:3260/${TARGET}/0
- ./test-tool/iscsi-test-cu -d -A --test=ALL.Inquiry.VersionDescriptors iscsi://127.0.0.1:3260/${TARGET}/0
- ./test-tool/iscsi-test-cu -d -A --test=ALL.Inquiry.EVPD iscsi://127.0.0.1:3260/${TARGET}/0
- ./test-tool/iscsi-test-cu -d -A --test=ALL.Mandatory iscsi://127.0.0.1:3260/${TARGET}/0
- ./test-tool/iscsi-test-cu -d -A --test=ALL.ModeSense6 iscsi://127.0.0.1:3260/${TARGET}/0
- ./test-tool/iscsi-test-cu -d -A --test=ALL.NoMedia iscsi://127.0.0.1:3260/${TARGET}/0
- ./test-tool/iscsi-test-cu -d -A --test=ALL.Prefetch10 iscsi://127.0.0.1:3260/${TARGET}/0
- ./test-tool/iscsi-test-cu -d -A --test=ALL.Prefetch16 iscsi://127.0.0.1:3260/${TARGET}/0

View File

@@ -1,5 +1,5 @@
/*
Copyright 2016 The GoStor Authors All rights reserved.
Copyright 2017 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.
@@ -148,7 +148,7 @@ type SCSIDataBuffer struct {
Buffer *bytes.Buffer
Length uint32
TransferLength uint32
Resid int32
Resid uint32
}
type SCSICommandState uint64
@@ -364,6 +364,7 @@ type ModePage struct {
PageCode uint8
// Sub page code
SubPageCode uint8
Size uint8
// Rest of mode page info
Data []byte
}
@@ -378,17 +379,18 @@ type SCSIReservation struct {
}
type SCSILu struct {
Address uint64
Size uint64
UUID uint64
Path string
BsoFlags int
BlockShift uint
ReserveID uuid.UUID
Attrs SCSILuPhyAttribute
ModePages []ModePage
Storage BackingStore
DeviceProtocol SCSIDeviceProtocol
Address uint64
Size uint64
UUID uint64
Path string
BsoFlags int
BlockShift uint
ReserveID uuid.UUID
Attrs SCSILuPhyAttribute
ModePages []ModePage
Storage BackingStore
DeviceProtocol SCSIDeviceProtocol
ModeBlockDescriptor []byte
PerformCommand CommandFunc
FinishCommand func(*SCSITarget, *SCSICommand)

View File

@@ -21,6 +21,7 @@ import (
"fmt"
"strings"
log "github.com/Sirupsen/logrus"
"github.com/gostor/gotgt/pkg/util"
)
@@ -94,6 +95,7 @@ type ISCSICommand struct {
TaskTag uint32
ExpCmdSN, MaxCmdSN uint32
AHSLen int
Resid uint32
// Connection ID.
ConnID uint16
@@ -185,7 +187,7 @@ func (m *ISCSICommand) String() string {
s = append(s, fmt.Sprintf("Next Stage = %v", m.NSG))
s = append(s, fmt.Sprintf("Status Class = %d", m.StatusClass))
s = append(s, fmt.Sprintf("Status Detail = %d", m.StatusDetail))
case OpSCSICmd, OpSCSIOut:
case OpSCSICmd, OpSCSIOut, OpSCSIIn:
s = append(s, fmt.Sprintf("LUN = %d", m.LUN))
s = append(s, fmt.Sprintf("ExpectedDataLen = %d", m.ExpectedDataLen))
s = append(s, fmt.Sprintf("CmdSN = %d", m.CmdSN))
@@ -278,7 +280,15 @@ func (m *ISCSICommand) scsiCmdRespBytes() []byte {
// rfc7143 11.4
buf := &bytes.Buffer{}
buf.WriteByte(byte(OpSCSIResp))
buf.WriteByte(0x80) // 11.4.1 = wtf
var flag byte = 0x80
if m.Resid > 0 {
if m.Resid > m.ExpectedDataLen {
flag |= 0x04
} else {
flag |= 0x02
}
}
buf.WriteByte(flag)
buf.WriteByte(byte(m.SCSIResponse))
buf.WriteByte(byte(m.Status))
@@ -295,9 +305,10 @@ func (m *ISCSICommand) scsiCmdRespBytes() []byte {
buf.Write(util.MarshalUint64(uint64(m.StatSN))[4:])
buf.Write(util.MarshalUint64(uint64(m.ExpCmdSN))[4:])
buf.Write(util.MarshalUint64(uint64(m.MaxCmdSN))[4:])
for i := 0; i < 3*4; i++ {
for i := 0; i < 2*4; i++ {
buf.WriteByte(0x00)
}
buf.Write(util.MarshalUint64(uint64(m.Resid))[4:])
buf.Write(m.RawData)
dl := len(m.RawData)
for dl%4 > 0 {
@@ -312,20 +323,27 @@ func (m *ISCSICommand) dataInBytes() []byte {
// rfc7143 11.7
buf := &bytes.Buffer{}
buf.WriteByte(byte(OpSCSIIn))
var b byte
b = 0x0
var flag byte
if m.FinalInSeq || m.Final == true {
b |= 0x80
flag |= 0x80
}
if m.HasStatus && m.Final == true {
b |= 0x01
flag |= 0x01
}
buf.WriteByte(b)
log.Debugf("resid: %v, ExpectedDataLen: %v", m.Resid, m.ExpectedDataLen)
if m.Resid > 0 {
if m.Resid > m.ExpectedDataLen {
flag |= 0x04
} else {
flag |= 0x02
}
}
buf.WriteByte(flag)
buf.WriteByte(0x00)
if m.HasStatus && m.Final == true {
b = byte(m.Status)
flag = byte(m.Status)
}
buf.WriteByte(b)
buf.WriteByte(flag)
buf.WriteByte(0x00) // 4
@@ -344,9 +362,7 @@ func (m *ISCSICommand) dataInBytes() []byte {
buf.Write(util.MarshalUint64(uint64(m.MaxCmdSN))[4:])
buf.Write(util.MarshalUint64(uint64(m.DataSN))[4:])
buf.Write(util.MarshalUint64(uint64(m.BufferOffset))[4:])
for i := 0; i < 4; i++ {
buf.WriteByte(0x00)
}
buf.Write(util.MarshalUint64(uint64(m.Resid))[4:])
buf.Write(m.RawData[m.BufferOffset : m.BufferOffset+uint32(m.DataLen)])
dl := m.DataLen
for dl%4 > 0 {

View File

@@ -155,10 +155,11 @@ func (conn *iscsiConnection) buildRespPackage(oc OpCode, task *iscsiTask) error
task = conn.rxTask
}
resp := &ISCSICommand{
StatSN: conn.req.ExpStatSN,
TaskTag: conn.req.TaskTag,
ExpCmdSN: conn.session.ExpCmdSN,
MaxCmdSN: conn.session.ExpCmdSN + conn.session.MaxQueueCommand,
StatSN: conn.req.ExpStatSN,
TaskTag: conn.req.TaskTag,
ExpCmdSN: conn.session.ExpCmdSN,
MaxCmdSN: conn.session.ExpCmdSN + conn.session.MaxQueueCommand,
ExpectedDataLen: conn.req.ExpectedDataLen,
}
switch oc {
case OpReady:
@@ -182,6 +183,7 @@ func (conn *iscsiConnection) buildRespPackage(oc OpCode, task *iscsiTask) error
resp.RawData = append(length[2:4], scmd.SenseBuffer.Bytes()...)
} else if scmd.Direction == api.SCSIDataRead || scmd.Direction == api.SCSIDataWrite {
if scmd.InSDBBuffer.Buffer != nil {
resp.Resid = scmd.InSDBBuffer.Resid
buf := scmd.InSDBBuffer.Buffer.Bytes()
resp.RawData = buf
} else {

View File

@@ -313,8 +313,7 @@ func (s *ISCSITargetDriver) rxHandler(conn *iscsiConnection) {
default:
iscsiExecReject(conn)
}
log.Debugf("connection state is %v", conn.state)
log.Debugf("%#v", conn.resp.String())
log.Debugf("connection state is %v", conn.State())
s.handler(DATAOUT, conn)
}
}
@@ -476,9 +475,7 @@ SendRemainingData:
switch conn.txIOState {
case IOSTATE_TX_BHS:
log.Debug("ready to write response")
log.Debugf("%s", resp.String())
log.Debugf("length of RawData is %d", len(resp.RawData))
log.Debugf("length of resp is %d", len(resp.Bytes()))
log.Debugf("response is %s", resp.String())
if l, err := conn.write(resp.Bytes()); err != nil {
log.Error(err)
return
@@ -678,7 +675,7 @@ func (s *ISCSITargetDriver) iscsiTaskQueueHandler(task *iscsiTask) error {
return s.iscsiExecTask(task)
}
cmdsn := cmd.CmdSN
log.Debugf("CmdSN of command is %d, ExpCmdSN of session is %d", cmdsn, sess.ExpCmdSN)
log.Debugf("CmdSN of command is %d", cmdsn)
if cmdsn == sess.ExpCmdSN {
retry:
cmdsn += 1

View File

@@ -1,10 +1,25 @@
/*
Copyright 2017 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.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package iscsit
import (
"bytes"
"fmt"
// log "github.com/Sirupsen/logrus"
"github.com/gostor/gotgt/pkg/util"
)

View File

@@ -20,6 +20,7 @@ package scsi
import (
"bytes"
"encoding/binary"
"fmt"
"unsafe"
log "github.com/Sirupsen/logrus"
@@ -67,6 +68,8 @@ func (sbc SBCSCSIDeviceProtocol) InitLu(lu *api.SCSILu) error {
lu.Attrs.VendorID = SCSIVendorID
lu.Attrs.ProductID = SCSIProductID
lu.Attrs.ProductRev = version.SCSIVersion
lu.Attrs.SCSIID = fmt.Sprintf("gotgt-scsi-%d%d", 0, lu.UUID)
lu.Attrs.SCSISN = fmt.Sprintf("gotgt-beaf-%d%d", 0, lu.UUID)
/*
SCSIID for PAGE83 T10 VENDOR IDENTIFICATION field
@@ -96,20 +99,25 @@ func (sbc SBCSCSIDeviceProtocol) InitLu(lu *api.SCSILu) error {
}
pages := []api.ModePage{}
// Vendor uniq - However most apps seem to call for mode page 0
pages = append(pages, api.ModePage{0, 0, []byte{}})
//pages = append(pages, api.ModePage{0, 0, []byte{}})
// Disconnect page
pages = append(pages, api.ModePage{2, 0, []byte{0x80, 0x80, 0, 0xa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}})
pages = append(pages, api.ModePage{2, 0, 14, []byte{0x80, 0x80, 0, 0xa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}})
// Caching Page
pages = append(pages, api.ModePage{8, 0, []byte{0x14, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}})
pages = append(pages, api.ModePage{8, 0, 18, []byte{0x14, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0, 0x4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}})
// Control page
pages = append(pages, api.ModePage{0x0a, 0, []byte{2, 0x10, 0, 0, 0, 0, 0, 0, 2, 0}})
pages = append(pages, api.ModePage{0x0a, 0, 10, []byte{2, 0x10, 0, 0, 0, 0, 0, 0, 2, 0, 0x08, 0, 0, 0, 0, 0, 0, 0}})
// Control Extensions mode page: TCMOS:1
pages = append(pages, api.ModePage{0x0a, 1, []byte{0x04, 0x00, 0x00}})
pages = append(pages, api.ModePage{0x0a, 1, 0x1c, []byte{0x04, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}})
// Informational Exceptions Control page
pages = append(pages, api.ModePage{0x1c, 0, []byte{8, 0, 0, 0, 0, 0, 0, 0, 0, 0}})
pages = append(pages, api.ModePage{0x1c, 0, 10, []byte{8, 0, 0, 0, 0, 0, 0, 0, 0, 0}})
lu.ModePages = pages
mbd := util.MarshalUint32(uint32(0xffffffff))
if size := lu.Size >> lu.BlockShift; size>>32 == 0 {
mbd = util.MarshalUint32(uint32(size))
}
lu.ModeBlockDescriptor = append(mbd, util.MarshalUint32(uint32(1<<lu.BlockShift))...)
return nil
}

View File

@@ -158,6 +158,7 @@ func BuildSenseData(cmd *api.SCSICommand, key byte, asc SCSISubError) {
}
if ok {
if int64(len(senseBuffer.Bytes())) > inBufLen {
log.Warnf("sense buffer is bigger than in buffer")
senseBuffer.Truncate(int(inBufLen))
}
} else {

View File

@@ -86,31 +86,23 @@ func InquiryPage0x00(host int, cmd *api.SCSICommand) (*bytes.Buffer, uint16) {
func InquiryPage0x80(host int, cmd *api.SCSICommand) (*bytes.Buffer, uint16) {
var (
buf = &bytes.Buffer{}
descBuf = &bytes.Buffer{}
data []byte = []byte{}
pageLength uint16 = 0
pageLength uint16 = 36
scsisn = make([]byte, pageLength)
)
descBuf.WriteByte(0x20)
descBuf.WriteByte(0x20)
descBuf.WriteByte(0x20)
descBuf.WriteByte(0x20)
data = descBuf.Bytes()
pageLength = uint16(len(data))
//byte 0
if cmd.Device.Attrs.Online {
buf.WriteByte(PQ_DEVICE_CONNECTED | byte(cmd.Device.Attrs.DeviceType))
} else {
buf.WriteByte(PQ_DEVICE_NOT_CONNECT | byte(cmd.Device.Attrs.DeviceType))
}
//byte 1
//PAGE CODE
//byte 1: PAGE CODE
buf.WriteByte(0x80)
//PAGE LENGTH
binary.Write(buf, binary.BigEndian, pageLength)
buf.Write(data)
//byte 2-3: PAGE LENGTH
buf.WriteByte(uint8(pageLength >> 8))
buf.WriteByte(uint8(pageLength & 0xff))
copy(scsisn, []byte(fmt.Sprintf("gotgt-%-36v", cmd.Device.UUID)))
buf.Write(scsisn)
return buf, pageLength
}
@@ -206,7 +198,6 @@ func InquiryPage0x83(host int, cmd *api.SCSICommand) (*bytes.Buffer, uint16) {
func SPCInquiry(host int, cmd *api.SCSICommand) api.SAMStat {
var (
allocationLength uint16
pageLength uint16
additionLength byte
buf = &bytes.Buffer{}
data []byte = []byte{}
@@ -235,24 +226,28 @@ func SPCInquiry(host int, cmd *api.SCSICommand) api.SAMStat {
if evpd {
switch pcode {
case 0x00:
buf, pageLength = InquiryPage0x00(host, cmd)
buf, _ = InquiryPage0x00(host, cmd)
case 0x80:
buf, pageLength = InquiryPage0x80(host, cmd)
buf, _ = InquiryPage0x80(host, cmd)
case 0x83:
buf, pageLength = InquiryPage0x83(host, cmd)
buf, _ = InquiryPage0x83(host, cmd)
default:
goto sense
}
data = buf.Bytes()
if allocationLength < pageLength {
if int(allocationLength) < len(data) {
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(data[0:allocationLength])
cmd.InSDBBuffer.Resid = uint32(len(data))
} else {
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(data[0:])
}
} else {
if pcode != 0 {
goto sense
}
//byte 5
//SCCS(0) AAC(0) TPGS(0) 3PC(0) PROTECT(0)
addBuf.WriteByte(INQUIRY_TPGS_IMPLICIT)
@@ -354,7 +349,7 @@ func SPCReportLuns(host int, cmd *api.SCSICommand) api.SAMStat {
// LUN list length
buf.Write(util.MarshalUint32(availLength))
cmd.InSDBBuffer.Resid = int32(actualLength)
cmd.InSDBBuffer.Resid = uint32(actualLength)
// Skip through to byte 4, Reserved
for i := 0; i < 4; i++ {
@@ -474,13 +469,17 @@ func SPCModeSense(host int, cmd *api.SCSICommand) api.SAMStat {
var (
scb = cmd.SCB.Bytes()
mode6 = (scb[0] == 0x1a)
dbd = scb[1] & 0x8 /* Disable Block Descriptors */
dbd = scb[1] & 0x8 // Disable Block Descriptors
pcode = scb[2] & 0x3f
pctrl = (scb[2] & 0xc0) >> 6
subpcode = scb[3]
blkDesctionLen = 0
key = ILLEGAL_REQUEST
asc = ASC_INVALID_FIELD_IN_CDB
data []byte
allocLen uint32
remainLen uint32
i uint32
)
if dbd == 0 {
blkDesctionLen = 8
@@ -489,11 +488,93 @@ func SPCModeSense(host int, cmd *api.SCSICommand) api.SAMStat {
asc = ASC_SAVING_PARMS_UNSUP
goto sense
}
_ = dbd
_ = pcode
_ = subpcode
_ = mode6
_ = blkDesctionLen
if mode6 {
allocLen = uint32(scb[4])
// set header
for i = 0; i < 4 && i < allocLen; i++ {
data = append(data, 0x00)
}
} else {
allocLen = uint32(util.GetUnalignedUint16(scb[7:9]))
// set header
for i = 0; i < 8 && i < allocLen; i++ {
data = append(data, 0x00)
}
}
remainLen = allocLen - uint32(len(data))
if dbd == 0 && remainLen >= 8 {
data = append(data, cmd.Device.ModeBlockDescriptor...)
}
if pcode == 0x3f {
for _, pg := range cmd.Device.ModePages {
if pg.SubPageCode == 0 {
if remainLen < 2+uint32(pg.Size) {
break
}
data = append(data, pg.PageCode)
data = append(data, pg.Size)
} else {
if remainLen < 4+uint32(pg.Size) {
break
}
data = append(data, pg.PageCode|0x40)
data = append(data, pg.SubPageCode)
data = append(data, (pg.Size>>8)&0xff)
data = append(data, pg.Size&0xff)
}
if pctrl == 1 {
data = append(data, pg.Data[pg.Size:]...)
} else {
data = append(data, pg.Data[:pg.Size]...)
}
}
} else {
var pg *api.ModePage
for _, p := range cmd.Device.ModePages {
if p.PageCode == pcode && p.SubPageCode == subpcode {
pg = &p
break
}
}
if pg == nil {
goto sense
}
if remainLen >= 2+uint32(pg.Size) {
if pg.SubPageCode == 0 {
data = append(data, pg.PageCode)
data = append(data, pg.Size)
if pctrl == 1 {
data = append(data, pg.Data[pg.Size:]...)
} else {
data = append(data, pg.Data[:pg.Size]...)
}
} else if remainLen >= 4+uint32(pg.Size) {
data = append(data, pg.PageCode|0x40)
data = append(data, pg.SubPageCode)
data = append(data, (pg.Size>>8)&0xff)
data = append(data, pg.Size&0xff)
if pctrl == 1 {
data = append(data, pg.Data[pg.Size:]...)
} else {
data = append(data, pg.Data[:pg.Size]...)
}
}
}
}
if mode6 {
data[0] = uint8(len(data) - 1)
data[3] = uint8(blkDesctionLen)
} else {
data[0] = uint8((len(data) - 2) >> 8)
data[1] = uint8(len(data) - 2)
data[6] = uint8(blkDesctionLen >> 8)
data[7] = uint8(blkDesctionLen)
}
if rlen := uint32(len(data)); rlen < allocLen {
cmd.InSDBBuffer.Resid = rlen
}
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(data)
return api.SAMStatGood
sense:
BuildSenseData(cmd, key, asc)
@@ -660,7 +741,7 @@ func SPCPRReadKeys(host int, cmd *api.SCSICommand) api.SAMStat {
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(data)
}
cmd.InSDBBuffer.Resid = int32(additionLength)
cmd.InSDBBuffer.Resid = uint32(additionLength)
return api.SAMStatGood
sense:
cmd.InSDBBuffer.Resid = 0
@@ -715,7 +796,7 @@ func SPCPRReadReservation(host int, cmd *api.SCSICommand) api.SAMStat {
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(data)
}
cmd.InSDBBuffer.Resid = int32(additionLength)
cmd.InSDBBuffer.Resid = uint32(additionLength)
return api.SAMStatGood
sense:
@@ -760,7 +841,7 @@ func SPCPRReportCapabilities(host int, cmd *api.SCSICommand) api.SAMStat {
} else {
actualLength = availLength
}
cmd.InSDBBuffer.Resid = int32(actualLength)
cmd.InSDBBuffer.Resid = uint32(actualLength)
return api.SAMStatGood
sense:
cmd.InSDBBuffer.Resid = 0
@@ -1257,7 +1338,7 @@ func SPCRequestSense(host int, cmd *api.SCSICommand) api.SAMStat {
if cmd.SenseBuffer != nil {
data.Write(cmd.SenseBuffer.Bytes()[:actualLength])
}
cmd.InSDBBuffer.Resid = int32(actualLength)
cmd.InSDBBuffer.Resid = uint32(actualLength)
cmd.InSDBBuffer.Buffer = data
// reset sense buffer in cmnd