From 681f1003b922f4a19923b48e34746ab53157ddf9 Mon Sep 17 00:00:00 2001 From: Le Zhang Date: Fri, 7 Oct 2016 23:54:08 +0800 Subject: [PATCH] bunch of bug fixes with dummy lun0 feature 1) add dummy lun0 2) fix report lun 3) fix inquiry command with correct version --- pkg/api/types.go | 4 +- pkg/scsi/lun.go | 25 ++++++-- pkg/scsi/sbc.go | 35 ++++++++---- pkg/scsi/scsi.go | 20 +++++-- pkg/scsi/scsilumap.go | 2 +- pkg/scsi/spc.go | 130 +++++++++++++++++++++++++++++++++--------- pkg/scsi/spc_test.go | 2 +- pkg/scsi/target.go | 13 +++-- pkg/util/util.go | 8 +-- 9 files changed, 180 insertions(+), 59 deletions(-) diff --git a/pkg/api/types.go b/pkg/api/types.go index 2e5338c..be5b153 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -193,6 +193,7 @@ type SCSITarget struct { LID int `json:"lid"` State SCSITargetState `json:"state"` Devices LUNMap `json:"-"` + LUN0 *SCSILu `json:"-"` ITNexus []*ITNexus `json:"itnexus"` SCSITargetDriver interface{} `json:"-"` @@ -306,6 +307,7 @@ var ( TYPE_RBC SCSIDeviceType = 0x0e TYPE_OSD SCSIDeviceType = 0x11 TYPE_NO_LUN SCSIDeviceType = 0x7f + TYPE_UNKNOWN SCSIDeviceType = 0X1f TYPE_PT SCSIDeviceType = 0xff ) @@ -338,7 +340,7 @@ type ModePage struct { type SCSILu struct { Address uint64 Size uint64 - Lun uint64 + UUID uint64 Path string BsoFlags int BlockShift uint diff --git a/pkg/scsi/lun.go b/pkg/scsi/lun.go index 4affb22..f3a46ac 100644 --- a/pkg/scsi/lun.go +++ b/pkg/scsi/lun.go @@ -27,7 +27,7 @@ import ( * path format :/absolute/file/path */ -func NewSCSILu(device_uuid uint64, path string) (*api.SCSILu, error) { +func NewSCSILu(device_uuid uint64, path string, online bool) (*api.SCSILu, error) { pathinfo := strings.SplitN(path, ":", 2) if len(pathinfo) < 2 { @@ -36,14 +36,13 @@ func NewSCSILu(device_uuid uint64, path string) (*api.SCSILu, error) { backendType := pathinfo[0] backendPath := pathinfo[1] - sbc := NewSBCDevice() + sbc := NewSBCDevice(api.TYPE_DISK) backing, err := NewBackingStore(backendType) if err != nil { return nil, err } var lu = &api.SCSILu{ - Lun: 0, PerformCommand: luPerformCommand, DeviceProtocol: sbc, Storage: backing, @@ -56,11 +55,29 @@ func NewSCSILu(device_uuid uint64, path string) (*api.SCSILu, error) { } lu.Size = backing.Size(lu) lu.DeviceProtocol.InitLu(lu) - lu.Attrs.Online = true + lu.Attrs.Online = online lu.Attrs.Lbppbe = 3 return lu, nil } +func NewLUN0() *api.SCSILu { + + sbc := NewSBCDevice(api.TYPE_UNKNOWN) + backing, _ := NewBackingStore("null") + var lu = &api.SCSILu{ + PerformCommand: luPerformCommand, + DeviceProtocol: sbc, + Storage: backing, + BlockShift: api.DefaultBlockShift, + } + + lu.Size = backing.Size(lu) + lu.DeviceProtocol.InitLu(lu) + lu.Attrs.Online = false + lu.Attrs.Lbppbe = 3 + return lu +} + func luPerformCommand(tid int, cmd *api.SCSICommand) api.SAMStat { op := int(cmd.SCB.Bytes()[0]) fn := cmd.Device.DeviceProtocol.PerformCommand(op) diff --git a/pkg/scsi/sbc.go b/pkg/scsi/sbc.go index 2c10e1d..5e64d7a 100644 --- a/pkg/scsi/sbc.go +++ b/pkg/scsi/sbc.go @@ -20,7 +20,7 @@ package scsi import ( "bytes" "encoding/binary" - "fmt" + "unsafe" "github.com/golang/glog" "github.com/gostor/gotgt/pkg/api" @@ -46,7 +46,7 @@ func (sbc SBCSCSIDeviceProtocol) PerformCommand(opcode int) interface{} { func (sbc SBCSCSIDeviceProtocol) InitLu(lu *api.SCSILu) error { // init LU's phy attribute - lu.Attrs.DeviceType = api.TYPE_DISK + lu.Attrs.DeviceType = sbc.DeviceType lu.Attrs.Qualifier = false lu.Attrs.Thinprovisioning = false lu.Attrs.Removable = false @@ -54,13 +54,25 @@ func (sbc SBCSCSIDeviceProtocol) InitLu(lu *api.SCSILu) error { lu.Attrs.SWP = false lu.Attrs.SenseFormat = false lu.Attrs.VendorID = "GOSTOR" - /* - lu.Attrs.SCSIID = fmt.Sprintf("GOSTOR %x%d", tgt.TID, lu.Lun) - lu.Attrs.SCSISN = fmt.Sprintf("beaf%d%d", tgt.TID, lu.Lun) - */ - lu.Attrs.SCSIID = fmt.Sprintf("GOSTOR%d", lu.Lun) - lu.Attrs.SCSISN = fmt.Sprintf("beaf%d", lu.Lun) lu.Attrs.ProductID = "VIRTUAL-DISK" + + /* + SCSIID for PAGE83 T10 VENDOR IDENTIFICATION field + It is going to be the iSCSI target iqn name + leave it with a default target name + */ + + lu.Attrs.SCSIID = "iqn.2016-09.com.gotgt.gostor:iscsi-tgt" + /* + The PRODUCT SERIAL NUMBER field contains + right-aligned ASCII data (see 4.3.1) + that is a vendor specific serial number. + If the product serial number is not available, + the device server shall return ASCII spaces (20h) in this field. + leave it with 4 spaces (20h) + */ + lu.Attrs.SCSISN = " " + lu.Attrs.VersionDesction = []uint16{ 0x04C0, // SBC-3 no version claimed 0x0960, // iSCSI @@ -104,10 +116,10 @@ func (sbc SBCSCSIDeviceProtocol) ExitLu(lu *api.SCSILu) error { return nil } -func NewSBCDevice() api.SCSIDeviceProtocol { +func NewSBCDevice(deviceType api.SCSIDeviceType) api.SCSIDeviceProtocol { var sbc = SBCSCSIDeviceProtocol{ BaseSCSIDeviceProtocol{ - Type: api.TYPE_DISK, + DeviceType: deviceType, SCSIDeviceOps: []SCSIDeviceOperation{}, }, } @@ -391,7 +403,8 @@ func SBCReserve(host int, cmd *api.SCSICommand) api.SAMStat { } func SBCRelease(host int, cmd *api.SCSICommand) api.SAMStat { - if err := deviceRelease(cmd.Target.TID, cmd.CommandITNID, cmd.Device.Lun, false); err != nil { + lun := *(*uint64)(unsafe.Pointer(&cmd.Lun)) + if err := deviceRelease(cmd.Target.TID, cmd.CommandITNID, lun, false); err != nil { return api.SAMStatReservationConflict } diff --git a/pkg/scsi/scsi.go b/pkg/scsi/scsi.go index 2713150..eb34df1 100644 --- a/pkg/scsi/scsi.go +++ b/pkg/scsi/scsi.go @@ -21,6 +21,7 @@ import ( "encoding/binary" "fmt" "sync" + "unsafe" "github.com/golang/glog" "github.com/gostor/gotgt/pkg/api" @@ -55,6 +56,7 @@ func (s *SCSITargetService) AddCommandQueue(tid int, scmd *api.SCSICommand) erro target *api.SCSITarget itn *api.ITNexus ) + s.mutex.RLock() for _, t := range s.Targets { if t.TID == tid { @@ -74,12 +76,20 @@ func (s *SCSITargetService) AddCommandQueue(tid int, scmd *api.SCSICommand) erro } } scmd.ITNexus = itn + lun := *(*uint64)(unsafe.Pointer(&scmd.Lun)) + scmd.Device = target.Devices[lun] - /* - * TODO: scmd.Device = target.Devices[util.GetUnalignedUint64(scmd.Lun[:])] - */ - scmd.Device = target.Devices[0] glog.V(2).Infof("scsi opcode: 0x%x, LUN: %d:", int(scmd.SCB.Bytes()[0]), binary.LittleEndian.Uint64(scmd.Lun[:])) + + if scmd.Device == nil { + scmd.Device = target.LUN0 + if lun != 0 { + BuildSenseData(scmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB) + scmd.Result = api.SAMStatCheckCondition.Stat + glog.Warningf("%v", api.SAMStatCheckCondition.Err) + return nil + } + } result := scmd.Device.PerformCommand(tid, scmd) if result != api.SAMStatGood { scmd.Result = result.Stat @@ -100,7 +110,7 @@ type SCSIDeviceOperation struct { } type BaseSCSIDeviceProtocol struct { - Type api.SCSIDeviceType + DeviceType api.SCSIDeviceType SCSIDeviceOps []SCSIDeviceOperation } diff --git a/pkg/scsi/scsilumap.go b/pkg/scsi/scsilumap.go index dba465d..dfa1ce6 100644 --- a/pkg/scsi/scsilumap.go +++ b/pkg/scsi/scsilumap.go @@ -69,7 +69,7 @@ func InitSCSILUMap(config *config.Config) error { defer globalSCSILUMap.mutex.Unlock() for _, bs := range config.Storages { - lu, err := NewSCSILu(bs.DeviceID, bs.Path) + lu, err := NewSCSILu(bs.DeviceID, bs.Path, bs.Online) if err != nil { return errors.New("Init SCSI LU map error.") } diff --git a/pkg/scsi/spc.go b/pkg/scsi/spc.go index 39eedae..16cf2f9 100644 --- a/pkg/scsi/spc.go +++ b/pkg/scsi/spc.go @@ -21,8 +21,6 @@ import ( "bytes" "encoding/binary" "fmt" - "reflect" - "unsafe" "github.com/golang/glog" "github.com/gostor/gotgt/pkg/api" @@ -55,6 +53,13 @@ const ( PIV_ATA ) +const ( + VERSION_NOT_CLAIM = byte(0x00) + VERSION_WITHDRAW_STANDARD = byte(0x03) + VERSION_WITHDRAW_SPC2 = byte(0x04) + VERSION_WITHDRAW_SPC3 = byte(0x05) +) + /* * Code Set * @@ -62,7 +67,7 @@ const ( * 2 - Designator field contains ASCII printable chars * 3 - Designaotor field contains UTF-8 */ -type CodeSet int +type CodeSet byte var ( INQ_CODE_BIN CodeSet = 1 @@ -78,7 +83,7 @@ var ( * 10b - Associated with SCSI Target device * 11b - Reserved */ -type AssociationField int +type AssociationField byte var ( ASS_LU AssociationField = 0 @@ -86,6 +91,56 @@ var ( ASS_TGT_DEV AssociationField = 0x20 ) +/* + * Table 177 — PERIPHERAL QUALIFIER field + * Qualifier Description + * 000b - A peripheral device having the indicated peripheral + * device type is connected to this logical unit. If the device server is + * unable to determine whether or not a peripheral device is connected, + * then the device server also shall use this peripheral qualifier. + * This peripheral qualifier does not indicate that the peripheral + * device connected to the logical unit is ready for access. + * 001b - A peripheral device having the indicated peripheral device type + * is not connected to this logical unit. However, the device server is capable of + * supporting the indicated peripheral device type on this logical unit. + * 010b - Reserved + * 011b - The device server is not capable of supporting a + * peripheral device on this logical unit. For this peripheral + * qualifier the peripheral device type shall be set to 1Fh. All other peripheral + * device type values are reserved for this peripheral qualifier. + * 100b to 111b Vendor specific + */ + +const ( + PQ_DEVICE_CONNECTED = byte(0x00) + PQ_DEVICE_NOT_CONNECT = byte(0x01) + PQ_RESERVED = byte(0x02) + PQ_NOT_SUPPORT = byte(0x03) +) + +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_BOTH = byte(0x30) + INQUIRY_3PC = byte(0x08) + INQUIRY_Reserved = byte(0x06) + INQUIRY_PROTECT = byte(0x01) + + INQUIRY_NORM_ACA = byte(0x20) + INQUIRY_HISUP = byte(0x10) + INQUIRY_STANDARD_FORMAT = byte(0x02) +) + +const ( + ADDRESS_METHOD_PERIPHERAL_DEVICE = byte(0x00) + ADDRESS_METHOD_FLAT_SPACE = byte(0x01) + ADDRESS_METHOD_LOGICAL_UNIT = byte(0x02) + ADDRESS_METHOD_EXTENDED_LOGICAL_UNIT = byte(0x03) +) + /* * Designator type - SPC-4 Reference * @@ -123,7 +178,7 @@ func SPCLuOffline(lu *api.SCSILu) error { func SPCLuOnline(lu *api.SCSILu) error { if luPreventRemoval(lu) { - return fmt.Errorf("lu(%s) prevent removal", lu.Lun) + return fmt.Errorf("lu prevent removal") } lu.Attrs.Online = false @@ -142,14 +197,19 @@ func SPCInquiry(host int, cmd *api.SCSICommand) api.SAMStat { if scb[1]&0x01 > 0 { evpd = true } - if reflect.DeepEqual(util.MarshalUint64(cmd.Device.Lun)[0:7], cmd.Lun[0:7]) { + + if cmd.Device == nil { b = (uint8(0) & 0x7) << 5 b |= uint8(0) & 0x1f - } - glog.V(2).Infof("%v, %v", cmd.Device.Lun, *(*uint64)(unsafe.Pointer(&cmd.Lun))) - if cmd.Device.Lun != *(*uint64)(unsafe.Pointer(&cmd.Lun)) { goto sense } + + if cmd.Device.Attrs.Online { + b = (byte(PQ_DEVICE_CONNECTED) << 5) | byte(cmd.Device.Attrs.DeviceType) + } else { + b = (byte(PQ_DEVICE_NOT_CONNECT) << 5) | byte(cmd.Device.Attrs.DeviceType) + } + if evpd { if pcode == 0x0 { buf.WriteByte(b) @@ -179,19 +239,22 @@ func SPCInquiry(host int, cmd *api.SCSICommand) api.SAMStat { } } else { buf.WriteByte(b) - b = 0 - buf.WriteByte(b) - buf.WriteByte(byte(1)) - b = 0x02 - buf.WriteByte(b) + // RMB(0) LU_CONG(0) + buf.WriteByte(0x00) + // version byte + buf.WriteByte(VERSION_WITHDRAW_SPC3) + + // Reserved, Reserved, NORMACA, HISUP, RESPONSE DATA FORMAT + buf.WriteByte(INQUIRY_HISUP | INQUIRY_STANDARD_FORMAT) + // ADDITIONAL LENGTH buf.WriteByte(0x00) // byte 5 - b = 0 - b |= byte(1) << 4 & 0x30 - buf.WriteByte(b) + /* + * SCCS(0) AAC(0) TPGS(0) 3PC(0) PROTECT(0) + */ + buf.WriteByte(0x00) // byte 6 - b = 0 - buf.WriteByte(b) + buf.WriteByte(0x00) buf.WriteByte(0x02) buf.Write([]byte{'1', '1', 'c', 'a', 'n', 's'}) buf.WriteByte(0x00) @@ -227,30 +290,43 @@ func SPCReportLuns(host int, cmd *api.SCSICommand) api.SAMStat { glog.Warningf("goto sense, allocationLength < 16") goto sense } - remainLength = allocationLength - 8 - availLength = 8 * uint32(len(cmd.Target.Devices)) + + remainLength = allocationLength + if _, ok := cmd.Target.Devices[0]; !ok { + availLength = 8 * uint32(len(cmd.Target.Devices)+1) + } else { + availLength = 8 * uint32(len(cmd.Target.Devices)) + } + + // LUN list length buf.Write(util.MarshalUint32(availLength)) cmd.InSDBBuffer.Resid = int32(actualLength) + // Skip through to byte 8, Reserved for i := 0; i < 4; i++ { buf.WriteByte(0x00) } - for lunumber, lu := range cmd.Target.Devices { - glog.V(2).Infof("LUN: ", lunumber) + //For LUN0 + if _, ok := cmd.Target.Devices[0]; !ok { + buf.Write(util.MarshalUint64(0)) + remainLength -= 8 + } + + for lun := range cmd.Target.Devices { if remainLength > 0 { - lun := lu.Lun if lun > 0xff { - lun = 0x1 << 30 + lun = (0x01 << 30) | (0x3fff&lun)<<16 } else { - lun = 0 + lun = (0x3fff & lun) << 16 } - lun = (0x3fff & lun) << 16 lun = uint64(lun << 32) + buf.Write(util.MarshalUint64(lun)) remainLength -= 8 } } + cmd.InSDBBuffer.Buffer = buf return api.SAMStatGood sense: diff --git a/pkg/scsi/spc_test.go b/pkg/scsi/spc_test.go index 8e5adae..d6779f6 100644 --- a/pkg/scsi/spc_test.go +++ b/pkg/scsi/spc_test.go @@ -33,7 +33,7 @@ func TestSPCReportLuns(t *testing.T) { cmd.Device = device lu := new(api.SCSILu) target := new(api.SCSITarget) - target.Devices = map[uint64]*api.SCSILu{lu.Lun: lu} + target.Devices = map[uint64]*api.SCSILu{0: lu} cmd.Target = target cmd.SCB = &bytes.Buffer{} cmd.SenseBuffer = &bytes.Buffer{} diff --git a/pkg/scsi/target.go b/pkg/scsi/target.go index fc0271b..06e4b49 100644 --- a/pkg/scsi/target.go +++ b/pkg/scsi/target.go @@ -18,6 +18,7 @@ package scsi import ( "fmt" + "unsafe" "github.com/golang/glog" "github.com/gostor/gotgt/pkg/api" @@ -35,20 +36,22 @@ func (s *SCSITargetService) NewSCSITarget(tid int, driverName, name string) (*ap } s.Targets = append(s.Targets, target) target.Devices = GetTargetLUNMap(target.Name) - + target.LUN0 = NewLUN0() return target, nil } func deviceReserve(cmd *api.SCSICommand) error { var lu *api.SCSILu - for _, dev := range cmd.Target.Devices { - if dev.Lun == cmd.Device.Lun { - lu = dev + lun := *(*uint64)(unsafe.Pointer(&cmd.Lun)) + + for tgtLUN, lunDev := range cmd.Target.Devices { + if tgtLUN == lun { + lu = lunDev break } } if lu == nil { - glog.Errorf("invalid target and lun %d %s", cmd.Target.TID, cmd.Device.Lun) + glog.Errorf("invalid target and lun %d %s", cmd.Target.TID, lun) return nil } diff --git a/pkg/util/util.go b/pkg/util/util.go index 78ebe24..2e56920 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -74,8 +74,8 @@ func MarshalKVText(kv []KeyValue) []byte { func MarshalUint32(i uint32) []byte { var data []byte - for j := 0; j < 4; j++ { - b := byte(i >> uint(4*(3-j)) & 0xff) + for j := 24; j >= 0; j -= 8 { + b := byte(i >> uint32(j)) data = append(data, b) } return data @@ -83,8 +83,8 @@ func MarshalUint32(i uint32) []byte { func MarshalUint64(i uint64) []byte { var data []byte - for j := 0; j < 8; j++ { - b := byte(i >> uint(8*(7-j)) & 0xff) + for j := 56; j >= 0; j -= 8 { + b := byte(i >> uint32(j)) data = append(data, b) } return data