From 547faf684d9115e6250b56897f03b73484813506 Mon Sep 17 00:00:00 2001 From: Le Zhang Date: Fri, 14 Oct 2016 16:46:34 +0800 Subject: [PATCH] iSCSI/SCSI multi port/ALUA support fix ALUA flag issue fix NNA flag issue fix fixed format sense data builder issue --- .travis.yml | 2 +- citd.go | 4 +- pkg/api/types.go | 43 ++++++++------ pkg/config/config.go | 60 ++++++++++++------- pkg/port/iscsit/cmd.go | 3 +- pkg/port/iscsit/conn.go | 1 + pkg/port/iscsit/iscsid.go | 114 +++++++++++++++++++++++++++---------- pkg/port/iscsit/iscsit.go | 29 +++++++++- pkg/port/iscsit/session.go | 2 +- pkg/port/service.go | 4 +- pkg/scsi/cmd.go | 40 +++++++++++++ pkg/scsi/sbc.go | 4 +- pkg/scsi/scsi.go | 12 ++++ pkg/scsi/scsilumap.go | 2 +- pkg/scsi/spc.go | 69 +++++++++++++--------- pkg/scsi/target.go | 29 +++++++++- pkg/util/util.go | 22 +++++++ 17 files changed, 333 insertions(+), 107 deletions(-) diff --git a/.travis.yml b/.travis.yml index e4195a6..f7b8ebf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ script: - go test -v ./pkg/... - dd if=/dev/zero of=/var/tmp/disk.img bs=1024 count=10240 - mkdir ${HOME}/.gotgt - - echo '{"storages":[{"deviceID":1000,"path":"file:/var/tmp/disk.img","online":true}],"targets":{"iqn.2016-09.com.gotgt.gostor:example_tgt_0":{"portals":["127.0.0.1"],"luns":{"0":1000}}}}' > ${HOME}/.gotgt/config.json + - echo '{"storages":[{"deviceID":1000,"path":"file:/var/tmp/disk.img","online":true}],"iscsiportals":[{"id":0,"portal":"127.0.0.1:3260"}],"iscsitargets":{"iqn.2016-09.com.gotgt.gostor:example_tgt_0":{"tpgts":{"1":[0]},"luns":{"0":1000}}}}' > ${HOME}/.gotgt/config.json - ./citd -v 4 1>/dev/null 2>&1 & # libiscsi test - mkdir ${HOME}/libiscsi diff --git a/citd.go b/citd.go index e94a287..883c36f 100644 --- a/citd.go +++ b/citd.go @@ -76,8 +76,8 @@ Help Options: os.Exit(1) } - for tgtname, tgt := range config.Targets { - targetDriver.NewTarget(tgtname, tgt.Portals) + for tgtname := range config.ISCSITargets { + targetDriver.NewTarget(tgtname, config) } runtime.GOMAXPROCS(runtime.NumCPU()) diff --git a/pkg/api/types.go b/pkg/api/types.go index 90a7acf..a8fec09 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -149,13 +149,14 @@ type SCSIDataBuffer struct { } type SCSICommand struct { - Target *SCSITarget - DeviceID uint64 - Device *SCSILu - State uint64 - Direction SCSIDataDirection - InSDBBuffer SCSIDataBuffer - OutSDBBuffer SCSIDataBuffer + Target *SCSITarget + DeviceID uint64 + Device *SCSILu + State uint64 + Direction SCSIDataDirection + InSDBBuffer SCSIDataBuffer + OutSDBBuffer SCSIDataBuffer + RelTargetPortID uint16 // Command ITN ID CommandITNID uint64 Offset uint64 @@ -187,16 +188,26 @@ type ITNexusLuInfo struct { Prevent int } -type SCSITarget struct { - Name string `json:"name"` - TID int `json:"tid"` - LID int `json:"lid"` - State SCSITargetState `json:"state"` - Devices LUNMap `json:"-"` - LUN0 *SCSILu `json:"-"` - ITNexus []*ITNexus `json:"itnexus"` +type SCSITargetPort struct { + RelativeTargetPortID uint16 + TargetPortName string +} - SCSITargetDriver interface{} `json:"-"` +type TargetPortGroup struct { + GroupID uint16 + TargetPortGroup []*SCSITargetPort `json:"targetportgroup"` +} + +type SCSITarget struct { + Name string `json:"name"` + TID int `json:"tid"` + LID int `json:"lid"` + State SCSITargetState `json:"state"` + Devices LUNMap `json:"-"` + LUN0 *SCSILu `json:"-"` + ITNexus []*ITNexus `json:"itnexus"` + TargetPortGroups []*TargetPortGroup `json:"tpg"` + SCSITargetDriver interface{} `json:"-"` } type SCSITargetDriverState int diff --git a/pkg/config/config.go b/pkg/config/config.go index 580ec37..cf9ab0a 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -34,13 +34,23 @@ Format of configuration file "deviceID": integer, uniqu device id, "path": string, :", "online": bool, online/offline - }, + } ], + + "portals": [ + { + "id": integer, uniqu portal id + "portal":string, : + } + ], + "targets": { : { - "portals": [ - - ], + "tpgts":{ + : [: } @@ -54,27 +64,29 @@ Example of the configuration file "storages": [ { "deviceID": 1000, - "path": "file:/tmp/image", - "online": true - }, - { - "deviceID": 2000, - "path": "ceph:/rbd/image", + "path": "file:/tmp/disk.img", "online": true } ], - "targets": { + "iscsiportals":[ + { + "id":0, + "portal":"192.168.159.1:3260" + } + ], + "iscsitargets": { "iqn.2016-09.com.gotgt.gostor:example_tgt_0": { - "portals": [ - "192.168.1.1" - ], + "tpgts": { + "1":[0] + } + , "luns": { "1": 1000 - "2": 2000 } } } } + */ const ( @@ -93,14 +105,20 @@ type BackendStorage struct { Online bool `json:"online"` } -type Target struct { - Portals []string `json:"portals"` - LUNs map[string]uint64 `json:"luns"` +type ISCSIPortalInfo struct { + ID uint16 `json:"id"` + Portal string `json:"portal"` +} + +type ISCSITarget struct { + TPGTs map[string][]uint64 `json:"tpgts"` + LUNs map[string]uint64 `json:"luns"` } type Config struct { - Storages []BackendStorage `json:"storages"` - Targets map[string]Target `json:"targets"` + Storages []BackendStorage `json:"storages"` + ISCSIPortals []ISCSIPortalInfo `json:"iscsiportals"` + ISCSITargets map[string]ISCSITarget `json:"iscsitargets"` } func init() { @@ -126,7 +144,7 @@ func Load(configDir string) (*Config, error) { filename := filepath.Join(configDir, ConfigFileName) config = &Config{ - Targets: make(map[string]Target), + ISCSITargets: make(map[string]ISCSITarget), } // Try happy path first - latest config file diff --git a/pkg/port/iscsit/cmd.go b/pkg/port/iscsit/cmd.go index 7ec3037..fc4a2de 100644 --- a/pkg/port/iscsit/cmd.go +++ b/pkg/port/iscsit/cmd.go @@ -272,7 +272,8 @@ func (m *ISCSICommand) dataInBytes() []byte { } buf.WriteByte(b) - buf.WriteByte(0x00) // 4 + buf.WriteByte(0x00) // 4 + buf.Write(util.MarshalUint64(uint64(len(m.RawData)))[5:]) // 5-8 // Skip through to byte 16 for i := 0; i < 8; i++ { diff --git a/pkg/port/iscsit/conn.go b/pkg/port/iscsit/conn.go index fd8ddc9..1103f08 100644 --- a/pkg/port/iscsit/conn.go +++ b/pkg/port/iscsit/conn.go @@ -61,6 +61,7 @@ type iscsiConnection struct { conn net.Conn initiator string initiatorAlias string + tpgt uint16 rxBuffer []byte txBuffer []byte diff --git a/pkg/port/iscsit/iscsid.go b/pkg/port/iscsit/iscsid.go index 5855695..615352f 100644 --- a/pkg/port/iscsit/iscsid.go +++ b/pkg/port/iscsit/iscsid.go @@ -18,21 +18,24 @@ package iscsit import ( "bytes" + "errors" "fmt" "net" "os" + "strconv" "github.com/golang/glog" "github.com/gostor/gotgt/pkg/api" + "github.com/gostor/gotgt/pkg/config" "github.com/gostor/gotgt/pkg/port" "github.com/gostor/gotgt/pkg/scsi" "github.com/gostor/gotgt/pkg/util" ) type ISCSITargetService struct { - SCSI *scsi.SCSITargetService - Name string - Targets map[string]*ISCSITarget + SCSI *scsi.SCSITargetService + Name string + iSCSITargets map[string]*ISCSITarget } func init() { @@ -41,47 +44,86 @@ func init() { func NewISCSITargetService(base *scsi.SCSITargetService) (port.SCSITargetService, error) { return &ISCSITargetService{ - Name: "iscsi", - Targets: map[string]*ISCSITarget{}, - SCSI: base, + Name: "iscsi", + iSCSITargets: map[string]*ISCSITarget{}, + SCSI: base, }, nil } -func (s *ISCSITargetService) NewTarget(target string, portals []string) (port.SCSITargetDriver, error) { - if _, ok := s.Targets[target]; ok { +func (s *ISCSITargetService) NewTarget(tgtName string, configInfo *config.Config) (port.SCSITargetDriver, error) { + if _, ok := s.iSCSITargets[tgtName]; ok { return nil, fmt.Errorf("target name has been existed") } - stgt, err := s.SCSI.NewSCSITarget(len(s.Targets), "iscsi", target) + stgt, err := s.SCSI.NewSCSITarget(len(s.iSCSITargets), "iscsi", tgtName) if err != nil { return nil, err } tgt := newISCSITarget(stgt) - s.Targets[target] = tgt - for _, portal := range portals { - s.AddNewPortal(target, portal) + s.iSCSITargets[tgtName] = tgt + scsiTPG := tgt.SCSITarget.TargetPortGroups[0] + targetConfig := configInfo.ISCSITargets[tgtName] + for tpgt, portalIDArrary := range targetConfig.TPGTs { + tpgtNumber, _ := strconv.ParseUint(tpgt, 10, 16) + tgt.TPGTs[uint16(tpgtNumber)] = &iSCSITPGT{uint16(tpgtNumber), make(map[string]struct{})} + targetPortName := fmt.Sprintf("%s,t,0x%02x", tgtName, tpgtNumber) + scsiTPG.TargetPortGroup = append(scsiTPG.TargetPortGroup, &api.SCSITargetPort{uint16(tpgtNumber), targetPortName}) + for _, portalID := range portalIDArrary { + portal := configInfo.ISCSIPortals[portalID] + s.AddiSCSIPortal(tgtName, uint16(tpgtNumber), portal.Portal) + } } return tgt, nil } -func (s *ISCSITargetService) AddNewPortal(tgtName string, portal string) error { - target := s.Targets[tgtName] - tgtPortals := target.Portals - _, ok := tgtPortals[portal] - if !ok { - tgtPortals[portal] = struct{}{} +func (s *ISCSITargetService) AddiSCSIPortal(tgtName string, tpgt uint16, portal string) error { + var ( + ok bool + errMsg string + target *ISCSITarget + tpgtInfo *iSCSITPGT + ) + + if target, ok = s.iSCSITargets[tgtName]; !ok { + errMsg = fmt.Sprintf("no target %s", tgtName) + return errors.New(errMsg) } + + if tpgtInfo, ok = target.TPGTs[tpgt]; !ok { + errMsg = fmt.Sprintf("no tpgt %d", tpgt) + return errors.New(errMsg) + } + tgtPortals := tpgtInfo.Portals + + if _, ok = tgtPortals[portal]; !ok { + tgtPortals[portal] = struct{}{} + } else { + errMsg := fmt.Sprintf("duplicate portal %s,in %s,%d", portal, tgtName, tpgt) + return errors.New(errMsg) + } + return nil } -func (s *ISCSITargetService) HasPortal(tgtName string, portal string) bool { - target := s.Targets[tgtName] - tgtPortals := target.Portals +func (s *ISCSITargetService) HasPortal(tgtName string, tpgt uint16, portal string) bool { + var ( + ok bool + target *ISCSITarget + tpgtInfo *iSCSITPGT + ) - if len(tgtPortals) == 0 { + if target, ok = s.iSCSITargets[tgtName]; !ok { + return false + } + if tpgtInfo, ok = target.TPGTs[tpgt]; !ok { + return false + } + tgtPortals := tpgtInfo.Portals + + if _, ok = tgtPortals[portal]; !ok { + return false + } else { return true } - _, ok := tgtPortals[portal] - return ok } func (s *ISCSITargetService) Run() error { @@ -254,6 +296,8 @@ func (s *ISCSITargetService) iscsiExecLogin(conn *iscsiConnection) error { var ( target *ISCSITarget cmd = conn.req + TPGT uint16 + err error ) conn.resp = &ISCSICommand{ OpCode: OpLoginResp, @@ -298,7 +342,7 @@ func (s *ISCSITargetService) iscsiExecLogin(conn *iscsiConnection) error { if conn.sessionType == SESSION_DISCOVERY { conn.tid = 0xffff } else { - for _, t := range s.Targets { + for _, t := range s.iSCSITargets { if t.SCSITarget.Name == targetName { target = t break @@ -308,7 +352,15 @@ func (s *ISCSITargetService) iscsiExecLogin(conn *iscsiConnection) error { conn.state = CONN_STATE_EXIT return fmt.Errorf("No target found with name(%s)", targetName) } + + TPGT, err = target.FindTPG(conn.conn.LocalAddr().String()) + if err != nil { + conn.state = CONN_STATE_EXIT + return err + } + conn.tpgt = TPGT conn.tid = target.TID + } switch conn.state { case CONN_STATE_FREE: @@ -361,13 +413,16 @@ func (s *ISCSITargetService) iscsiExecText(conn *iscsiConnection) error { keys := util.ParseKVText(cmd.RawData) if st, ok := keys["SendTargets"]; ok { if st == "All" { - for name, tgt := range s.Targets { + for name, tgt := range s.iSCSITargets { glog.V(2).Infof("iscsi target: %v", name) - glog.V(2).Infof("iscsi target portals: %v", tgt.Portals) + //glog.V(2).Infof("iscsi target portals: %v", tgt.Portals) result = append(result, util.KeyValue{"TargetName", name}) - for portal := range tgt.Portals { - result = append(result, util.KeyValue{"TargetAddress", portal + ",1"}) + for _, tpgt := range tgt.TPGTs { + for portal := range tpgt.Portals { + targetPort := fmt.Sprintf("%s,%d", portal, tpgt.TPGT) + result = append(result, util.KeyValue{"TargetAddress", targetPort}) + } } } } @@ -754,6 +809,7 @@ func (s *ISCSITargetService) iscsiExecTask(task *iscsiTask) error { task.scmd.SCBLength = len(cmd.CDB) task.scmd.Lun = cmd.LUN task.scmd.Tag = uint64(cmd.TaskTag) + task.scmd.RelTargetPortID = task.conn.tpgt task.state = taskSCSI if task.scmd.OutSDBBuffer.Buffer == nil { task.scmd.OutSDBBuffer.Buffer = bytes.NewBuffer(cmd.RawData) diff --git a/pkg/port/iscsit/iscsit.go b/pkg/port/iscsit/iscsit.go index a862812..acab8c7 100644 --- a/pkg/port/iscsit/iscsit.go +++ b/pkg/port/iscsit/iscsit.go @@ -17,7 +17,13 @@ limitations under the License. // iSCSI Target Driver package iscsit -import "github.com/gostor/gotgt/pkg/api" +import ( + "errors" + "fmt" + "strings" + + "github.com/gostor/gotgt/pkg/api" +) const ( IOSTATE_FREE = iota @@ -64,10 +70,15 @@ type ISCSIRedirectInfo struct { Callback string } +type iSCSITPGT struct { + TPGT uint16 /* Mapping to SCSI Reltive Target Port ID */ + Portals map[string]struct{} +} + type ISCSITarget struct { api.SCSITarget api.SCSITargetDriverCommon - Portals map[string]struct{} + TPGTs map[uint16]*iSCSITPGT Sessions []*ISCSISession SessionParam []ISCSISessionParam Alias string @@ -78,10 +89,22 @@ type ISCSITarget struct { NopCount int } +func (tgt *ISCSITarget) FindTPG(portal string) (uint16, error) { + for tpgt, TPG := range tgt.TPGTs { + for tgtPortal := range TPG.Portals { + if strings.EqualFold(portal, tgtPortal) { + return tpgt, nil + } + } + } + errMsg := fmt.Sprintf("No TPGT found with IP(%s)", portal) + return 0, errors.New(errMsg) +} + func newISCSITarget(target *api.SCSITarget) *ISCSITarget { return &ISCSITarget{ SCSITarget: *target, - Portals: make(map[string]struct{}), + TPGTs: make(map[uint16]*iSCSITPGT), } } diff --git a/pkg/port/iscsit/session.go b/pkg/port/iscsit/session.go index 8dcf891..6eaede5 100644 --- a/pkg/port/iscsit/session.go +++ b/pkg/port/iscsit/session.go @@ -221,7 +221,7 @@ func (s *ISCSITargetService) NewISCSISession(conn *iscsiConnection) (*ISCSISessi tsih uint64 ) - for _, t := range s.Targets { + for _, t := range s.iSCSITargets { if t.TID == conn.tid { target = t break diff --git a/pkg/port/service.go b/pkg/port/service.go index 77dd881..c1db9ba 100644 --- a/pkg/port/service.go +++ b/pkg/port/service.go @@ -19,13 +19,13 @@ package port import ( "fmt" + "github.com/gostor/gotgt/pkg/config" "github.com/gostor/gotgt/pkg/scsi" ) type SCSITargetService interface { Run() error - NewTarget(string, []string) (SCSITargetDriver, error) - AddNewPortal(string, string) error + NewTarget(string, *config.Config) (SCSITargetDriver, error) } type TargetServiceFunc func(*scsi.SCSITargetService) (SCSITargetService, error) diff --git a/pkg/scsi/cmd.go b/pkg/scsi/cmd.go index e50fa3a..01d417a 100644 --- a/pkg/scsi/cmd.go +++ b/pkg/scsi/cmd.go @@ -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 +} diff --git a/pkg/scsi/sbc.go b/pkg/scsi/sbc.go index a3e1257..b9a7912 100644 --- a/pkg/scsi/sbc.go +++ b/pkg/scsi/sbc.go @@ -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) diff --git a/pkg/scsi/scsi.go b/pkg/scsi/scsi.go index eb34df1..b1f79f3 100644 --- a/pkg/scsi/scsi.go +++ b/pkg/scsi/scsi.go @@ -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 } diff --git a/pkg/scsi/scsilumap.go b/pkg/scsi/scsilumap.go index dfa1ce6..534528b 100644 --- a/pkg/scsi/scsilumap.go +++ b/pkg/scsi/scsilumap.go @@ -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 { diff --git a/pkg/scsi/spc.go b/pkg/scsi/spc.go index 06fb394..9a1a08d 100644 --- a/pkg/scsi/spc.go +++ b/pkg/scsi/spc.go @@ -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) diff --git a/pkg/scsi/target.go b/pkg/scsi/target.go index 06e4b49..8128dbf 100644 --- a/pkg/scsi/target.go +++ b/pkg/scsi/target.go @@ -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)) diff --git a/pkg/util/util.go b/pkg/util/util.go index 2e56920..3f76d4e 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -90,6 +90,28 @@ func MarshalUint64(i uint64) []byte { return data } +func StringToByte(str string, align int, maxlength int) []byte { + var ( + data []byte + data2 []byte + length int + d int + ) + + data = []byte(str) + length = len(data) + d = align - (length % align) + + if (length + d) > maxlength { + data = ([]byte(str))[0:maxlength] + return data + } else { + data2 = make([]byte, length+d) + copy(data2, data) + return data2 + } +} + const ( POSIX_FADV_NORMAL = iota POSIX_FADV_RANDOM