func (c *SCSICmd) IllegalRequest() SCSIResponse {
	return c.CheckCondition(scsi.SenseIllegalRequest, scsi.AscInvalidFieldInCdb)
}
IllegalRequest is a preset response for a request that is malformed or unexpected.
package tcmu
import (
	"crypto/md5"
	"encoding/binary"
	"encoding/hex"
	"errors"
	"fmt"
	"io"
	"sync"
	"github.com/coreos/go-tcmu/scsi"
	"github.com/prometheus/common/log"
)
type SCSICmd struct {
	id        uint16
	cdb       []byte
	vecs      [][]byte
	offset    int
	vecoffset int
	device    *Device
	Buf []byte
}
func (c *SCSICmd) Command() byte {
	return c.cdb[0]
}
func (c *SCSICmd) CdbLen() int {
	opcode := c.cdb[0]
	if opcode <= 0x1f {
		return 6
	} else if opcode <= 0x5f {
		return 10
	} else if opcode == 0x7f {
		return int(c.cdb[7]) + 8
	} else if opcode >= 0x80 && opcode <= 0x9f {
		return 16
	} else if opcode >= 0xa0 && opcode <= 0xbf {
		return 12
	}
	panic(fmt.Sprintf("what opcode is %x", opcode))
}
func (c *SCSICmd) LBA() uint64 {
	order := binary.BigEndian
	switch c.CdbLen() {
	case 6:
		val6 := uint8(order.Uint16(c.cdb[2:4]))
		if val6 == 0 {
			return 256
		}
		return uint64(val6)
	case 10:
		return uint64(order.Uint32(c.cdb[2:6]))
	case 12:
		return uint64(order.Uint32(c.cdb[2:6]))
	case 16:
		return uint64(order.Uint64(c.cdb[2:10]))
	default:
		log.Errorf("What LBA has this length: %d", c.CdbLen())
		panic("unusal scsi command length")
	}
}
func (c *SCSICmd) XferLen() uint32 {
	order := binary.BigEndian
	switch c.CdbLen() {
	case 6:
		return uint32(c.cdb[4])
	case 10:
		return uint32(order.Uint16(c.cdb[7:9]))
	case 12:
		return uint32(order.Uint32(c.cdb[6:10]))
	case 16:
		return uint32(order.Uint32(c.cdb[10:14]))
	default:
		log.Errorf("What XferLen has this length: %d", c.CdbLen())
		panic("unusal scsi command length")
	}
}
func (c *SCSICmd) Write(b []byte) (n int, err error) {
	toWrite := len(b)
	boff := 0
	for toWrite != 0 {
		if c.vecoffset == len(c.vecs) {
			return boff, errors.New("out of buffer scsi cmd buffer space")
		}
		wrote := copy(c.vecs[c.vecoffset][c.offset:], b[boff:])
		boff += wrote
		toWrite -= wrote
		c.offset += wrote
		if c.offset == len(c.vecs[c.vecoffset]) {
			c.vecoffset++
			c.offset = 0
		}
	}
	return boff, nil
}
func (c *SCSICmd) Read(b []byte) (n int, err error) {
	toRead := len(b)
	boff := 0
	for toRead != 0 {
		if c.vecoffset == len(c.vecs) {
			return boff, io.EOF
		}
		read := copy(b[boff:], c.vecs[c.vecoffset][c.offset:])
		boff += read
		toRead -= read
		c.offset += read
		if c.offset == len(c.vecs[c.vecoffset]) {
			c.vecoffset++
			c.offset = 0
		}
	}
	return boff, nil
}
func (c *SCSICmd) Device() *Device {
	return c.device
}
func (c *SCSICmd) Ok() SCSIResponse {
	return SCSIResponse{
		id:     c.id,
		status: scsi.SamStatGood,
	}
}
func (c *SCSICmd) GetCDB(index int) byte {
	return c.cdb[index]
}
func (c *SCSICmd) RespondStatus(status byte) SCSIResponse {
	return SCSIResponse{
		id:     c.id,
		status: status,
	}
}
func (c *SCSICmd) RespondSenseData(status byte, sense []byte) SCSIResponse {
	return SCSIResponse{
		id:          c.id,
		status:      status,
		senseBuffer: sense,
	}
}
func (c *SCSICmd) NotHandled() SCSIResponse {
	buf := make([]byte, tcmuSenseBufferSize)
	buf[0] = 0x70  
	buf[2] = 0x5   
	buf[7] = 0xa
	buf[12] = 0x20  
	buf[13] = 0x0   
	return SCSIResponse{
		id:          c.id,
		status:      scsi.SamStatCheckCondition,
		senseBuffer: buf,
	}
}
func (c *SCSICmd) CheckCondition(key byte, asc uint16) SCSIResponse {
	buf := make([]byte, tcmuSenseBufferSize)
	buf[0] = 0x70  
	buf[2] = key
	buf[7] = 0xa
	buf[12] = byte(uint8((asc >> 8) & 0xff))
	buf[13] = byte(uint8(asc & 0xff))
	return SCSIResponse{
		id:          c.id,
		status:      scsi.SamStatCheckCondition,
		senseBuffer: buf,
	}
}
func (c *SCSICmd) MediumError() SCSIResponse {
	return c.CheckCondition(scsi.SenseMediumError, scsi.AscReadError)
}