Creation of Cybook 2416 (actually Gen4) repository
This commit is contained in:
4
include/scsi/Kbuild
Normal file
4
include/scsi/Kbuild
Normal file
@@ -0,0 +1,4 @@
|
||||
header-y += scsi.h
|
||||
|
||||
unifdef-y += scsi_ioctl.h
|
||||
unifdef-y += sg.h
|
||||
335
include/scsi/iscsi_if.h
Normal file
335
include/scsi/iscsi_if.h
Normal file
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* iSCSI User/Kernel Shares (Defines, Constants, Protocol definitions, etc)
|
||||
*
|
||||
* Copyright (C) 2005 Dmitry Yusupov
|
||||
* Copyright (C) 2005 Alex Aizman
|
||||
* maintained by open-iscsi@googlegroups.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* See the file COPYING included with this distribution for more details.
|
||||
*/
|
||||
|
||||
#ifndef ISCSI_IF_H
|
||||
#define ISCSI_IF_H
|
||||
|
||||
#include <scsi/iscsi_proto.h>
|
||||
|
||||
#define UEVENT_BASE 10
|
||||
#define KEVENT_BASE 100
|
||||
#define ISCSI_ERR_BASE 1000
|
||||
|
||||
enum iscsi_uevent_e {
|
||||
ISCSI_UEVENT_UNKNOWN = 0,
|
||||
|
||||
/* down events */
|
||||
ISCSI_UEVENT_CREATE_SESSION = UEVENT_BASE + 1,
|
||||
ISCSI_UEVENT_DESTROY_SESSION = UEVENT_BASE + 2,
|
||||
ISCSI_UEVENT_CREATE_CONN = UEVENT_BASE + 3,
|
||||
ISCSI_UEVENT_DESTROY_CONN = UEVENT_BASE + 4,
|
||||
ISCSI_UEVENT_BIND_CONN = UEVENT_BASE + 5,
|
||||
ISCSI_UEVENT_SET_PARAM = UEVENT_BASE + 6,
|
||||
ISCSI_UEVENT_START_CONN = UEVENT_BASE + 7,
|
||||
ISCSI_UEVENT_STOP_CONN = UEVENT_BASE + 8,
|
||||
ISCSI_UEVENT_SEND_PDU = UEVENT_BASE + 9,
|
||||
ISCSI_UEVENT_GET_STATS = UEVENT_BASE + 10,
|
||||
ISCSI_UEVENT_GET_PARAM = UEVENT_BASE + 11,
|
||||
|
||||
ISCSI_UEVENT_TRANSPORT_EP_CONNECT = UEVENT_BASE + 12,
|
||||
ISCSI_UEVENT_TRANSPORT_EP_POLL = UEVENT_BASE + 13,
|
||||
ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT = UEVENT_BASE + 14,
|
||||
|
||||
ISCSI_UEVENT_TGT_DSCVR = UEVENT_BASE + 15,
|
||||
|
||||
/* up events */
|
||||
ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
|
||||
ISCSI_KEVENT_CONN_ERROR = KEVENT_BASE + 2,
|
||||
ISCSI_KEVENT_IF_ERROR = KEVENT_BASE + 3,
|
||||
ISCSI_KEVENT_DESTROY_SESSION = KEVENT_BASE + 4,
|
||||
};
|
||||
|
||||
enum iscsi_tgt_dscvr {
|
||||
ISCSI_TGT_DSCVR_SEND_TARGETS = 1,
|
||||
ISCSI_TGT_DSCVR_ISNS = 2,
|
||||
ISCSI_TGT_DSCVR_SLP = 3,
|
||||
};
|
||||
|
||||
struct iscsi_uevent {
|
||||
uint32_t type; /* k/u events type */
|
||||
uint32_t iferror; /* carries interface or resource errors */
|
||||
uint64_t transport_handle;
|
||||
|
||||
union {
|
||||
/* messages u -> k */
|
||||
struct msg_create_session {
|
||||
uint32_t initial_cmdsn;
|
||||
} c_session;
|
||||
struct msg_destroy_session {
|
||||
uint32_t sid;
|
||||
} d_session;
|
||||
struct msg_create_conn {
|
||||
uint32_t sid;
|
||||
uint32_t cid;
|
||||
} c_conn;
|
||||
struct msg_bind_conn {
|
||||
uint32_t sid;
|
||||
uint32_t cid;
|
||||
uint64_t transport_eph;
|
||||
uint32_t is_leading;
|
||||
} b_conn;
|
||||
struct msg_destroy_conn {
|
||||
uint32_t sid;
|
||||
uint32_t cid;
|
||||
} d_conn;
|
||||
struct msg_send_pdu {
|
||||
uint32_t sid;
|
||||
uint32_t cid;
|
||||
uint32_t hdr_size;
|
||||
uint32_t data_size;
|
||||
} send_pdu;
|
||||
struct msg_set_param {
|
||||
uint32_t sid;
|
||||
uint32_t cid;
|
||||
uint32_t param; /* enum iscsi_param */
|
||||
uint32_t len;
|
||||
} set_param;
|
||||
struct msg_start_conn {
|
||||
uint32_t sid;
|
||||
uint32_t cid;
|
||||
} start_conn;
|
||||
struct msg_stop_conn {
|
||||
uint32_t sid;
|
||||
uint32_t cid;
|
||||
uint64_t conn_handle;
|
||||
uint32_t flag;
|
||||
} stop_conn;
|
||||
struct msg_get_stats {
|
||||
uint32_t sid;
|
||||
uint32_t cid;
|
||||
} get_stats;
|
||||
struct msg_transport_connect {
|
||||
uint32_t non_blocking;
|
||||
} ep_connect;
|
||||
struct msg_transport_poll {
|
||||
uint64_t ep_handle;
|
||||
uint32_t timeout_ms;
|
||||
} ep_poll;
|
||||
struct msg_transport_disconnect {
|
||||
uint64_t ep_handle;
|
||||
} ep_disconnect;
|
||||
struct msg_tgt_dscvr {
|
||||
enum iscsi_tgt_dscvr type;
|
||||
uint32_t host_no;
|
||||
/*
|
||||
* enable = 1 to establish a new connection
|
||||
* with the server. enable = 0 to disconnect
|
||||
* from the server. Used primarily to switch
|
||||
* from one iSNS server to another.
|
||||
*/
|
||||
uint32_t enable;
|
||||
} tgt_dscvr;
|
||||
} u;
|
||||
union {
|
||||
/* messages k -> u */
|
||||
int retcode;
|
||||
struct msg_create_session_ret {
|
||||
uint32_t sid;
|
||||
uint32_t host_no;
|
||||
} c_session_ret;
|
||||
struct msg_create_conn_ret {
|
||||
uint32_t sid;
|
||||
uint32_t cid;
|
||||
} c_conn_ret;
|
||||
struct msg_recv_req {
|
||||
uint32_t sid;
|
||||
uint32_t cid;
|
||||
uint64_t recv_handle;
|
||||
} recv_req;
|
||||
struct msg_conn_error {
|
||||
uint32_t sid;
|
||||
uint32_t cid;
|
||||
uint32_t error; /* enum iscsi_err */
|
||||
} connerror;
|
||||
struct msg_session_destroyed {
|
||||
uint32_t host_no;
|
||||
uint32_t sid;
|
||||
} d_session;
|
||||
struct msg_transport_connect_ret {
|
||||
uint64_t handle;
|
||||
} ep_connect_ret;
|
||||
} r;
|
||||
} __attribute__ ((aligned (sizeof(uint64_t))));
|
||||
|
||||
/*
|
||||
* Common error codes
|
||||
*/
|
||||
enum iscsi_err {
|
||||
ISCSI_OK = 0,
|
||||
|
||||
ISCSI_ERR_DATASN = ISCSI_ERR_BASE + 1,
|
||||
ISCSI_ERR_DATA_OFFSET = ISCSI_ERR_BASE + 2,
|
||||
ISCSI_ERR_MAX_CMDSN = ISCSI_ERR_BASE + 3,
|
||||
ISCSI_ERR_EXP_CMDSN = ISCSI_ERR_BASE + 4,
|
||||
ISCSI_ERR_BAD_OPCODE = ISCSI_ERR_BASE + 5,
|
||||
ISCSI_ERR_DATALEN = ISCSI_ERR_BASE + 6,
|
||||
ISCSI_ERR_AHSLEN = ISCSI_ERR_BASE + 7,
|
||||
ISCSI_ERR_PROTO = ISCSI_ERR_BASE + 8,
|
||||
ISCSI_ERR_LUN = ISCSI_ERR_BASE + 9,
|
||||
ISCSI_ERR_BAD_ITT = ISCSI_ERR_BASE + 10,
|
||||
ISCSI_ERR_CONN_FAILED = ISCSI_ERR_BASE + 11,
|
||||
ISCSI_ERR_R2TSN = ISCSI_ERR_BASE + 12,
|
||||
ISCSI_ERR_SESSION_FAILED = ISCSI_ERR_BASE + 13,
|
||||
ISCSI_ERR_HDR_DGST = ISCSI_ERR_BASE + 14,
|
||||
ISCSI_ERR_DATA_DGST = ISCSI_ERR_BASE + 15,
|
||||
ISCSI_ERR_PARAM_NOT_FOUND = ISCSI_ERR_BASE + 16,
|
||||
ISCSI_ERR_NO_SCSI_CMD = ISCSI_ERR_BASE + 17,
|
||||
};
|
||||
|
||||
/*
|
||||
* iSCSI Parameters (RFC3720)
|
||||
*/
|
||||
enum iscsi_param {
|
||||
/* passed in using netlink set param */
|
||||
ISCSI_PARAM_MAX_RECV_DLENGTH,
|
||||
ISCSI_PARAM_MAX_XMIT_DLENGTH,
|
||||
ISCSI_PARAM_HDRDGST_EN,
|
||||
ISCSI_PARAM_DATADGST_EN,
|
||||
ISCSI_PARAM_INITIAL_R2T_EN,
|
||||
ISCSI_PARAM_MAX_R2T,
|
||||
ISCSI_PARAM_IMM_DATA_EN,
|
||||
ISCSI_PARAM_FIRST_BURST,
|
||||
ISCSI_PARAM_MAX_BURST,
|
||||
ISCSI_PARAM_PDU_INORDER_EN,
|
||||
ISCSI_PARAM_DATASEQ_INORDER_EN,
|
||||
ISCSI_PARAM_ERL,
|
||||
ISCSI_PARAM_IFMARKER_EN,
|
||||
ISCSI_PARAM_OFMARKER_EN,
|
||||
ISCSI_PARAM_EXP_STATSN,
|
||||
ISCSI_PARAM_TARGET_NAME,
|
||||
ISCSI_PARAM_TPGT,
|
||||
ISCSI_PARAM_PERSISTENT_ADDRESS,
|
||||
ISCSI_PARAM_PERSISTENT_PORT,
|
||||
ISCSI_PARAM_SESS_RECOVERY_TMO,
|
||||
|
||||
/* pased in through bind conn using transport_fd */
|
||||
ISCSI_PARAM_CONN_PORT,
|
||||
ISCSI_PARAM_CONN_ADDRESS,
|
||||
|
||||
/* must always be last */
|
||||
ISCSI_PARAM_MAX,
|
||||
};
|
||||
|
||||
#define ISCSI_MAX_RECV_DLENGTH (1 << ISCSI_PARAM_MAX_RECV_DLENGTH)
|
||||
#define ISCSI_MAX_XMIT_DLENGTH (1 << ISCSI_PARAM_MAX_XMIT_DLENGTH)
|
||||
#define ISCSI_HDRDGST_EN (1 << ISCSI_PARAM_HDRDGST_EN)
|
||||
#define ISCSI_DATADGST_EN (1 << ISCSI_PARAM_DATADGST_EN)
|
||||
#define ISCSI_INITIAL_R2T_EN (1 << ISCSI_PARAM_INITIAL_R2T_EN)
|
||||
#define ISCSI_MAX_R2T (1 << ISCSI_PARAM_MAX_R2T)
|
||||
#define ISCSI_IMM_DATA_EN (1 << ISCSI_PARAM_IMM_DATA_EN)
|
||||
#define ISCSI_FIRST_BURST (1 << ISCSI_PARAM_FIRST_BURST)
|
||||
#define ISCSI_MAX_BURST (1 << ISCSI_PARAM_MAX_BURST)
|
||||
#define ISCSI_PDU_INORDER_EN (1 << ISCSI_PARAM_PDU_INORDER_EN)
|
||||
#define ISCSI_DATASEQ_INORDER_EN (1 << ISCSI_PARAM_DATASEQ_INORDER_EN)
|
||||
#define ISCSI_ERL (1 << ISCSI_PARAM_ERL)
|
||||
#define ISCSI_IFMARKER_EN (1 << ISCSI_PARAM_IFMARKER_EN)
|
||||
#define ISCSI_OFMARKER_EN (1 << ISCSI_PARAM_OFMARKER_EN)
|
||||
#define ISCSI_EXP_STATSN (1 << ISCSI_PARAM_EXP_STATSN)
|
||||
#define ISCSI_TARGET_NAME (1 << ISCSI_PARAM_TARGET_NAME)
|
||||
#define ISCSI_TPGT (1 << ISCSI_PARAM_TPGT)
|
||||
#define ISCSI_PERSISTENT_ADDRESS (1 << ISCSI_PARAM_PERSISTENT_ADDRESS)
|
||||
#define ISCSI_PERSISTENT_PORT (1 << ISCSI_PARAM_PERSISTENT_PORT)
|
||||
#define ISCSI_SESS_RECOVERY_TMO (1 << ISCSI_PARAM_SESS_RECOVERY_TMO)
|
||||
#define ISCSI_CONN_PORT (1 << ISCSI_PARAM_CONN_PORT)
|
||||
#define ISCSI_CONN_ADDRESS (1 << ISCSI_PARAM_CONN_ADDRESS)
|
||||
|
||||
#define iscsi_ptr(_handle) ((void*)(unsigned long)_handle)
|
||||
#define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr)
|
||||
#define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata))
|
||||
|
||||
/**
|
||||
* iscsi_hostdata - get LLD hostdata from scsi_host
|
||||
* @_hostdata: pointer to scsi host's hostdata
|
||||
**/
|
||||
#define iscsi_hostdata(_hostdata) ((void*)_hostdata + sizeof(unsigned long))
|
||||
|
||||
/*
|
||||
* These flags presents iSCSI Data-Path capabilities.
|
||||
*/
|
||||
#define CAP_RECOVERY_L0 0x1
|
||||
#define CAP_RECOVERY_L1 0x2
|
||||
#define CAP_RECOVERY_L2 0x4
|
||||
#define CAP_MULTI_R2T 0x8
|
||||
#define CAP_HDRDGST 0x10
|
||||
#define CAP_DATADGST 0x20
|
||||
#define CAP_MULTI_CONN 0x40
|
||||
#define CAP_TEXT_NEGO 0x80
|
||||
#define CAP_MARKERS 0x100
|
||||
|
||||
/*
|
||||
* These flags describes reason of stop_conn() call
|
||||
*/
|
||||
#define STOP_CONN_TERM 0x1
|
||||
#define STOP_CONN_SUSPEND 0x2
|
||||
#define STOP_CONN_RECOVER 0x3
|
||||
|
||||
#define ISCSI_STATS_CUSTOM_MAX 32
|
||||
#define ISCSI_STATS_CUSTOM_DESC_MAX 64
|
||||
struct iscsi_stats_custom {
|
||||
char desc[ISCSI_STATS_CUSTOM_DESC_MAX];
|
||||
uint64_t value;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct iscsi_stats - iSCSI Statistics (iSCSI MIB)
|
||||
*
|
||||
* Note: this structure contains counters collected on per-connection basis.
|
||||
*/
|
||||
struct iscsi_stats {
|
||||
/* octets */
|
||||
uint64_t txdata_octets;
|
||||
uint64_t rxdata_octets;
|
||||
|
||||
/* xmit pdus */
|
||||
uint32_t noptx_pdus;
|
||||
uint32_t scsicmd_pdus;
|
||||
uint32_t tmfcmd_pdus;
|
||||
uint32_t login_pdus;
|
||||
uint32_t text_pdus;
|
||||
uint32_t dataout_pdus;
|
||||
uint32_t logout_pdus;
|
||||
uint32_t snack_pdus;
|
||||
|
||||
/* recv pdus */
|
||||
uint32_t noprx_pdus;
|
||||
uint32_t scsirsp_pdus;
|
||||
uint32_t tmfrsp_pdus;
|
||||
uint32_t textrsp_pdus;
|
||||
uint32_t datain_pdus;
|
||||
uint32_t logoutrsp_pdus;
|
||||
uint32_t r2t_pdus;
|
||||
uint32_t async_pdus;
|
||||
uint32_t rjt_pdus;
|
||||
|
||||
/* errors */
|
||||
uint32_t digest_err;
|
||||
uint32_t timeout_err;
|
||||
|
||||
/*
|
||||
* iSCSI Custom Statistics support, i.e. Transport could
|
||||
* extend existing MIB statistics with its own specific statistics
|
||||
* up to ISCSI_STATS_CUSTOM_MAX
|
||||
*/
|
||||
uint32_t custom_length;
|
||||
struct iscsi_stats_custom custom[0]
|
||||
__attribute__ ((aligned (sizeof(uint64_t))));
|
||||
};
|
||||
|
||||
#endif
|
||||
595
include/scsi/iscsi_proto.h
Normal file
595
include/scsi/iscsi_proto.h
Normal file
@@ -0,0 +1,595 @@
|
||||
/*
|
||||
* RFC 3720 (iSCSI) protocol data types
|
||||
*
|
||||
* Copyright (C) 2005 Dmitry Yusupov
|
||||
* Copyright (C) 2005 Alex Aizman
|
||||
* maintained by open-iscsi@googlegroups.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* See the file COPYING included with this distribution for more details.
|
||||
*/
|
||||
|
||||
#ifndef ISCSI_PROTO_H
|
||||
#define ISCSI_PROTO_H
|
||||
|
||||
#define ISCSI_DRAFT20_VERSION 0x00
|
||||
|
||||
/* default iSCSI listen port for incoming connections */
|
||||
#define ISCSI_LISTEN_PORT 3260
|
||||
|
||||
/* Padding word length */
|
||||
#define PAD_WORD_LEN 4
|
||||
|
||||
/*
|
||||
* useful common(control and data pathes) macro
|
||||
*/
|
||||
#define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2]))
|
||||
#define hton24(p, v) { \
|
||||
p[0] = (((v) >> 16) & 0xFF); \
|
||||
p[1] = (((v) >> 8) & 0xFF); \
|
||||
p[2] = ((v) & 0xFF); \
|
||||
}
|
||||
#define zero_data(p) {p[0]=0;p[1]=0;p[2]=0;}
|
||||
|
||||
/* initiator tags; opaque for target */
|
||||
typedef uint32_t __bitwise__ itt_t;
|
||||
/* below makes sense only for initiator that created this tag */
|
||||
#define build_itt(itt, id, age) ((__force itt_t)\
|
||||
((itt) | ((id) << ISCSI_CID_SHIFT) | ((age) << ISCSI_AGE_SHIFT)))
|
||||
#define get_itt(itt) ((__force uint32_t)(itt_t)(itt) & ISCSI_ITT_MASK)
|
||||
#define RESERVED_ITT ((__force itt_t)0xffffffff)
|
||||
|
||||
/*
|
||||
* iSCSI Template Message Header
|
||||
*/
|
||||
struct iscsi_hdr {
|
||||
uint8_t opcode;
|
||||
uint8_t flags; /* Final bit */
|
||||
uint8_t rsvd2[2];
|
||||
uint8_t hlength; /* AHSs total length */
|
||||
uint8_t dlength[3]; /* Data length */
|
||||
uint8_t lun[8];
|
||||
itt_t itt; /* Initiator Task Tag, opaque for target */
|
||||
__be32 ttt; /* Target Task Tag */
|
||||
__be32 statsn;
|
||||
__be32 exp_statsn;
|
||||
__be32 max_statsn;
|
||||
uint8_t other[12];
|
||||
};
|
||||
|
||||
/************************* RFC 3720 Begin *****************************/
|
||||
|
||||
#define ISCSI_RESERVED_TAG 0xffffffff
|
||||
|
||||
/* Opcode encoding bits */
|
||||
#define ISCSI_OP_RETRY 0x80
|
||||
#define ISCSI_OP_IMMEDIATE 0x40
|
||||
#define ISCSI_OPCODE_MASK 0x3F
|
||||
|
||||
/* Initiator Opcode values */
|
||||
#define ISCSI_OP_NOOP_OUT 0x00
|
||||
#define ISCSI_OP_SCSI_CMD 0x01
|
||||
#define ISCSI_OP_SCSI_TMFUNC 0x02
|
||||
#define ISCSI_OP_LOGIN 0x03
|
||||
#define ISCSI_OP_TEXT 0x04
|
||||
#define ISCSI_OP_SCSI_DATA_OUT 0x05
|
||||
#define ISCSI_OP_LOGOUT 0x06
|
||||
#define ISCSI_OP_SNACK 0x10
|
||||
|
||||
#define ISCSI_OP_VENDOR1_CMD 0x1c
|
||||
#define ISCSI_OP_VENDOR2_CMD 0x1d
|
||||
#define ISCSI_OP_VENDOR3_CMD 0x1e
|
||||
#define ISCSI_OP_VENDOR4_CMD 0x1f
|
||||
|
||||
/* Target Opcode values */
|
||||
#define ISCSI_OP_NOOP_IN 0x20
|
||||
#define ISCSI_OP_SCSI_CMD_RSP 0x21
|
||||
#define ISCSI_OP_SCSI_TMFUNC_RSP 0x22
|
||||
#define ISCSI_OP_LOGIN_RSP 0x23
|
||||
#define ISCSI_OP_TEXT_RSP 0x24
|
||||
#define ISCSI_OP_SCSI_DATA_IN 0x25
|
||||
#define ISCSI_OP_LOGOUT_RSP 0x26
|
||||
#define ISCSI_OP_R2T 0x31
|
||||
#define ISCSI_OP_ASYNC_EVENT 0x32
|
||||
#define ISCSI_OP_REJECT 0x3f
|
||||
|
||||
struct iscsi_ahs_hdr {
|
||||
__be16 ahslength;
|
||||
uint8_t ahstype;
|
||||
uint8_t ahspec[5];
|
||||
};
|
||||
|
||||
#define ISCSI_AHSTYPE_CDB 1
|
||||
#define ISCSI_AHSTYPE_RLENGTH 2
|
||||
|
||||
/* iSCSI PDU Header */
|
||||
struct iscsi_cmd {
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
__be16 rsvd2;
|
||||
uint8_t hlength;
|
||||
uint8_t dlength[3];
|
||||
uint8_t lun[8];
|
||||
itt_t itt; /* Initiator Task Tag */
|
||||
__be32 data_length;
|
||||
__be32 cmdsn;
|
||||
__be32 exp_statsn;
|
||||
uint8_t cdb[16]; /* SCSI Command Block */
|
||||
/* Additional Data (Command Dependent) */
|
||||
};
|
||||
|
||||
/* Command PDU flags */
|
||||
#define ISCSI_FLAG_CMD_FINAL 0x80
|
||||
#define ISCSI_FLAG_CMD_READ 0x40
|
||||
#define ISCSI_FLAG_CMD_WRITE 0x20
|
||||
#define ISCSI_FLAG_CMD_ATTR_MASK 0x07 /* 3 bits */
|
||||
|
||||
/* SCSI Command Attribute values */
|
||||
#define ISCSI_ATTR_UNTAGGED 0
|
||||
#define ISCSI_ATTR_SIMPLE 1
|
||||
#define ISCSI_ATTR_ORDERED 2
|
||||
#define ISCSI_ATTR_HEAD_OF_QUEUE 3
|
||||
#define ISCSI_ATTR_ACA 4
|
||||
|
||||
struct iscsi_rlength_ahdr {
|
||||
__be16 ahslength;
|
||||
uint8_t ahstype;
|
||||
uint8_t reserved;
|
||||
__be32 read_length;
|
||||
};
|
||||
|
||||
/* SCSI Response Header */
|
||||
struct iscsi_cmd_rsp {
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t response;
|
||||
uint8_t cmd_status;
|
||||
uint8_t hlength;
|
||||
uint8_t dlength[3];
|
||||
uint8_t rsvd[8];
|
||||
itt_t itt; /* Initiator Task Tag */
|
||||
__be32 rsvd1;
|
||||
__be32 statsn;
|
||||
__be32 exp_cmdsn;
|
||||
__be32 max_cmdsn;
|
||||
__be32 exp_datasn;
|
||||
__be32 bi_residual_count;
|
||||
__be32 residual_count;
|
||||
/* Response or Sense Data (optional) */
|
||||
};
|
||||
|
||||
/* Command Response PDU flags */
|
||||
#define ISCSI_FLAG_CMD_BIDI_OVERFLOW 0x10
|
||||
#define ISCSI_FLAG_CMD_BIDI_UNDERFLOW 0x08
|
||||
#define ISCSI_FLAG_CMD_OVERFLOW 0x04
|
||||
#define ISCSI_FLAG_CMD_UNDERFLOW 0x02
|
||||
|
||||
/* iSCSI Status values. Valid if Rsp Selector bit is not set */
|
||||
#define ISCSI_STATUS_CMD_COMPLETED 0
|
||||
#define ISCSI_STATUS_TARGET_FAILURE 1
|
||||
#define ISCSI_STATUS_SUBSYS_FAILURE 2
|
||||
|
||||
/* Asynchronous Event Header */
|
||||
struct iscsi_async {
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t rsvd2[2];
|
||||
uint8_t rsvd3;
|
||||
uint8_t dlength[3];
|
||||
uint8_t lun[8];
|
||||
uint8_t rsvd4[8];
|
||||
__be32 statsn;
|
||||
__be32 exp_cmdsn;
|
||||
__be32 max_cmdsn;
|
||||
uint8_t async_event;
|
||||
uint8_t async_vcode;
|
||||
__be16 param1;
|
||||
__be16 param2;
|
||||
__be16 param3;
|
||||
uint8_t rsvd5[4];
|
||||
};
|
||||
|
||||
/* iSCSI Event Codes */
|
||||
#define ISCSI_ASYNC_MSG_SCSI_EVENT 0
|
||||
#define ISCSI_ASYNC_MSG_REQUEST_LOGOUT 1
|
||||
#define ISCSI_ASYNC_MSG_DROPPING_CONNECTION 2
|
||||
#define ISCSI_ASYNC_MSG_DROPPING_ALL_CONNECTIONS 3
|
||||
#define ISCSI_ASYNC_MSG_PARAM_NEGOTIATION 4
|
||||
#define ISCSI_ASYNC_MSG_VENDOR_SPECIFIC 255
|
||||
|
||||
/* NOP-Out Message */
|
||||
struct iscsi_nopout {
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
__be16 rsvd2;
|
||||
uint8_t rsvd3;
|
||||
uint8_t dlength[3];
|
||||
uint8_t lun[8];
|
||||
itt_t itt; /* Initiator Task Tag */
|
||||
__be32 ttt; /* Target Transfer Tag */
|
||||
__be32 cmdsn;
|
||||
__be32 exp_statsn;
|
||||
uint8_t rsvd4[16];
|
||||
};
|
||||
|
||||
/* NOP-In Message */
|
||||
struct iscsi_nopin {
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
__be16 rsvd2;
|
||||
uint8_t rsvd3;
|
||||
uint8_t dlength[3];
|
||||
uint8_t lun[8];
|
||||
itt_t itt; /* Initiator Task Tag */
|
||||
__be32 ttt; /* Target Transfer Tag */
|
||||
__be32 statsn;
|
||||
__be32 exp_cmdsn;
|
||||
__be32 max_cmdsn;
|
||||
uint8_t rsvd4[12];
|
||||
};
|
||||
|
||||
/* SCSI Task Management Message Header */
|
||||
struct iscsi_tm {
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t rsvd1[2];
|
||||
uint8_t hlength;
|
||||
uint8_t dlength[3];
|
||||
uint8_t lun[8];
|
||||
itt_t itt; /* Initiator Task Tag */
|
||||
itt_t rtt; /* Reference Task Tag */
|
||||
__be32 cmdsn;
|
||||
__be32 exp_statsn;
|
||||
__be32 refcmdsn;
|
||||
__be32 exp_datasn;
|
||||
uint8_t rsvd2[8];
|
||||
};
|
||||
|
||||
#define ISCSI_FLAG_TM_FUNC_MASK 0x7F
|
||||
|
||||
/* Function values */
|
||||
#define ISCSI_TM_FUNC_ABORT_TASK 1
|
||||
#define ISCSI_TM_FUNC_ABORT_TASK_SET 2
|
||||
#define ISCSI_TM_FUNC_CLEAR_ACA 3
|
||||
#define ISCSI_TM_FUNC_CLEAR_TASK_SET 4
|
||||
#define ISCSI_TM_FUNC_LOGICAL_UNIT_RESET 5
|
||||
#define ISCSI_TM_FUNC_TARGET_WARM_RESET 6
|
||||
#define ISCSI_TM_FUNC_TARGET_COLD_RESET 7
|
||||
#define ISCSI_TM_FUNC_TASK_REASSIGN 8
|
||||
|
||||
/* SCSI Task Management Response Header */
|
||||
struct iscsi_tm_rsp {
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t response; /* see Response values below */
|
||||
uint8_t qualifier;
|
||||
uint8_t hlength;
|
||||
uint8_t dlength[3];
|
||||
uint8_t rsvd2[8];
|
||||
itt_t itt; /* Initiator Task Tag */
|
||||
itt_t rtt; /* Reference Task Tag */
|
||||
__be32 statsn;
|
||||
__be32 exp_cmdsn;
|
||||
__be32 max_cmdsn;
|
||||
uint8_t rsvd3[12];
|
||||
};
|
||||
|
||||
/* Response values */
|
||||
#define ISCSI_TMF_RSP_COMPLETE 0x00
|
||||
#define ISCSI_TMF_RSP_NO_TASK 0x01
|
||||
#define ISCSI_TMF_RSP_NO_LUN 0x02
|
||||
#define ISCSI_TMF_RSP_TASK_ALLEGIANT 0x03
|
||||
#define ISCSI_TMF_RSP_NO_FAILOVER 0x04
|
||||
#define ISCSI_TMF_RSP_NOT_SUPPORTED 0x05
|
||||
#define ISCSI_TMF_RSP_AUTH_FAILED 0x06
|
||||
#define ISCSI_TMF_RSP_REJECTED 0xff
|
||||
|
||||
/* Ready To Transfer Header */
|
||||
struct iscsi_r2t_rsp {
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t rsvd2[2];
|
||||
uint8_t hlength;
|
||||
uint8_t dlength[3];
|
||||
uint8_t lun[8];
|
||||
itt_t itt; /* Initiator Task Tag */
|
||||
__be32 ttt; /* Target Transfer Tag */
|
||||
__be32 statsn;
|
||||
__be32 exp_cmdsn;
|
||||
__be32 max_cmdsn;
|
||||
__be32 r2tsn;
|
||||
__be32 data_offset;
|
||||
__be32 data_length;
|
||||
};
|
||||
|
||||
/* SCSI Data Hdr */
|
||||
struct iscsi_data {
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t rsvd2[2];
|
||||
uint8_t rsvd3;
|
||||
uint8_t dlength[3];
|
||||
uint8_t lun[8];
|
||||
itt_t itt;
|
||||
__be32 ttt;
|
||||
__be32 rsvd4;
|
||||
__be32 exp_statsn;
|
||||
__be32 rsvd5;
|
||||
__be32 datasn;
|
||||
__be32 offset;
|
||||
__be32 rsvd6;
|
||||
/* Payload */
|
||||
};
|
||||
|
||||
/* SCSI Data Response Hdr */
|
||||
struct iscsi_data_rsp {
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t rsvd2;
|
||||
uint8_t cmd_status;
|
||||
uint8_t hlength;
|
||||
uint8_t dlength[3];
|
||||
uint8_t lun[8];
|
||||
itt_t itt;
|
||||
__be32 ttt;
|
||||
__be32 statsn;
|
||||
__be32 exp_cmdsn;
|
||||
__be32 max_cmdsn;
|
||||
__be32 datasn;
|
||||
__be32 offset;
|
||||
__be32 residual_count;
|
||||
};
|
||||
|
||||
/* Data Response PDU flags */
|
||||
#define ISCSI_FLAG_DATA_ACK 0x40
|
||||
#define ISCSI_FLAG_DATA_OVERFLOW 0x04
|
||||
#define ISCSI_FLAG_DATA_UNDERFLOW 0x02
|
||||
#define ISCSI_FLAG_DATA_STATUS 0x01
|
||||
|
||||
/* Text Header */
|
||||
struct iscsi_text {
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t rsvd2[2];
|
||||
uint8_t hlength;
|
||||
uint8_t dlength[3];
|
||||
uint8_t rsvd4[8];
|
||||
itt_t itt;
|
||||
__be32 ttt;
|
||||
__be32 cmdsn;
|
||||
__be32 exp_statsn;
|
||||
uint8_t rsvd5[16];
|
||||
/* Text - key=value pairs */
|
||||
};
|
||||
|
||||
#define ISCSI_FLAG_TEXT_CONTINUE 0x40
|
||||
|
||||
/* Text Response Header */
|
||||
struct iscsi_text_rsp {
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t rsvd2[2];
|
||||
uint8_t hlength;
|
||||
uint8_t dlength[3];
|
||||
uint8_t rsvd4[8];
|
||||
itt_t itt;
|
||||
__be32 ttt;
|
||||
__be32 statsn;
|
||||
__be32 exp_cmdsn;
|
||||
__be32 max_cmdsn;
|
||||
uint8_t rsvd5[12];
|
||||
/* Text Response - key:value pairs */
|
||||
};
|
||||
|
||||
/* Login Header */
|
||||
struct iscsi_login {
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t max_version; /* Max. version supported */
|
||||
uint8_t min_version; /* Min. version supported */
|
||||
uint8_t hlength;
|
||||
uint8_t dlength[3];
|
||||
uint8_t isid[6]; /* Initiator Session ID */
|
||||
__be16 tsih; /* Target Session Handle */
|
||||
itt_t itt; /* Initiator Task Tag */
|
||||
__be16 cid;
|
||||
__be16 rsvd3;
|
||||
__be32 cmdsn;
|
||||
__be32 exp_statsn;
|
||||
uint8_t rsvd5[16];
|
||||
};
|
||||
|
||||
/* Login PDU flags */
|
||||
#define ISCSI_FLAG_LOGIN_TRANSIT 0x80
|
||||
#define ISCSI_FLAG_LOGIN_CONTINUE 0x40
|
||||
#define ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK 0x0C /* 2 bits */
|
||||
#define ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK 0x03 /* 2 bits */
|
||||
|
||||
#define ISCSI_LOGIN_CURRENT_STAGE(flags) \
|
||||
((flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2)
|
||||
#define ISCSI_LOGIN_NEXT_STAGE(flags) \
|
||||
(flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK)
|
||||
|
||||
/* Login Response Header */
|
||||
struct iscsi_login_rsp {
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t max_version; /* Max. version supported */
|
||||
uint8_t active_version; /* Active version */
|
||||
uint8_t hlength;
|
||||
uint8_t dlength[3];
|
||||
uint8_t isid[6]; /* Initiator Session ID */
|
||||
__be16 tsih; /* Target Session Handle */
|
||||
itt_t itt; /* Initiator Task Tag */
|
||||
__be32 rsvd3;
|
||||
__be32 statsn;
|
||||
__be32 exp_cmdsn;
|
||||
__be32 max_cmdsn;
|
||||
uint8_t status_class; /* see Login RSP ststus classes below */
|
||||
uint8_t status_detail; /* see Login RSP Status details below */
|
||||
uint8_t rsvd4[10];
|
||||
};
|
||||
|
||||
/* Login stage (phase) codes for CSG, NSG */
|
||||
#define ISCSI_INITIAL_LOGIN_STAGE -1
|
||||
#define ISCSI_SECURITY_NEGOTIATION_STAGE 0
|
||||
#define ISCSI_OP_PARMS_NEGOTIATION_STAGE 1
|
||||
#define ISCSI_FULL_FEATURE_PHASE 3
|
||||
|
||||
/* Login Status response classes */
|
||||
#define ISCSI_STATUS_CLS_SUCCESS 0x00
|
||||
#define ISCSI_STATUS_CLS_REDIRECT 0x01
|
||||
#define ISCSI_STATUS_CLS_INITIATOR_ERR 0x02
|
||||
#define ISCSI_STATUS_CLS_TARGET_ERR 0x03
|
||||
|
||||
/* Login Status response detail codes */
|
||||
/* Class-0 (Success) */
|
||||
#define ISCSI_LOGIN_STATUS_ACCEPT 0x00
|
||||
|
||||
/* Class-1 (Redirection) */
|
||||
#define ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP 0x01
|
||||
#define ISCSI_LOGIN_STATUS_TGT_MOVED_PERM 0x02
|
||||
|
||||
/* Class-2 (Initiator Error) */
|
||||
#define ISCSI_LOGIN_STATUS_INIT_ERR 0x00
|
||||
#define ISCSI_LOGIN_STATUS_AUTH_FAILED 0x01
|
||||
#define ISCSI_LOGIN_STATUS_TGT_FORBIDDEN 0x02
|
||||
#define ISCSI_LOGIN_STATUS_TGT_NOT_FOUND 0x03
|
||||
#define ISCSI_LOGIN_STATUS_TGT_REMOVED 0x04
|
||||
#define ISCSI_LOGIN_STATUS_NO_VERSION 0x05
|
||||
#define ISCSI_LOGIN_STATUS_ISID_ERROR 0x06
|
||||
#define ISCSI_LOGIN_STATUS_MISSING_FIELDS 0x07
|
||||
#define ISCSI_LOGIN_STATUS_CONN_ADD_FAILED 0x08
|
||||
#define ISCSI_LOGIN_STATUS_NO_SESSION_TYPE 0x09
|
||||
#define ISCSI_LOGIN_STATUS_NO_SESSION 0x0a
|
||||
#define ISCSI_LOGIN_STATUS_INVALID_REQUEST 0x0b
|
||||
|
||||
/* Class-3 (Target Error) */
|
||||
#define ISCSI_LOGIN_STATUS_TARGET_ERROR 0x00
|
||||
#define ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE 0x01
|
||||
#define ISCSI_LOGIN_STATUS_NO_RESOURCES 0x02
|
||||
|
||||
/* Logout Header */
|
||||
struct iscsi_logout {
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t rsvd1[2];
|
||||
uint8_t hlength;
|
||||
uint8_t dlength[3];
|
||||
uint8_t rsvd2[8];
|
||||
itt_t itt; /* Initiator Task Tag */
|
||||
__be16 cid;
|
||||
uint8_t rsvd3[2];
|
||||
__be32 cmdsn;
|
||||
__be32 exp_statsn;
|
||||
uint8_t rsvd4[16];
|
||||
};
|
||||
|
||||
/* Logout PDU flags */
|
||||
#define ISCSI_FLAG_LOGOUT_REASON_MASK 0x7F
|
||||
|
||||
/* logout reason_code values */
|
||||
|
||||
#define ISCSI_LOGOUT_REASON_CLOSE_SESSION 0
|
||||
#define ISCSI_LOGOUT_REASON_CLOSE_CONNECTION 1
|
||||
#define ISCSI_LOGOUT_REASON_RECOVERY 2
|
||||
#define ISCSI_LOGOUT_REASON_AEN_REQUEST 3
|
||||
|
||||
/* Logout Response Header */
|
||||
struct iscsi_logout_rsp {
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t response; /* see Logout response values below */
|
||||
uint8_t rsvd2;
|
||||
uint8_t hlength;
|
||||
uint8_t dlength[3];
|
||||
uint8_t rsvd3[8];
|
||||
itt_t itt; /* Initiator Task Tag */
|
||||
__be32 rsvd4;
|
||||
__be32 statsn;
|
||||
__be32 exp_cmdsn;
|
||||
__be32 max_cmdsn;
|
||||
__be32 rsvd5;
|
||||
__be16 t2wait;
|
||||
__be16 t2retain;
|
||||
__be32 rsvd6;
|
||||
};
|
||||
|
||||
/* logout response status values */
|
||||
|
||||
#define ISCSI_LOGOUT_SUCCESS 0
|
||||
#define ISCSI_LOGOUT_CID_NOT_FOUND 1
|
||||
#define ISCSI_LOGOUT_RECOVERY_UNSUPPORTED 2
|
||||
#define ISCSI_LOGOUT_CLEANUP_FAILED 3
|
||||
|
||||
/* SNACK Header */
|
||||
struct iscsi_snack {
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t rsvd2[14];
|
||||
itt_t itt;
|
||||
__be32 begrun;
|
||||
__be32 runlength;
|
||||
__be32 exp_statsn;
|
||||
__be32 rsvd3;
|
||||
__be32 exp_datasn;
|
||||
uint8_t rsvd6[8];
|
||||
};
|
||||
|
||||
/* SNACK PDU flags */
|
||||
#define ISCSI_FLAG_SNACK_TYPE_MASK 0x0F /* 4 bits */
|
||||
|
||||
/* Reject Message Header */
|
||||
struct iscsi_reject {
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t reason;
|
||||
uint8_t rsvd2;
|
||||
uint8_t hlength;
|
||||
uint8_t dlength[3];
|
||||
uint8_t rsvd3[8];
|
||||
__be32 ffffffff;
|
||||
uint8_t rsvd4[4];
|
||||
__be32 statsn;
|
||||
__be32 exp_cmdsn;
|
||||
__be32 max_cmdsn;
|
||||
__be32 datasn;
|
||||
uint8_t rsvd5[8];
|
||||
/* Text - Rejected hdr */
|
||||
};
|
||||
|
||||
/* Reason for Reject */
|
||||
#define ISCSI_REASON_CMD_BEFORE_LOGIN 1
|
||||
#define ISCSI_REASON_DATA_DIGEST_ERROR 2
|
||||
#define ISCSI_REASON_DATA_SNACK_REJECT 3
|
||||
#define ISCSI_REASON_PROTOCOL_ERROR 4
|
||||
#define ISCSI_REASON_CMD_NOT_SUPPORTED 5
|
||||
#define ISCSI_REASON_IMM_CMD_REJECT 6
|
||||
#define ISCSI_REASON_TASK_IN_PROGRESS 7
|
||||
#define ISCSI_REASON_INVALID_SNACK 8
|
||||
#define ISCSI_REASON_BOOKMARK_INVALID 9
|
||||
#define ISCSI_REASON_BOOKMARK_NO_RESOURCES 10
|
||||
#define ISCSI_REASON_NEGOTIATION_RESET 11
|
||||
|
||||
/* Max. number of Key=Value pairs in a text message */
|
||||
#define MAX_KEY_VALUE_PAIRS 8192
|
||||
|
||||
/* maximum length for text keys/values */
|
||||
#define KEY_MAXLEN 64
|
||||
#define VALUE_MAXLEN 255
|
||||
#define TARGET_NAME_MAXLEN VALUE_MAXLEN
|
||||
|
||||
#define DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH 8192
|
||||
|
||||
/************************* RFC 3720 End *****************************/
|
||||
|
||||
#endif /* ISCSI_PROTO_H */
|
||||
311
include/scsi/libiscsi.h
Normal file
311
include/scsi/libiscsi.h
Normal file
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* iSCSI lib definitions
|
||||
*
|
||||
* Copyright (C) 2006 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 - 2006 Mike Christie
|
||||
* Copyright (C) 2004 - 2005 Dmitry Yusupov
|
||||
* Copyright (C) 2004 - 2005 Alex Aizman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef LIBISCSI_H
|
||||
#define LIBISCSI_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <scsi/iscsi_proto.h>
|
||||
#include <scsi/iscsi_if.h>
|
||||
|
||||
struct scsi_transport_template;
|
||||
struct scsi_device;
|
||||
struct Scsi_Host;
|
||||
struct scsi_cmnd;
|
||||
struct socket;
|
||||
struct iscsi_transport;
|
||||
struct iscsi_cls_session;
|
||||
struct iscsi_cls_conn;
|
||||
struct iscsi_session;
|
||||
struct iscsi_nopin;
|
||||
|
||||
/* #define DEBUG_SCSI */
|
||||
#ifdef DEBUG_SCSI
|
||||
#define debug_scsi(fmt...) printk(KERN_INFO "iscsi: " fmt)
|
||||
#else
|
||||
#define debug_scsi(fmt...)
|
||||
#endif
|
||||
|
||||
#define ISCSI_XMIT_CMDS_MAX 128 /* must be power of 2 */
|
||||
#define ISCSI_MGMT_CMDS_MAX 32 /* must be power of 2 */
|
||||
#define ISCSI_CONN_MAX 1
|
||||
|
||||
#define ISCSI_MGMT_ITT_OFFSET 0xa00
|
||||
|
||||
#define ISCSI_DEF_CMD_PER_LUN 32
|
||||
#define ISCSI_MAX_CMD_PER_LUN 128
|
||||
|
||||
/* Task Mgmt states */
|
||||
#define TMABORT_INITIAL 0x0
|
||||
#define TMABORT_SUCCESS 0x1
|
||||
#define TMABORT_FAILED 0x2
|
||||
#define TMABORT_TIMEDOUT 0x3
|
||||
#define TMABORT_NOT_FOUND 0x4
|
||||
|
||||
/* Connection suspend "bit" */
|
||||
#define ISCSI_SUSPEND_BIT 1
|
||||
|
||||
#define ISCSI_ITT_MASK (0xfff)
|
||||
#define ISCSI_CID_SHIFT 12
|
||||
#define ISCSI_CID_MASK (0xffff << ISCSI_CID_SHIFT)
|
||||
#define ISCSI_AGE_SHIFT 28
|
||||
#define ISCSI_AGE_MASK (0xf << ISCSI_AGE_SHIFT)
|
||||
|
||||
struct iscsi_mgmt_task {
|
||||
/*
|
||||
* Becuae LLDs allocate their hdr differently, this is a pointer to
|
||||
* that storage. It must be setup at session creation time.
|
||||
*/
|
||||
struct iscsi_hdr *hdr;
|
||||
char *data; /* mgmt payload */
|
||||
int data_count; /* counts data to be sent */
|
||||
uint32_t itt; /* this ITT */
|
||||
void *dd_data; /* driver/transport data */
|
||||
struct list_head running;
|
||||
};
|
||||
|
||||
enum {
|
||||
ISCSI_TASK_COMPLETED,
|
||||
ISCSI_TASK_PENDING,
|
||||
ISCSI_TASK_RUNNING,
|
||||
};
|
||||
|
||||
struct iscsi_cmd_task {
|
||||
/*
|
||||
* Becuae LLDs allocate their hdr differently, this is a pointer to
|
||||
* that storage. It must be setup at session creation time.
|
||||
*/
|
||||
struct iscsi_cmd *hdr;
|
||||
int itt; /* this ITT */
|
||||
int datasn; /* DataSN */
|
||||
|
||||
uint32_t unsol_datasn;
|
||||
int imm_count; /* imm-data (bytes) */
|
||||
int unsol_count; /* unsolicited (bytes)*/
|
||||
/* offset in unsolicited stream (bytes); */
|
||||
int unsol_offset;
|
||||
int data_count; /* remaining Data-Out */
|
||||
struct scsi_cmnd *sc; /* associated SCSI cmd*/
|
||||
int total_length;
|
||||
struct iscsi_conn *conn; /* used connection */
|
||||
struct iscsi_mgmt_task *mtask; /* tmf mtask in progr */
|
||||
|
||||
/* state set/tested under session->lock */
|
||||
int state;
|
||||
atomic_t refcount;
|
||||
struct list_head running; /* running cmd list */
|
||||
void *dd_data; /* driver/transport data */
|
||||
};
|
||||
|
||||
struct iscsi_conn {
|
||||
struct iscsi_cls_conn *cls_conn; /* ptr to class connection */
|
||||
void *dd_data; /* iscsi_transport data */
|
||||
struct iscsi_session *session; /* parent session */
|
||||
/*
|
||||
* LLDs should set this lock. It protects the transport recv
|
||||
* code
|
||||
*/
|
||||
rwlock_t *recv_lock;
|
||||
/*
|
||||
* conn_stop() flag: stop to recover, stop to terminate
|
||||
*/
|
||||
int stop_stage;
|
||||
|
||||
/* iSCSI connection-wide sequencing */
|
||||
uint32_t exp_statsn;
|
||||
|
||||
/* control data */
|
||||
int id; /* CID */
|
||||
int c_stage; /* connection state */
|
||||
/*
|
||||
* Preallocated buffer for pdus that have data but do not
|
||||
* originate from scsi-ml. We never have two pdus using the
|
||||
* buffer at the same time. It is only allocated to
|
||||
* the default max recv size because the pdus we support
|
||||
* should always fit in this buffer
|
||||
*/
|
||||
char *data;
|
||||
struct iscsi_mgmt_task *login_mtask; /* mtask used for login/text */
|
||||
struct iscsi_mgmt_task *mtask; /* xmit mtask in progress */
|
||||
struct iscsi_cmd_task *ctask; /* xmit ctask in progress */
|
||||
|
||||
/* xmit */
|
||||
struct kfifo *immqueue; /* immediate xmit queue */
|
||||
struct kfifo *mgmtqueue; /* mgmt (control) xmit queue */
|
||||
struct list_head mgmt_run_list; /* list of control tasks */
|
||||
struct list_head xmitqueue; /* data-path cmd queue */
|
||||
struct list_head run_list; /* list of cmds in progress */
|
||||
struct work_struct xmitwork; /* per-conn. xmit workqueue */
|
||||
/*
|
||||
* serializes connection xmit, access to kfifos:
|
||||
* xmitqueue, immqueue, mgmtqueue
|
||||
*/
|
||||
struct mutex xmitmutex;
|
||||
|
||||
unsigned long suspend_tx; /* suspend Tx */
|
||||
unsigned long suspend_rx; /* suspend Rx */
|
||||
|
||||
/* abort */
|
||||
wait_queue_head_t ehwait; /* used in eh_abort() */
|
||||
struct iscsi_tm tmhdr;
|
||||
struct timer_list tmabort_timer;
|
||||
int tmabort_state; /* see TMABORT_INITIAL, etc.*/
|
||||
|
||||
/* negotiated params */
|
||||
int max_recv_dlength; /* initiator_max_recv_dsl*/
|
||||
int max_xmit_dlength; /* target_max_recv_dsl */
|
||||
int hdrdgst_en;
|
||||
int datadgst_en;
|
||||
int ifmarker_en;
|
||||
int ofmarker_en;
|
||||
/* values userspace uses to id a conn */
|
||||
int persistent_port;
|
||||
char *persistent_address;
|
||||
|
||||
/* MIB-statistics */
|
||||
uint64_t txdata_octets;
|
||||
uint64_t rxdata_octets;
|
||||
uint32_t scsicmd_pdus_cnt;
|
||||
uint32_t dataout_pdus_cnt;
|
||||
uint32_t scsirsp_pdus_cnt;
|
||||
uint32_t datain_pdus_cnt;
|
||||
uint32_t r2t_pdus_cnt;
|
||||
uint32_t tmfcmd_pdus_cnt;
|
||||
int32_t tmfrsp_pdus_cnt;
|
||||
|
||||
/* custom statistics */
|
||||
uint32_t eh_abort_cnt;
|
||||
};
|
||||
|
||||
struct iscsi_queue {
|
||||
struct kfifo *queue; /* FIFO Queue */
|
||||
void **pool; /* Pool of elements */
|
||||
int max; /* Max number of elements */
|
||||
};
|
||||
|
||||
struct iscsi_session {
|
||||
/* iSCSI session-wide sequencing */
|
||||
uint32_t cmdsn;
|
||||
uint32_t exp_cmdsn;
|
||||
uint32_t max_cmdsn;
|
||||
|
||||
/* configuration */
|
||||
int initial_r2t_en;
|
||||
int max_r2t;
|
||||
int imm_data_en;
|
||||
int first_burst;
|
||||
int max_burst;
|
||||
int time2wait;
|
||||
int time2retain;
|
||||
int pdu_inorder_en;
|
||||
int dataseq_inorder_en;
|
||||
int erl;
|
||||
int tpgt;
|
||||
char *targetname;
|
||||
|
||||
/* control data */
|
||||
struct iscsi_transport *tt;
|
||||
struct Scsi_Host *host;
|
||||
struct iscsi_conn *leadconn; /* leading connection */
|
||||
spinlock_t lock; /* protects session state, *
|
||||
* sequence numbers, *
|
||||
* session resources: *
|
||||
* - cmdpool, *
|
||||
* - mgmtpool, *
|
||||
* - r2tpool */
|
||||
int state; /* session state */
|
||||
int age; /* counts session re-opens */
|
||||
|
||||
int cmds_max; /* size of cmds array */
|
||||
struct iscsi_cmd_task **cmds; /* Original Cmds arr */
|
||||
struct iscsi_queue cmdpool; /* PDU's pool */
|
||||
int mgmtpool_max; /* size of mgmt array */
|
||||
struct iscsi_mgmt_task **mgmt_cmds; /* Original mgmt arr */
|
||||
struct iscsi_queue mgmtpool; /* Mgmt PDU's pool */
|
||||
};
|
||||
|
||||
/*
|
||||
* scsi host template
|
||||
*/
|
||||
extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth);
|
||||
extern int iscsi_eh_abort(struct scsi_cmnd *sc);
|
||||
extern int iscsi_eh_host_reset(struct scsi_cmnd *sc);
|
||||
extern int iscsi_queuecommand(struct scsi_cmnd *sc,
|
||||
void (*done)(struct scsi_cmnd *));
|
||||
|
||||
/*
|
||||
* session management
|
||||
*/
|
||||
extern struct iscsi_cls_session *
|
||||
iscsi_session_setup(struct iscsi_transport *, struct scsi_transport_template *,
|
||||
int, int, uint32_t, uint32_t *);
|
||||
extern void iscsi_session_teardown(struct iscsi_cls_session *);
|
||||
extern struct iscsi_session *class_to_transport_session(struct iscsi_cls_session *);
|
||||
extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *);
|
||||
extern int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
|
||||
enum iscsi_param param, char *buf, int buflen);
|
||||
extern int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
|
||||
enum iscsi_param param, char *buf);
|
||||
|
||||
#define session_to_cls(_sess) \
|
||||
hostdata_session(_sess->host->hostdata)
|
||||
|
||||
/*
|
||||
* connection management
|
||||
*/
|
||||
extern struct iscsi_cls_conn *iscsi_conn_setup(struct iscsi_cls_session *,
|
||||
uint32_t);
|
||||
extern void iscsi_conn_teardown(struct iscsi_cls_conn *);
|
||||
extern int iscsi_conn_start(struct iscsi_cls_conn *);
|
||||
extern void iscsi_conn_stop(struct iscsi_cls_conn *, int);
|
||||
extern int iscsi_conn_bind(struct iscsi_cls_session *, struct iscsi_cls_conn *,
|
||||
int);
|
||||
extern void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err);
|
||||
extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
|
||||
enum iscsi_param param, char *buf);
|
||||
|
||||
/*
|
||||
* pdu and task processing
|
||||
*/
|
||||
extern int iscsi_check_assign_cmdsn(struct iscsi_session *,
|
||||
struct iscsi_nopin *);
|
||||
extern void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *,
|
||||
struct iscsi_data *hdr);
|
||||
extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *,
|
||||
char *, uint32_t);
|
||||
extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,
|
||||
char *, int);
|
||||
extern int __iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,
|
||||
char *, int);
|
||||
extern int iscsi_verify_itt(struct iscsi_conn *, struct iscsi_hdr *,
|
||||
uint32_t *);
|
||||
|
||||
/*
|
||||
* generic helpers
|
||||
*/
|
||||
extern void iscsi_pool_free(struct iscsi_queue *, void **);
|
||||
extern int iscsi_pool_init(struct iscsi_queue *, int, void ***, int);
|
||||
|
||||
#endif
|
||||
665
include/scsi/libsas.h
Normal file
665
include/scsi/libsas.h
Normal file
@@ -0,0 +1,665 @@
|
||||
/*
|
||||
* SAS host prototypes and structures header file
|
||||
*
|
||||
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
|
||||
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
|
||||
*
|
||||
* This file is licensed under GPLv2.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LIBSAS_H_
|
||||
#define _LIBSAS_H_
|
||||
|
||||
|
||||
#include <linux/timer.h>
|
||||
#include <linux/pci.h>
|
||||
#include <scsi/sas.h>
|
||||
#include <linux/list.h>
|
||||
#include <asm/semaphore.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include <scsi/scsi_transport_sas.h>
|
||||
#include <asm/scatterlist.h>
|
||||
|
||||
struct block_device;
|
||||
|
||||
enum sas_class {
|
||||
SAS,
|
||||
EXPANDER
|
||||
};
|
||||
|
||||
enum sas_phy_role {
|
||||
PHY_ROLE_NONE = 0,
|
||||
PHY_ROLE_TARGET = 0x40,
|
||||
PHY_ROLE_INITIATOR = 0x80,
|
||||
};
|
||||
|
||||
enum sas_phy_type {
|
||||
PHY_TYPE_PHYSICAL,
|
||||
PHY_TYPE_VIRTUAL
|
||||
};
|
||||
|
||||
/* The events are mnemonically described in sas_dump.c
|
||||
* so when updating/adding events here, please also
|
||||
* update the other file too.
|
||||
*/
|
||||
enum ha_event {
|
||||
HAE_RESET = 0U,
|
||||
HA_NUM_EVENTS = 1,
|
||||
};
|
||||
|
||||
enum port_event {
|
||||
PORTE_BYTES_DMAED = 0U,
|
||||
PORTE_BROADCAST_RCVD = 1,
|
||||
PORTE_LINK_RESET_ERR = 2,
|
||||
PORTE_TIMER_EVENT = 3,
|
||||
PORTE_HARD_RESET = 4,
|
||||
PORT_NUM_EVENTS = 5,
|
||||
};
|
||||
|
||||
enum phy_event {
|
||||
PHYE_LOSS_OF_SIGNAL = 0U,
|
||||
PHYE_OOB_DONE = 1,
|
||||
PHYE_OOB_ERROR = 2,
|
||||
PHYE_SPINUP_HOLD = 3, /* hot plug SATA, no COMWAKE sent */
|
||||
PHY_NUM_EVENTS = 4,
|
||||
};
|
||||
|
||||
enum discover_event {
|
||||
DISCE_DISCOVER_DOMAIN = 0U,
|
||||
DISCE_REVALIDATE_DOMAIN = 1,
|
||||
DISCE_PORT_GONE = 2,
|
||||
DISC_NUM_EVENTS = 3,
|
||||
};
|
||||
|
||||
/* ---------- Expander Devices ---------- */
|
||||
|
||||
#define ETASK 0xFA
|
||||
|
||||
#define to_dom_device(_obj) container_of(_obj, struct domain_device, dev_obj)
|
||||
#define to_dev_attr(_attr) container_of(_attr, struct domain_dev_attribute,\
|
||||
attr)
|
||||
|
||||
enum routing_attribute {
|
||||
DIRECT_ROUTING,
|
||||
SUBTRACTIVE_ROUTING,
|
||||
TABLE_ROUTING,
|
||||
};
|
||||
|
||||
enum ex_phy_state {
|
||||
PHY_EMPTY,
|
||||
PHY_VACANT,
|
||||
PHY_NOT_PRESENT,
|
||||
PHY_DEVICE_DISCOVERED
|
||||
};
|
||||
|
||||
struct ex_phy {
|
||||
int phy_id;
|
||||
|
||||
enum ex_phy_state phy_state;
|
||||
|
||||
enum sas_dev_type attached_dev_type;
|
||||
enum sas_linkrate linkrate;
|
||||
|
||||
u8 attached_sata_host:1;
|
||||
u8 attached_sata_dev:1;
|
||||
u8 attached_sata_ps:1;
|
||||
|
||||
enum sas_proto attached_tproto;
|
||||
enum sas_proto attached_iproto;
|
||||
|
||||
u8 attached_sas_addr[SAS_ADDR_SIZE];
|
||||
u8 attached_phy_id;
|
||||
|
||||
u8 phy_change_count;
|
||||
enum routing_attribute routing_attr;
|
||||
u8 virtual:1;
|
||||
|
||||
int last_da_index;
|
||||
|
||||
struct sas_phy *phy;
|
||||
struct sas_port *port;
|
||||
};
|
||||
|
||||
struct expander_device {
|
||||
struct list_head children;
|
||||
|
||||
u16 ex_change_count;
|
||||
u16 max_route_indexes;
|
||||
u8 num_phys;
|
||||
u8 configuring:1;
|
||||
u8 conf_route_table:1;
|
||||
u8 enclosure_logical_id[8];
|
||||
|
||||
struct ex_phy *ex_phy;
|
||||
struct sas_port *parent_port;
|
||||
};
|
||||
|
||||
/* ---------- SATA device ---------- */
|
||||
enum ata_command_set {
|
||||
ATA_COMMAND_SET = 0,
|
||||
ATAPI_COMMAND_SET = 1,
|
||||
};
|
||||
|
||||
struct sata_device {
|
||||
enum ata_command_set command_set;
|
||||
struct smp_resp rps_resp; /* report_phy_sata_resp */
|
||||
__le16 *identify_device;
|
||||
__le16 *identify_packet_device;
|
||||
|
||||
u8 port_no; /* port number, if this is a PM (Port) */
|
||||
struct list_head children; /* PM Ports if this is a PM */
|
||||
};
|
||||
|
||||
/* ---------- Domain device ---------- */
|
||||
struct domain_device {
|
||||
enum sas_dev_type dev_type;
|
||||
|
||||
enum sas_linkrate linkrate;
|
||||
enum sas_linkrate min_linkrate;
|
||||
enum sas_linkrate max_linkrate;
|
||||
|
||||
int pathways;
|
||||
|
||||
struct domain_device *parent;
|
||||
struct list_head siblings; /* devices on the same level */
|
||||
struct asd_sas_port *port; /* shortcut to root of the tree */
|
||||
|
||||
struct list_head dev_list_node;
|
||||
|
||||
enum sas_proto iproto;
|
||||
enum sas_proto tproto;
|
||||
|
||||
struct sas_rphy *rphy;
|
||||
|
||||
u8 sas_addr[SAS_ADDR_SIZE];
|
||||
u8 hashed_sas_addr[HASHED_SAS_ADDR_SIZE];
|
||||
|
||||
u8 frame_rcvd[32];
|
||||
|
||||
union {
|
||||
struct expander_device ex_dev;
|
||||
struct sata_device sata_dev; /* STP & directly attached */
|
||||
};
|
||||
|
||||
void *lldd_dev;
|
||||
};
|
||||
|
||||
struct sas_discovery_event {
|
||||
struct work_struct work;
|
||||
struct asd_sas_port *port;
|
||||
};
|
||||
|
||||
struct sas_discovery {
|
||||
spinlock_t disc_event_lock;
|
||||
struct sas_discovery_event disc_work[DISC_NUM_EVENTS];
|
||||
unsigned long pending;
|
||||
u8 fanout_sas_addr[8];
|
||||
u8 eeds_a[8];
|
||||
u8 eeds_b[8];
|
||||
int max_level;
|
||||
};
|
||||
|
||||
|
||||
/* The port struct is Class:RW, driver:RO */
|
||||
struct asd_sas_port {
|
||||
/* private: */
|
||||
struct completion port_gone_completion;
|
||||
|
||||
struct sas_discovery disc;
|
||||
struct domain_device *port_dev;
|
||||
spinlock_t dev_list_lock;
|
||||
struct list_head dev_list;
|
||||
enum sas_linkrate linkrate;
|
||||
|
||||
struct sas_phy *phy;
|
||||
struct work_struct work;
|
||||
|
||||
/* public: */
|
||||
int id;
|
||||
|
||||
enum sas_class class;
|
||||
u8 sas_addr[SAS_ADDR_SIZE];
|
||||
u8 attached_sas_addr[SAS_ADDR_SIZE];
|
||||
enum sas_proto iproto;
|
||||
enum sas_proto tproto;
|
||||
|
||||
enum sas_oob_mode oob_mode;
|
||||
|
||||
spinlock_t phy_list_lock;
|
||||
struct list_head phy_list;
|
||||
int num_phys;
|
||||
u32 phy_mask;
|
||||
|
||||
struct sas_ha_struct *ha;
|
||||
|
||||
struct sas_port *port;
|
||||
|
||||
void *lldd_port; /* not touched by the sas class code */
|
||||
};
|
||||
|
||||
struct asd_sas_event {
|
||||
struct work_struct work;
|
||||
struct asd_sas_phy *phy;
|
||||
};
|
||||
|
||||
/* The phy pretty much is controlled by the LLDD.
|
||||
* The class only reads those fields.
|
||||
*/
|
||||
struct asd_sas_phy {
|
||||
/* private: */
|
||||
/* protected by ha->event_lock */
|
||||
struct asd_sas_event port_events[PORT_NUM_EVENTS];
|
||||
struct asd_sas_event phy_events[PHY_NUM_EVENTS];
|
||||
|
||||
unsigned long port_events_pending;
|
||||
unsigned long phy_events_pending;
|
||||
|
||||
int error;
|
||||
|
||||
struct sas_phy *phy;
|
||||
|
||||
/* public: */
|
||||
/* The following are class:RO, driver:R/W */
|
||||
int enabled; /* must be set */
|
||||
|
||||
int id; /* must be set */
|
||||
enum sas_class class;
|
||||
enum sas_proto iproto;
|
||||
enum sas_proto tproto;
|
||||
|
||||
enum sas_phy_type type;
|
||||
enum sas_phy_role role;
|
||||
enum sas_oob_mode oob_mode;
|
||||
enum sas_linkrate linkrate;
|
||||
|
||||
u8 *sas_addr; /* must be set */
|
||||
u8 attached_sas_addr[SAS_ADDR_SIZE]; /* class:RO, driver: R/W */
|
||||
|
||||
spinlock_t frame_rcvd_lock;
|
||||
u8 *frame_rcvd; /* must be set */
|
||||
int frame_rcvd_size;
|
||||
|
||||
spinlock_t sas_prim_lock;
|
||||
u32 sas_prim;
|
||||
|
||||
struct list_head port_phy_el; /* driver:RO */
|
||||
struct asd_sas_port *port; /* Class:RW, driver: RO */
|
||||
|
||||
struct sas_ha_struct *ha; /* may be set; the class sets it anyway */
|
||||
|
||||
void *lldd_phy; /* not touched by the sas_class_code */
|
||||
};
|
||||
|
||||
struct scsi_core {
|
||||
struct Scsi_Host *shost;
|
||||
|
||||
spinlock_t task_queue_lock;
|
||||
struct list_head task_queue;
|
||||
int task_queue_size;
|
||||
|
||||
struct semaphore queue_thread_sema;
|
||||
int queue_thread_kill;
|
||||
};
|
||||
|
||||
struct sas_ha_event {
|
||||
struct work_struct work;
|
||||
struct sas_ha_struct *ha;
|
||||
};
|
||||
|
||||
enum sas_ha_state {
|
||||
SAS_HA_REGISTERED,
|
||||
SAS_HA_UNREGISTERED
|
||||
};
|
||||
|
||||
struct sas_ha_struct {
|
||||
/* private: */
|
||||
spinlock_t event_lock;
|
||||
struct sas_ha_event ha_events[HA_NUM_EVENTS];
|
||||
unsigned long pending;
|
||||
|
||||
enum sas_ha_state state;
|
||||
spinlock_t state_lock;
|
||||
|
||||
struct scsi_core core;
|
||||
|
||||
/* public: */
|
||||
char *sas_ha_name;
|
||||
struct pci_dev *pcidev; /* should be set */
|
||||
struct module *lldd_module; /* should be set */
|
||||
|
||||
u8 *sas_addr; /* must be set */
|
||||
u8 hashed_sas_addr[HASHED_SAS_ADDR_SIZE];
|
||||
|
||||
spinlock_t phy_port_lock;
|
||||
struct asd_sas_phy **sas_phy; /* array of valid pointers, must be set */
|
||||
struct asd_sas_port **sas_port; /* array of valid pointers, must be set */
|
||||
int num_phys; /* must be set, gt 0, static */
|
||||
|
||||
/* The class calls this to send a task for execution. */
|
||||
int lldd_max_execute_num;
|
||||
int lldd_queue_size;
|
||||
|
||||
/* LLDD calls these to notify the class of an event. */
|
||||
void (*notify_ha_event)(struct sas_ha_struct *, enum ha_event);
|
||||
void (*notify_port_event)(struct asd_sas_phy *, enum port_event);
|
||||
void (*notify_phy_event)(struct asd_sas_phy *, enum phy_event);
|
||||
|
||||
void *lldd_ha; /* not touched by sas class code */
|
||||
|
||||
struct list_head eh_done_q;
|
||||
};
|
||||
|
||||
#define SHOST_TO_SAS_HA(_shost) (*(struct sas_ha_struct **)(_shost)->hostdata)
|
||||
|
||||
static inline struct domain_device *
|
||||
starget_to_domain_dev(struct scsi_target *starget) {
|
||||
return starget->hostdata;
|
||||
}
|
||||
|
||||
static inline struct domain_device *
|
||||
sdev_to_domain_dev(struct scsi_device *sdev) {
|
||||
return starget_to_domain_dev(sdev->sdev_target);
|
||||
}
|
||||
|
||||
static inline struct domain_device *
|
||||
cmd_to_domain_dev(struct scsi_cmnd *cmd)
|
||||
{
|
||||
return sdev_to_domain_dev(cmd->device);
|
||||
}
|
||||
|
||||
void sas_hash_addr(u8 *hashed, const u8 *sas_addr);
|
||||
|
||||
/* Before calling a notify event, LLDD should use this function
|
||||
* when the link is severed (possibly from its tasklet).
|
||||
* The idea is that the Class only reads those, while the LLDD,
|
||||
* can R/W these (thus avoiding a race).
|
||||
*/
|
||||
static inline void sas_phy_disconnected(struct asd_sas_phy *phy)
|
||||
{
|
||||
phy->oob_mode = OOB_NOT_CONNECTED;
|
||||
phy->linkrate = SAS_LINK_RATE_UNKNOWN;
|
||||
}
|
||||
|
||||
/* ---------- Tasks ---------- */
|
||||
/*
|
||||
service_response | SAS_TASK_COMPLETE | SAS_TASK_UNDELIVERED |
|
||||
exec_status | | |
|
||||
---------------------+---------------------+-----------------------+
|
||||
SAM_... | X | |
|
||||
DEV_NO_RESPONSE | X | X |
|
||||
INTERRUPTED | X | |
|
||||
QUEUE_FULL | | X |
|
||||
DEVICE_UNKNOWN | | X |
|
||||
SG_ERR | | X |
|
||||
---------------------+---------------------+-----------------------+
|
||||
*/
|
||||
|
||||
enum service_response {
|
||||
SAS_TASK_COMPLETE,
|
||||
SAS_TASK_UNDELIVERED = -1,
|
||||
};
|
||||
|
||||
enum exec_status {
|
||||
SAM_GOOD = 0,
|
||||
SAM_CHECK_COND = 2,
|
||||
SAM_COND_MET = 4,
|
||||
SAM_BUSY = 8,
|
||||
SAM_INTERMEDIATE = 0x10,
|
||||
SAM_IM_COND_MET = 0x12,
|
||||
SAM_RESV_CONFLICT= 0x14,
|
||||
SAM_TASK_SET_FULL= 0x28,
|
||||
SAM_ACA_ACTIVE = 0x30,
|
||||
SAM_TASK_ABORTED = 0x40,
|
||||
|
||||
SAS_DEV_NO_RESPONSE = 0x80,
|
||||
SAS_DATA_UNDERRUN,
|
||||
SAS_DATA_OVERRUN,
|
||||
SAS_INTERRUPTED,
|
||||
SAS_QUEUE_FULL,
|
||||
SAS_DEVICE_UNKNOWN,
|
||||
SAS_SG_ERR,
|
||||
SAS_OPEN_REJECT,
|
||||
SAS_OPEN_TO,
|
||||
SAS_PROTO_RESPONSE,
|
||||
SAS_PHY_DOWN,
|
||||
SAS_NAK_R_ERR,
|
||||
SAS_PENDING,
|
||||
SAS_ABORTED_TASK,
|
||||
};
|
||||
|
||||
/* When a task finishes with a response, the LLDD examines the
|
||||
* response:
|
||||
* - For an ATA task task_status_struct::stat is set to
|
||||
* SAS_PROTO_RESPONSE, and the task_status_struct::buf is set to the
|
||||
* contents of struct ata_task_resp.
|
||||
* - For SSP tasks, if no data is present or status/TMF response
|
||||
* is valid, task_status_struct::stat is set. If data is present
|
||||
* (SENSE data), the LLDD copies up to SAS_STATUS_BUF_SIZE, sets
|
||||
* task_status_struct::buf_valid_size, and task_status_struct::stat is
|
||||
* set to SAM_CHECK_COND.
|
||||
*
|
||||
* "buf" has format SCSI Sense for SSP task, or struct ata_task_resp
|
||||
* for ATA task.
|
||||
*
|
||||
* "frame_len" is the total frame length, which could be more or less
|
||||
* than actually copied.
|
||||
*
|
||||
* Tasks ending with response, always set the residual field.
|
||||
*/
|
||||
struct ata_task_resp {
|
||||
u16 frame_len;
|
||||
u8 ending_fis[24]; /* dev to host or data-in */
|
||||
u32 sstatus;
|
||||
u32 serror;
|
||||
u32 scontrol;
|
||||
u32 sactive;
|
||||
};
|
||||
|
||||
#define SAS_STATUS_BUF_SIZE 96
|
||||
|
||||
struct task_status_struct {
|
||||
enum service_response resp;
|
||||
enum exec_status stat;
|
||||
int buf_valid_size;
|
||||
|
||||
u8 buf[SAS_STATUS_BUF_SIZE];
|
||||
|
||||
u32 residual;
|
||||
enum sas_open_rej_reason open_rej_reason;
|
||||
};
|
||||
|
||||
/* ATA and ATAPI task queuable to a SAS LLDD.
|
||||
*/
|
||||
struct sas_ata_task {
|
||||
struct host_to_dev_fis fis;
|
||||
u8 atapi_packet[16]; /* 0 if not ATAPI task */
|
||||
|
||||
u8 retry_count; /* hardware retry, should be > 0 */
|
||||
|
||||
u8 dma_xfer:1; /* PIO:0 or DMA:1 */
|
||||
u8 use_ncq:1;
|
||||
u8 set_affil_pol:1;
|
||||
u8 stp_affil_pol:1;
|
||||
|
||||
u8 device_control_reg_update:1;
|
||||
};
|
||||
|
||||
struct sas_smp_task {
|
||||
struct scatterlist smp_req;
|
||||
struct scatterlist smp_resp;
|
||||
};
|
||||
|
||||
enum task_attribute {
|
||||
TASK_ATTR_SIMPLE = 0,
|
||||
TASK_ATTR_HOQ = 1,
|
||||
TASK_ATTR_ORDERED= 2,
|
||||
TASK_ATTR_ACA = 4,
|
||||
};
|
||||
|
||||
struct sas_ssp_task {
|
||||
u8 retry_count; /* hardware retry, should be > 0 */
|
||||
|
||||
u8 LUN[8];
|
||||
u8 enable_first_burst:1;
|
||||
enum task_attribute task_attr;
|
||||
u8 task_prio;
|
||||
u8 cdb[16];
|
||||
};
|
||||
|
||||
struct sas_task {
|
||||
struct domain_device *dev;
|
||||
struct list_head list;
|
||||
|
||||
spinlock_t task_state_lock;
|
||||
unsigned task_state_flags;
|
||||
|
||||
enum sas_proto task_proto;
|
||||
|
||||
/* Used by the discovery code. */
|
||||
struct timer_list timer;
|
||||
struct completion completion;
|
||||
|
||||
union {
|
||||
struct sas_ata_task ata_task;
|
||||
struct sas_smp_task smp_task;
|
||||
struct sas_ssp_task ssp_task;
|
||||
};
|
||||
|
||||
struct scatterlist *scatter;
|
||||
int num_scatter;
|
||||
u32 total_xfer_len;
|
||||
u8 data_dir:2; /* Use PCI_DMA_... */
|
||||
|
||||
struct task_status_struct task_status;
|
||||
void (*task_done)(struct sas_task *);
|
||||
|
||||
void *lldd_task; /* for use by LLDDs */
|
||||
void *uldd_task;
|
||||
|
||||
struct work_struct abort_work;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define SAS_TASK_STATE_PENDING 1
|
||||
#define SAS_TASK_STATE_DONE 2
|
||||
#define SAS_TASK_STATE_ABORTED 4
|
||||
#define SAS_TASK_NEED_DEV_RESET 8
|
||||
#define SAS_TASK_AT_INITIATOR 16
|
||||
|
||||
static inline struct sas_task *sas_alloc_task(gfp_t flags)
|
||||
{
|
||||
extern struct kmem_cache *sas_task_cache;
|
||||
struct sas_task *task = kmem_cache_zalloc(sas_task_cache, flags);
|
||||
|
||||
if (task) {
|
||||
INIT_LIST_HEAD(&task->list);
|
||||
spin_lock_init(&task->task_state_lock);
|
||||
task->task_state_flags = SAS_TASK_STATE_PENDING;
|
||||
init_timer(&task->timer);
|
||||
init_completion(&task->completion);
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
static inline void sas_free_task(struct sas_task *task)
|
||||
{
|
||||
if (task) {
|
||||
extern struct kmem_cache *sas_task_cache;
|
||||
BUG_ON(!list_empty(&task->list));
|
||||
kmem_cache_free(sas_task_cache, task);
|
||||
}
|
||||
}
|
||||
|
||||
struct sas_domain_function_template {
|
||||
/* The class calls these to notify the LLDD of an event. */
|
||||
void (*lldd_port_formed)(struct asd_sas_phy *);
|
||||
void (*lldd_port_deformed)(struct asd_sas_phy *);
|
||||
|
||||
/* The class calls these when a device is found or gone. */
|
||||
int (*lldd_dev_found)(struct domain_device *);
|
||||
void (*lldd_dev_gone)(struct domain_device *);
|
||||
|
||||
int (*lldd_execute_task)(struct sas_task *, int num,
|
||||
gfp_t gfp_flags);
|
||||
|
||||
/* Task Management Functions. Must be called from process context. */
|
||||
int (*lldd_abort_task)(struct sas_task *);
|
||||
int (*lldd_abort_task_set)(struct domain_device *, u8 *lun);
|
||||
int (*lldd_clear_aca)(struct domain_device *, u8 *lun);
|
||||
int (*lldd_clear_task_set)(struct domain_device *, u8 *lun);
|
||||
int (*lldd_I_T_nexus_reset)(struct domain_device *);
|
||||
int (*lldd_lu_reset)(struct domain_device *, u8 *lun);
|
||||
int (*lldd_query_task)(struct sas_task *);
|
||||
|
||||
/* Port and Adapter management */
|
||||
int (*lldd_clear_nexus_port)(struct asd_sas_port *);
|
||||
int (*lldd_clear_nexus_ha)(struct sas_ha_struct *);
|
||||
|
||||
/* Phy management */
|
||||
int (*lldd_control_phy)(struct asd_sas_phy *, enum phy_func, void *);
|
||||
};
|
||||
|
||||
extern int sas_register_ha(struct sas_ha_struct *);
|
||||
extern int sas_unregister_ha(struct sas_ha_struct *);
|
||||
|
||||
int sas_set_phy_speed(struct sas_phy *phy,
|
||||
struct sas_phy_linkrates *rates);
|
||||
int sas_phy_enable(struct sas_phy *phy, int enabled);
|
||||
int sas_phy_reset(struct sas_phy *phy, int hard_reset);
|
||||
extern int sas_queuecommand(struct scsi_cmnd *,
|
||||
void (*scsi_done)(struct scsi_cmnd *));
|
||||
extern int sas_target_alloc(struct scsi_target *);
|
||||
extern int sas_slave_alloc(struct scsi_device *);
|
||||
extern int sas_slave_configure(struct scsi_device *);
|
||||
extern void sas_slave_destroy(struct scsi_device *);
|
||||
extern int sas_change_queue_depth(struct scsi_device *, int new_depth);
|
||||
extern int sas_change_queue_type(struct scsi_device *, int qt);
|
||||
extern int sas_bios_param(struct scsi_device *,
|
||||
struct block_device *,
|
||||
sector_t capacity, int *hsc);
|
||||
extern struct scsi_transport_template *
|
||||
sas_domain_attach_transport(struct sas_domain_function_template *);
|
||||
extern void sas_domain_release_transport(struct scsi_transport_template *);
|
||||
|
||||
int sas_discover_root_expander(struct domain_device *);
|
||||
|
||||
void sas_init_ex_attr(void);
|
||||
|
||||
int sas_ex_revalidate_domain(struct domain_device *);
|
||||
|
||||
void sas_unregister_domain_devices(struct asd_sas_port *port);
|
||||
void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *);
|
||||
int sas_discover_event(struct asd_sas_port *, enum discover_event ev);
|
||||
|
||||
int sas_discover_sata(struct domain_device *);
|
||||
int sas_discover_end_dev(struct domain_device *);
|
||||
|
||||
void sas_unregister_dev(struct domain_device *);
|
||||
|
||||
void sas_init_dev(struct domain_device *);
|
||||
|
||||
void sas_task_abort(struct sas_task *);
|
||||
int __sas_task_abort(struct sas_task *);
|
||||
int sas_eh_device_reset_handler(struct scsi_cmnd *cmd);
|
||||
int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd);
|
||||
|
||||
#endif /* _SASLIB_H_ */
|
||||
77
include/scsi/libsrp.h
Normal file
77
include/scsi/libsrp.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#ifndef __LIBSRP_H__
|
||||
#define __LIBSRP_H__
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <scsi/srp.h>
|
||||
|
||||
enum iue_flags {
|
||||
V_DIOVER,
|
||||
V_WRITE,
|
||||
V_LINKED,
|
||||
V_FLYING,
|
||||
};
|
||||
|
||||
struct srp_buf {
|
||||
dma_addr_t dma;
|
||||
void *buf;
|
||||
};
|
||||
|
||||
struct srp_queue {
|
||||
void *pool;
|
||||
void *items;
|
||||
struct kfifo *queue;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct srp_target {
|
||||
struct Scsi_Host *shost;
|
||||
struct device *dev;
|
||||
|
||||
spinlock_t lock;
|
||||
struct list_head cmd_queue;
|
||||
|
||||
size_t srp_iu_size;
|
||||
struct srp_queue iu_queue;
|
||||
size_t rx_ring_size;
|
||||
struct srp_buf **rx_ring;
|
||||
|
||||
void *ldata;
|
||||
};
|
||||
|
||||
struct iu_entry {
|
||||
struct srp_target *target;
|
||||
|
||||
struct list_head ilist;
|
||||
dma_addr_t remote_token;
|
||||
unsigned long flags;
|
||||
|
||||
struct srp_buf *sbuf;
|
||||
};
|
||||
|
||||
typedef int (srp_rdma_t)(struct scsi_cmnd *, struct scatterlist *, int,
|
||||
struct srp_direct_buf *, int,
|
||||
enum dma_data_direction, unsigned int);
|
||||
extern int srp_target_alloc(struct srp_target *, struct device *, size_t, size_t);
|
||||
extern void srp_target_free(struct srp_target *);
|
||||
|
||||
extern struct iu_entry *srp_iu_get(struct srp_target *);
|
||||
extern void srp_iu_put(struct iu_entry *);
|
||||
|
||||
extern int srp_cmd_queue(struct Scsi_Host *, struct srp_cmd *, void *, u64);
|
||||
extern int srp_transfer_data(struct scsi_cmnd *, struct srp_cmd *,
|
||||
srp_rdma_t, int, int);
|
||||
|
||||
|
||||
static inline struct srp_target *host_to_srp_target(struct Scsi_Host *host)
|
||||
{
|
||||
return (struct srp_target *) host->hostdata;
|
||||
}
|
||||
|
||||
static inline int srp_cmd_direction(struct srp_cmd *cmd)
|
||||
{
|
||||
return (cmd->buf_fmt >> 4) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
|
||||
}
|
||||
|
||||
#endif
|
||||
631
include/scsi/sas.h
Normal file
631
include/scsi/sas.h
Normal file
@@ -0,0 +1,631 @@
|
||||
/*
|
||||
* SAS structures and definitions header file
|
||||
*
|
||||
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
|
||||
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
|
||||
*
|
||||
* This file is licensed under GPLv2.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SAS_H_
|
||||
#define _SAS_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#define SAS_ADDR_SIZE 8
|
||||
#define HASHED_SAS_ADDR_SIZE 3
|
||||
#define SAS_ADDR(_sa) ((unsigned long long) be64_to_cpu(*(__be64 *)(_sa)))
|
||||
|
||||
#define SMP_REQUEST 0x40
|
||||
#define SMP_RESPONSE 0x41
|
||||
|
||||
#define SSP_DATA 0x01
|
||||
#define SSP_XFER_RDY 0x05
|
||||
#define SSP_COMMAND 0x06
|
||||
#define SSP_RESPONSE 0x07
|
||||
#define SSP_TASK 0x16
|
||||
|
||||
#define SMP_REPORT_GENERAL 0x00
|
||||
#define SMP_REPORT_MANUF_INFO 0x01
|
||||
#define SMP_READ_GPIO_REG 0x02
|
||||
#define SMP_DISCOVER 0x10
|
||||
#define SMP_REPORT_PHY_ERR_LOG 0x11
|
||||
#define SMP_REPORT_PHY_SATA 0x12
|
||||
#define SMP_REPORT_ROUTE_INFO 0x13
|
||||
#define SMP_WRITE_GPIO_REG 0x82
|
||||
#define SMP_CONF_ROUTE_INFO 0x90
|
||||
#define SMP_PHY_CONTROL 0x91
|
||||
#define SMP_PHY_TEST_FUNCTION 0x92
|
||||
|
||||
#define SMP_RESP_FUNC_ACC 0x00
|
||||
#define SMP_RESP_FUNC_UNK 0x01
|
||||
#define SMP_RESP_FUNC_FAILED 0x02
|
||||
#define SMP_RESP_INV_FRM_LEN 0x03
|
||||
#define SMP_RESP_NO_PHY 0x10
|
||||
#define SMP_RESP_NO_INDEX 0x11
|
||||
#define SMP_RESP_PHY_NO_SATA 0x12
|
||||
#define SMP_RESP_PHY_UNK_OP 0x13
|
||||
#define SMP_RESP_PHY_UNK_TESTF 0x14
|
||||
#define SMP_RESP_PHY_TEST_INPROG 0x15
|
||||
#define SMP_RESP_PHY_VACANT 0x16
|
||||
|
||||
/* SAM TMFs */
|
||||
#define TMF_ABORT_TASK 0x01
|
||||
#define TMF_ABORT_TASK_SET 0x02
|
||||
#define TMF_CLEAR_TASK_SET 0x04
|
||||
#define TMF_LU_RESET 0x08
|
||||
#define TMF_CLEAR_ACA 0x40
|
||||
#define TMF_QUERY_TASK 0x80
|
||||
|
||||
/* SAS TMF responses */
|
||||
#define TMF_RESP_FUNC_COMPLETE 0x00
|
||||
#define TMF_RESP_INVALID_FRAME 0x02
|
||||
#define TMF_RESP_FUNC_ESUPP 0x04
|
||||
#define TMF_RESP_FUNC_FAILED 0x05
|
||||
#define TMF_RESP_FUNC_SUCC 0x08
|
||||
#define TMF_RESP_NO_LUN 0x09
|
||||
#define TMF_RESP_OVERLAPPED_TAG 0x0A
|
||||
|
||||
enum sas_oob_mode {
|
||||
OOB_NOT_CONNECTED,
|
||||
SATA_OOB_MODE,
|
||||
SAS_OOB_MODE
|
||||
};
|
||||
|
||||
/* See sas_discover.c if you plan on changing these.
|
||||
*/
|
||||
enum sas_dev_type {
|
||||
NO_DEVICE = 0, /* protocol */
|
||||
SAS_END_DEV = 1, /* protocol */
|
||||
EDGE_DEV = 2, /* protocol */
|
||||
FANOUT_DEV = 3, /* protocol */
|
||||
SAS_HA = 4,
|
||||
SATA_DEV = 5,
|
||||
SATA_PM = 7,
|
||||
SATA_PM_PORT= 8,
|
||||
};
|
||||
|
||||
/* Partly from IDENTIFY address frame. */
|
||||
enum sas_proto {
|
||||
SATA_PROTO = 1,
|
||||
SAS_PROTO_SMP = 2, /* protocol */
|
||||
SAS_PROTO_STP = 4, /* protocol */
|
||||
SAS_PROTO_SSP = 8, /* protocol */
|
||||
SAS_PROTO_ALL = 0xE,
|
||||
};
|
||||
|
||||
/* From the spec; local phys only */
|
||||
enum phy_func {
|
||||
PHY_FUNC_NOP,
|
||||
PHY_FUNC_LINK_RESET, /* Enables the phy */
|
||||
PHY_FUNC_HARD_RESET,
|
||||
PHY_FUNC_DISABLE,
|
||||
PHY_FUNC_CLEAR_ERROR_LOG = 5,
|
||||
PHY_FUNC_CLEAR_AFFIL,
|
||||
PHY_FUNC_TX_SATA_PS_SIGNAL,
|
||||
PHY_FUNC_RELEASE_SPINUP_HOLD = 0x10, /* LOCAL PORT ONLY! */
|
||||
PHY_FUNC_SET_LINK_RATE,
|
||||
};
|
||||
|
||||
/* SAS LLDD would need to report only _very_few_ of those, like BROADCAST.
|
||||
* Most of those are here for completeness.
|
||||
*/
|
||||
enum sas_prim {
|
||||
SAS_PRIM_AIP_NORMAL = 1,
|
||||
SAS_PRIM_AIP_R0 = 2,
|
||||
SAS_PRIM_AIP_R1 = 3,
|
||||
SAS_PRIM_AIP_R2 = 4,
|
||||
SAS_PRIM_AIP_WC = 5,
|
||||
SAS_PRIM_AIP_WD = 6,
|
||||
SAS_PRIM_AIP_WP = 7,
|
||||
SAS_PRIM_AIP_RWP = 8,
|
||||
|
||||
SAS_PRIM_BC_CH = 9,
|
||||
SAS_PRIM_BC_RCH0 = 10,
|
||||
SAS_PRIM_BC_RCH1 = 11,
|
||||
SAS_PRIM_BC_R0 = 12,
|
||||
SAS_PRIM_BC_R1 = 13,
|
||||
SAS_PRIM_BC_R2 = 14,
|
||||
SAS_PRIM_BC_R3 = 15,
|
||||
SAS_PRIM_BC_R4 = 16,
|
||||
|
||||
SAS_PRIM_NOTIFY_ENSP= 17,
|
||||
SAS_PRIM_NOTIFY_R0 = 18,
|
||||
SAS_PRIM_NOTIFY_R1 = 19,
|
||||
SAS_PRIM_NOTIFY_R2 = 20,
|
||||
|
||||
SAS_PRIM_CLOSE_CLAF = 21,
|
||||
SAS_PRIM_CLOSE_NORM = 22,
|
||||
SAS_PRIM_CLOSE_R0 = 23,
|
||||
SAS_PRIM_CLOSE_R1 = 24,
|
||||
|
||||
SAS_PRIM_OPEN_RTRY = 25,
|
||||
SAS_PRIM_OPEN_RJCT = 26,
|
||||
SAS_PRIM_OPEN_ACPT = 27,
|
||||
|
||||
SAS_PRIM_DONE = 28,
|
||||
SAS_PRIM_BREAK = 29,
|
||||
|
||||
SATA_PRIM_DMAT = 33,
|
||||
SATA_PRIM_PMNAK = 34,
|
||||
SATA_PRIM_PMACK = 35,
|
||||
SATA_PRIM_PMREQ_S = 36,
|
||||
SATA_PRIM_PMREQ_P = 37,
|
||||
SATA_SATA_R_ERR = 38,
|
||||
};
|
||||
|
||||
enum sas_open_rej_reason {
|
||||
/* Abandon open */
|
||||
SAS_OREJ_UNKNOWN = 0,
|
||||
SAS_OREJ_BAD_DEST = 1,
|
||||
SAS_OREJ_CONN_RATE = 2,
|
||||
SAS_OREJ_EPROTO = 3,
|
||||
SAS_OREJ_RESV_AB0 = 4,
|
||||
SAS_OREJ_RESV_AB1 = 5,
|
||||
SAS_OREJ_RESV_AB2 = 6,
|
||||
SAS_OREJ_RESV_AB3 = 7,
|
||||
SAS_OREJ_WRONG_DEST= 8,
|
||||
SAS_OREJ_STP_NORES = 9,
|
||||
|
||||
/* Retry open */
|
||||
SAS_OREJ_NO_DEST = 10,
|
||||
SAS_OREJ_PATH_BLOCKED = 11,
|
||||
SAS_OREJ_RSVD_CONT0 = 12,
|
||||
SAS_OREJ_RSVD_CONT1 = 13,
|
||||
SAS_OREJ_RSVD_INIT0 = 14,
|
||||
SAS_OREJ_RSVD_INIT1 = 15,
|
||||
SAS_OREJ_RSVD_STOP0 = 16,
|
||||
SAS_OREJ_RSVD_STOP1 = 17,
|
||||
SAS_OREJ_RSVD_RETRY = 18,
|
||||
};
|
||||
|
||||
struct dev_to_host_fis {
|
||||
u8 fis_type; /* 0x34 */
|
||||
u8 flags;
|
||||
u8 status;
|
||||
u8 error;
|
||||
|
||||
u8 lbal;
|
||||
union { u8 lbam; u8 byte_count_low; };
|
||||
union { u8 lbah; u8 byte_count_high; };
|
||||
u8 device;
|
||||
|
||||
u8 lbal_exp;
|
||||
u8 lbam_exp;
|
||||
u8 lbah_exp;
|
||||
u8 _r_a;
|
||||
|
||||
union { u8 sector_count; u8 interrupt_reason; };
|
||||
u8 sector_count_exp;
|
||||
u8 _r_b;
|
||||
u8 _r_c;
|
||||
|
||||
u32 _r_d;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct host_to_dev_fis {
|
||||
u8 fis_type; /* 0x27 */
|
||||
u8 flags;
|
||||
u8 command;
|
||||
u8 features;
|
||||
|
||||
u8 lbal;
|
||||
union { u8 lbam; u8 byte_count_low; };
|
||||
union { u8 lbah; u8 byte_count_high; };
|
||||
u8 device;
|
||||
|
||||
u8 lbal_exp;
|
||||
u8 lbam_exp;
|
||||
u8 lbah_exp;
|
||||
u8 features_exp;
|
||||
|
||||
union { u8 sector_count; u8 interrupt_reason; };
|
||||
u8 sector_count_exp;
|
||||
u8 _r_a;
|
||||
u8 control;
|
||||
|
||||
u32 _r_b;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Prefer to have code clarity over header file clarity.
|
||||
*/
|
||||
#ifdef __LITTLE_ENDIAN_BITFIELD
|
||||
struct sas_identify_frame {
|
||||
/* Byte 0 */
|
||||
u8 frame_type:4;
|
||||
u8 dev_type:3;
|
||||
u8 _un0:1;
|
||||
|
||||
/* Byte 1 */
|
||||
u8 _un1;
|
||||
|
||||
/* Byte 2 */
|
||||
union {
|
||||
struct {
|
||||
u8 _un20:1;
|
||||
u8 smp_iport:1;
|
||||
u8 stp_iport:1;
|
||||
u8 ssp_iport:1;
|
||||
u8 _un247:4;
|
||||
};
|
||||
u8 initiator_bits;
|
||||
};
|
||||
|
||||
/* Byte 3 */
|
||||
union {
|
||||
struct {
|
||||
u8 _un30:1;
|
||||
u8 smp_tport:1;
|
||||
u8 stp_tport:1;
|
||||
u8 ssp_tport:1;
|
||||
u8 _un347:4;
|
||||
};
|
||||
u8 target_bits;
|
||||
};
|
||||
|
||||
/* Byte 4 - 11 */
|
||||
u8 _un4_11[8];
|
||||
|
||||
/* Byte 12 - 19 */
|
||||
u8 sas_addr[SAS_ADDR_SIZE];
|
||||
|
||||
/* Byte 20 */
|
||||
u8 phy_id;
|
||||
|
||||
u8 _un21_27[7];
|
||||
|
||||
__be32 crc;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ssp_frame_hdr {
|
||||
u8 frame_type;
|
||||
u8 hashed_dest_addr[HASHED_SAS_ADDR_SIZE];
|
||||
u8 _r_a;
|
||||
u8 hashed_src_addr[HASHED_SAS_ADDR_SIZE];
|
||||
__be16 _r_b;
|
||||
|
||||
u8 changing_data_ptr:1;
|
||||
u8 retransmit:1;
|
||||
u8 retry_data_frames:1;
|
||||
u8 _r_c:5;
|
||||
|
||||
u8 num_fill_bytes:2;
|
||||
u8 _r_d:6;
|
||||
|
||||
u32 _r_e;
|
||||
__be16 tag;
|
||||
__be16 tptt;
|
||||
__be32 data_offs;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ssp_response_iu {
|
||||
u8 _r_a[10];
|
||||
|
||||
u8 datapres:2;
|
||||
u8 _r_b:6;
|
||||
|
||||
u8 status;
|
||||
|
||||
u32 _r_c;
|
||||
|
||||
__be32 sense_data_len;
|
||||
__be32 response_data_len;
|
||||
|
||||
u8 resp_data[0];
|
||||
u8 sense_data[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* ---------- SMP ---------- */
|
||||
|
||||
struct report_general_resp {
|
||||
__be16 change_count;
|
||||
__be16 route_indexes;
|
||||
u8 _r_a;
|
||||
u8 num_phys;
|
||||
|
||||
u8 conf_route_table:1;
|
||||
u8 configuring:1;
|
||||
u8 _r_b:6;
|
||||
|
||||
u8 _r_c;
|
||||
|
||||
u8 enclosure_logical_id[8];
|
||||
|
||||
u8 _r_d[12];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct discover_resp {
|
||||
u8 _r_a[5];
|
||||
|
||||
u8 phy_id;
|
||||
__be16 _r_b;
|
||||
|
||||
u8 _r_c:4;
|
||||
u8 attached_dev_type:3;
|
||||
u8 _r_d:1;
|
||||
|
||||
u8 linkrate:4;
|
||||
u8 _r_e:4;
|
||||
|
||||
u8 attached_sata_host:1;
|
||||
u8 iproto:3;
|
||||
u8 _r_f:4;
|
||||
|
||||
u8 attached_sata_dev:1;
|
||||
u8 tproto:3;
|
||||
u8 _r_g:3;
|
||||
u8 attached_sata_ps:1;
|
||||
|
||||
u8 sas_addr[8];
|
||||
u8 attached_sas_addr[8];
|
||||
u8 attached_phy_id;
|
||||
|
||||
u8 _r_h[7];
|
||||
|
||||
u8 hmin_linkrate:4;
|
||||
u8 pmin_linkrate:4;
|
||||
u8 hmax_linkrate:4;
|
||||
u8 pmax_linkrate:4;
|
||||
|
||||
u8 change_count;
|
||||
|
||||
u8 pptv:4;
|
||||
u8 _r_i:3;
|
||||
u8 virtual:1;
|
||||
|
||||
u8 routing_attr:4;
|
||||
u8 _r_j:4;
|
||||
|
||||
u8 conn_type;
|
||||
u8 conn_el_index;
|
||||
u8 conn_phy_link;
|
||||
|
||||
u8 _r_k[8];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct report_phy_sata_resp {
|
||||
u8 _r_a[5];
|
||||
|
||||
u8 phy_id;
|
||||
u8 _r_b;
|
||||
|
||||
u8 affil_valid:1;
|
||||
u8 affil_supp:1;
|
||||
u8 _r_c:6;
|
||||
|
||||
u32 _r_d;
|
||||
|
||||
u8 stp_sas_addr[8];
|
||||
|
||||
struct dev_to_host_fis fis;
|
||||
|
||||
u32 _r_e;
|
||||
|
||||
u8 affil_stp_ini_addr[8];
|
||||
|
||||
__be32 crc;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct smp_resp {
|
||||
u8 frame_type;
|
||||
u8 function;
|
||||
u8 result;
|
||||
u8 reserved;
|
||||
union {
|
||||
struct report_general_resp rg;
|
||||
struct discover_resp disc;
|
||||
struct report_phy_sata_resp rps;
|
||||
};
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#elif defined(__BIG_ENDIAN_BITFIELD)
|
||||
struct sas_identify_frame {
|
||||
/* Byte 0 */
|
||||
u8 _un0:1;
|
||||
u8 dev_type:3;
|
||||
u8 frame_type:4;
|
||||
|
||||
/* Byte 1 */
|
||||
u8 _un1;
|
||||
|
||||
/* Byte 2 */
|
||||
union {
|
||||
struct {
|
||||
u8 _un247:4;
|
||||
u8 ssp_iport:1;
|
||||
u8 stp_iport:1;
|
||||
u8 smp_iport:1;
|
||||
u8 _un20:1;
|
||||
};
|
||||
u8 initiator_bits;
|
||||
};
|
||||
|
||||
/* Byte 3 */
|
||||
union {
|
||||
struct {
|
||||
u8 _un347:4;
|
||||
u8 ssp_tport:1;
|
||||
u8 stp_tport:1;
|
||||
u8 smp_tport:1;
|
||||
u8 _un30:1;
|
||||
};
|
||||
u8 target_bits;
|
||||
};
|
||||
|
||||
/* Byte 4 - 11 */
|
||||
u8 _un4_11[8];
|
||||
|
||||
/* Byte 12 - 19 */
|
||||
u8 sas_addr[SAS_ADDR_SIZE];
|
||||
|
||||
/* Byte 20 */
|
||||
u8 phy_id;
|
||||
|
||||
u8 _un21_27[7];
|
||||
|
||||
__be32 crc;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ssp_frame_hdr {
|
||||
u8 frame_type;
|
||||
u8 hashed_dest_addr[HASHED_SAS_ADDR_SIZE];
|
||||
u8 _r_a;
|
||||
u8 hashed_src_addr[HASHED_SAS_ADDR_SIZE];
|
||||
__be16 _r_b;
|
||||
|
||||
u8 _r_c:5;
|
||||
u8 retry_data_frames:1;
|
||||
u8 retransmit:1;
|
||||
u8 changing_data_ptr:1;
|
||||
|
||||
u8 _r_d:6;
|
||||
u8 num_fill_bytes:2;
|
||||
|
||||
u32 _r_e;
|
||||
__be16 tag;
|
||||
__be16 tptt;
|
||||
__be32 data_offs;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ssp_response_iu {
|
||||
u8 _r_a[10];
|
||||
|
||||
u8 _r_b:6;
|
||||
u8 datapres:2;
|
||||
|
||||
u8 status;
|
||||
|
||||
u32 _r_c;
|
||||
|
||||
__be32 sense_data_len;
|
||||
__be32 response_data_len;
|
||||
|
||||
u8 resp_data[0];
|
||||
u8 sense_data[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* ---------- SMP ---------- */
|
||||
|
||||
struct report_general_resp {
|
||||
__be16 change_count;
|
||||
__be16 route_indexes;
|
||||
u8 _r_a;
|
||||
u8 num_phys;
|
||||
|
||||
u8 _r_b:6;
|
||||
u8 configuring:1;
|
||||
u8 conf_route_table:1;
|
||||
|
||||
u8 _r_c;
|
||||
|
||||
u8 enclosure_logical_id[8];
|
||||
|
||||
u8 _r_d[12];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct discover_resp {
|
||||
u8 _r_a[5];
|
||||
|
||||
u8 phy_id;
|
||||
__be16 _r_b;
|
||||
|
||||
u8 _r_d:1;
|
||||
u8 attached_dev_type:3;
|
||||
u8 _r_c:4;
|
||||
|
||||
u8 _r_e:4;
|
||||
u8 linkrate:4;
|
||||
|
||||
u8 _r_f:4;
|
||||
u8 iproto:3;
|
||||
u8 attached_sata_host:1;
|
||||
|
||||
u8 attached_sata_ps:1;
|
||||
u8 _r_g:3;
|
||||
u8 tproto:3;
|
||||
u8 attached_sata_dev:1;
|
||||
|
||||
u8 sas_addr[8];
|
||||
u8 attached_sas_addr[8];
|
||||
u8 attached_phy_id;
|
||||
|
||||
u8 _r_h[7];
|
||||
|
||||
u8 pmin_linkrate:4;
|
||||
u8 hmin_linkrate:4;
|
||||
u8 pmax_linkrate:4;
|
||||
u8 hmax_linkrate:4;
|
||||
|
||||
u8 change_count;
|
||||
|
||||
u8 virtual:1;
|
||||
u8 _r_i:3;
|
||||
u8 pptv:4;
|
||||
|
||||
u8 _r_j:4;
|
||||
u8 routing_attr:4;
|
||||
|
||||
u8 conn_type;
|
||||
u8 conn_el_index;
|
||||
u8 conn_phy_link;
|
||||
|
||||
u8 _r_k[8];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct report_phy_sata_resp {
|
||||
u8 _r_a[5];
|
||||
|
||||
u8 phy_id;
|
||||
u8 _r_b;
|
||||
|
||||
u8 _r_c:6;
|
||||
u8 affil_supp:1;
|
||||
u8 affil_valid:1;
|
||||
|
||||
u32 _r_d;
|
||||
|
||||
u8 stp_sas_addr[8];
|
||||
|
||||
struct dev_to_host_fis fis;
|
||||
|
||||
u32 _r_e;
|
||||
|
||||
u8 affil_stp_ini_addr[8];
|
||||
|
||||
__be32 crc;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct smp_resp {
|
||||
u8 frame_type;
|
||||
u8 function;
|
||||
u8 result;
|
||||
u8 reserved;
|
||||
union {
|
||||
struct report_general_resp rg;
|
||||
struct discover_resp disc;
|
||||
struct report_phy_sata_resp rps;
|
||||
};
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#else
|
||||
#error "Bitfield order not defined!"
|
||||
#endif
|
||||
|
||||
#endif /* _SAS_H_ */
|
||||
441
include/scsi/scsi.h
Normal file
441
include/scsi/scsi.h
Normal file
@@ -0,0 +1,441 @@
|
||||
/*
|
||||
* This header file contains public constants and structures used by
|
||||
* the scsi code for linux.
|
||||
*
|
||||
* For documentation on the OPCODES, MESSAGES, and SENSE values,
|
||||
* please consult the SCSI standard.
|
||||
*/
|
||||
#ifndef _SCSI_SCSI_H
|
||||
#define _SCSI_SCSI_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* The maximum sg list length SCSI can cope with
|
||||
* (currently must be a power of 2 between 32 and 256)
|
||||
*/
|
||||
#define SCSI_MAX_PHYS_SEGMENTS MAX_PHYS_SEGMENTS
|
||||
|
||||
|
||||
/*
|
||||
* SCSI command lengths
|
||||
*/
|
||||
|
||||
extern const unsigned char scsi_command_size[8];
|
||||
#define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]
|
||||
|
||||
/*
|
||||
* Special value for scanning to specify scanning or rescanning of all
|
||||
* possible channels, (target) ids, or luns on a given shost.
|
||||
*/
|
||||
#define SCAN_WILD_CARD ~0
|
||||
|
||||
/*
|
||||
* SCSI opcodes
|
||||
*/
|
||||
|
||||
#define TEST_UNIT_READY 0x00
|
||||
#define REZERO_UNIT 0x01
|
||||
#define REQUEST_SENSE 0x03
|
||||
#define FORMAT_UNIT 0x04
|
||||
#define READ_BLOCK_LIMITS 0x05
|
||||
#define REASSIGN_BLOCKS 0x07
|
||||
#define INITIALIZE_ELEMENT_STATUS 0x07
|
||||
#define READ_6 0x08
|
||||
#define WRITE_6 0x0a
|
||||
#define SEEK_6 0x0b
|
||||
#define READ_REVERSE 0x0f
|
||||
#define WRITE_FILEMARKS 0x10
|
||||
#define SPACE 0x11
|
||||
#define INQUIRY 0x12
|
||||
#define RECOVER_BUFFERED_DATA 0x14
|
||||
#define MODE_SELECT 0x15
|
||||
#define RESERVE 0x16
|
||||
#define RELEASE 0x17
|
||||
#define COPY 0x18
|
||||
#define ERASE 0x19
|
||||
#define MODE_SENSE 0x1a
|
||||
#define START_STOP 0x1b
|
||||
#define RECEIVE_DIAGNOSTIC 0x1c
|
||||
#define SEND_DIAGNOSTIC 0x1d
|
||||
#define ALLOW_MEDIUM_REMOVAL 0x1e
|
||||
|
||||
#define SET_WINDOW 0x24
|
||||
#define READ_CAPACITY 0x25
|
||||
#define READ_10 0x28
|
||||
#define WRITE_10 0x2a
|
||||
#define SEEK_10 0x2b
|
||||
#define POSITION_TO_ELEMENT 0x2b
|
||||
#define WRITE_VERIFY 0x2e
|
||||
#define VERIFY 0x2f
|
||||
#define SEARCH_HIGH 0x30
|
||||
#define SEARCH_EQUAL 0x31
|
||||
#define SEARCH_LOW 0x32
|
||||
#define SET_LIMITS 0x33
|
||||
#define PRE_FETCH 0x34
|
||||
#define READ_POSITION 0x34
|
||||
#define SYNCHRONIZE_CACHE 0x35
|
||||
#define LOCK_UNLOCK_CACHE 0x36
|
||||
#define READ_DEFECT_DATA 0x37
|
||||
#define MEDIUM_SCAN 0x38
|
||||
#define COMPARE 0x39
|
||||
#define COPY_VERIFY 0x3a
|
||||
#define WRITE_BUFFER 0x3b
|
||||
#define READ_BUFFER 0x3c
|
||||
#define UPDATE_BLOCK 0x3d
|
||||
#define READ_LONG 0x3e
|
||||
#define WRITE_LONG 0x3f
|
||||
#define CHANGE_DEFINITION 0x40
|
||||
#define WRITE_SAME 0x41
|
||||
#define READ_TOC 0x43
|
||||
#define LOG_SELECT 0x4c
|
||||
#define LOG_SENSE 0x4d
|
||||
#define MODE_SELECT_10 0x55
|
||||
#define RESERVE_10 0x56
|
||||
#define RELEASE_10 0x57
|
||||
#define MODE_SENSE_10 0x5a
|
||||
#define PERSISTENT_RESERVE_IN 0x5e
|
||||
#define PERSISTENT_RESERVE_OUT 0x5f
|
||||
#define REPORT_LUNS 0xa0
|
||||
#define MAINTENANCE_IN 0xa3
|
||||
#define MOVE_MEDIUM 0xa5
|
||||
#define EXCHANGE_MEDIUM 0xa6
|
||||
#define READ_12 0xa8
|
||||
#define WRITE_12 0xaa
|
||||
#define WRITE_VERIFY_12 0xae
|
||||
#define SEARCH_HIGH_12 0xb0
|
||||
#define SEARCH_EQUAL_12 0xb1
|
||||
#define SEARCH_LOW_12 0xb2
|
||||
#define READ_ELEMENT_STATUS 0xb8
|
||||
#define SEND_VOLUME_TAG 0xb6
|
||||
#define WRITE_LONG_2 0xea
|
||||
#define READ_16 0x88
|
||||
#define WRITE_16 0x8a
|
||||
#define VERIFY_16 0x8f
|
||||
#define SERVICE_ACTION_IN 0x9e
|
||||
/* values for service action in */
|
||||
#define SAI_READ_CAPACITY_16 0x10
|
||||
/* values for maintenance in */
|
||||
#define MI_REPORT_TARGET_PGS 0x0a
|
||||
|
||||
/* Values for T10/04-262r7 */
|
||||
#define ATA_16 0x85 /* 16-byte pass-thru */
|
||||
#define ATA_12 0xa1 /* 12-byte pass-thru */
|
||||
|
||||
/*
|
||||
* SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft
|
||||
* T10/1561-D Revision 4 Draft dated 7th November 2002.
|
||||
*/
|
||||
#define SAM_STAT_GOOD 0x00
|
||||
#define SAM_STAT_CHECK_CONDITION 0x02
|
||||
#define SAM_STAT_CONDITION_MET 0x04
|
||||
#define SAM_STAT_BUSY 0x08
|
||||
#define SAM_STAT_INTERMEDIATE 0x10
|
||||
#define SAM_STAT_INTERMEDIATE_CONDITION_MET 0x14
|
||||
#define SAM_STAT_RESERVATION_CONFLICT 0x18
|
||||
#define SAM_STAT_COMMAND_TERMINATED 0x22 /* obsolete in SAM-3 */
|
||||
#define SAM_STAT_TASK_SET_FULL 0x28
|
||||
#define SAM_STAT_ACA_ACTIVE 0x30
|
||||
#define SAM_STAT_TASK_ABORTED 0x40
|
||||
|
||||
/** scsi_status_is_good - check the status return.
|
||||
*
|
||||
* @status: the status passed up from the driver (including host and
|
||||
* driver components)
|
||||
*
|
||||
* This returns true for known good conditions that may be treated as
|
||||
* command completed normally
|
||||
*/
|
||||
static inline int scsi_status_is_good(int status)
|
||||
{
|
||||
/*
|
||||
* FIXME: bit0 is listed as reserved in SCSI-2, but is
|
||||
* significant in SCSI-3. For now, we follow the SCSI-2
|
||||
* behaviour and ignore reserved bits.
|
||||
*/
|
||||
status &= 0xfe;
|
||||
return ((status == SAM_STAT_GOOD) ||
|
||||
(status == SAM_STAT_INTERMEDIATE) ||
|
||||
(status == SAM_STAT_INTERMEDIATE_CONDITION_MET) ||
|
||||
/* FIXME: this is obsolete in SAM-3 */
|
||||
(status == SAM_STAT_COMMAND_TERMINATED));
|
||||
}
|
||||
|
||||
/*
|
||||
* Status codes. These are deprecated as they are shifted 1 bit right
|
||||
* from those found in the SCSI standards. This causes confusion for
|
||||
* applications that are ported to several OSes. Prefer SAM Status codes
|
||||
* above.
|
||||
*/
|
||||
|
||||
#define GOOD 0x00
|
||||
#define CHECK_CONDITION 0x01
|
||||
#define CONDITION_GOOD 0x02
|
||||
#define BUSY 0x04
|
||||
#define INTERMEDIATE_GOOD 0x08
|
||||
#define INTERMEDIATE_C_GOOD 0x0a
|
||||
#define RESERVATION_CONFLICT 0x0c
|
||||
#define COMMAND_TERMINATED 0x11
|
||||
#define QUEUE_FULL 0x14
|
||||
#define ACA_ACTIVE 0x18
|
||||
#define TASK_ABORTED 0x20
|
||||
|
||||
#define STATUS_MASK 0xfe
|
||||
|
||||
/*
|
||||
* SENSE KEYS
|
||||
*/
|
||||
|
||||
#define NO_SENSE 0x00
|
||||
#define RECOVERED_ERROR 0x01
|
||||
#define NOT_READY 0x02
|
||||
#define MEDIUM_ERROR 0x03
|
||||
#define HARDWARE_ERROR 0x04
|
||||
#define ILLEGAL_REQUEST 0x05
|
||||
#define UNIT_ATTENTION 0x06
|
||||
#define DATA_PROTECT 0x07
|
||||
#define BLANK_CHECK 0x08
|
||||
#define COPY_ABORTED 0x0a
|
||||
#define ABORTED_COMMAND 0x0b
|
||||
#define VOLUME_OVERFLOW 0x0d
|
||||
#define MISCOMPARE 0x0e
|
||||
|
||||
|
||||
/*
|
||||
* DEVICE TYPES
|
||||
*/
|
||||
|
||||
#define TYPE_DISK 0x00
|
||||
#define TYPE_TAPE 0x01
|
||||
#define TYPE_PRINTER 0x02
|
||||
#define TYPE_PROCESSOR 0x03 /* HP scanners use this */
|
||||
#define TYPE_WORM 0x04 /* Treated as ROM by our system */
|
||||
#define TYPE_ROM 0x05
|
||||
#define TYPE_SCANNER 0x06
|
||||
#define TYPE_MOD 0x07 /* Magneto-optical disk -
|
||||
* - treated as TYPE_DISK */
|
||||
#define TYPE_MEDIUM_CHANGER 0x08
|
||||
#define TYPE_COMM 0x09 /* Communications device */
|
||||
#define TYPE_RAID 0x0c
|
||||
#define TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */
|
||||
#define TYPE_RBC 0x0e
|
||||
#define TYPE_NO_LUN 0x7f
|
||||
|
||||
/* Returns a human-readable name for the device */
|
||||
extern const char * scsi_device_type(unsigned type);
|
||||
|
||||
/*
|
||||
* standard mode-select header prepended to all mode-select commands
|
||||
*/
|
||||
|
||||
struct ccs_modesel_head {
|
||||
__u8 _r1; /* reserved */
|
||||
__u8 medium; /* device-specific medium type */
|
||||
__u8 _r2; /* reserved */
|
||||
__u8 block_desc_length; /* block descriptor length */
|
||||
__u8 density; /* device-specific density code */
|
||||
__u8 number_blocks_hi; /* number of blocks in this block desc */
|
||||
__u8 number_blocks_med;
|
||||
__u8 number_blocks_lo;
|
||||
__u8 _r3;
|
||||
__u8 block_length_hi; /* block length for blocks in this desc */
|
||||
__u8 block_length_med;
|
||||
__u8 block_length_lo;
|
||||
};
|
||||
|
||||
/*
|
||||
* ScsiLun: 8 byte LUN.
|
||||
*/
|
||||
struct scsi_lun {
|
||||
__u8 scsi_lun[8];
|
||||
};
|
||||
|
||||
/*
|
||||
* MESSAGE CODES
|
||||
*/
|
||||
|
||||
#define COMMAND_COMPLETE 0x00
|
||||
#define EXTENDED_MESSAGE 0x01
|
||||
#define EXTENDED_MODIFY_DATA_POINTER 0x00
|
||||
#define EXTENDED_SDTR 0x01
|
||||
#define EXTENDED_EXTENDED_IDENTIFY 0x02 /* SCSI-I only */
|
||||
#define EXTENDED_WDTR 0x03
|
||||
#define EXTENDED_PPR 0x04
|
||||
#define EXTENDED_MODIFY_BIDI_DATA_PTR 0x05
|
||||
#define SAVE_POINTERS 0x02
|
||||
#define RESTORE_POINTERS 0x03
|
||||
#define DISCONNECT 0x04
|
||||
#define INITIATOR_ERROR 0x05
|
||||
#define ABORT_TASK_SET 0x06
|
||||
#define MESSAGE_REJECT 0x07
|
||||
#define NOP 0x08
|
||||
#define MSG_PARITY_ERROR 0x09
|
||||
#define LINKED_CMD_COMPLETE 0x0a
|
||||
#define LINKED_FLG_CMD_COMPLETE 0x0b
|
||||
#define TARGET_RESET 0x0c
|
||||
#define ABORT_TASK 0x0d
|
||||
#define CLEAR_TASK_SET 0x0e
|
||||
#define INITIATE_RECOVERY 0x0f /* SCSI-II only */
|
||||
#define RELEASE_RECOVERY 0x10 /* SCSI-II only */
|
||||
#define CLEAR_ACA 0x16
|
||||
#define LOGICAL_UNIT_RESET 0x17
|
||||
#define SIMPLE_QUEUE_TAG 0x20
|
||||
#define HEAD_OF_QUEUE_TAG 0x21
|
||||
#define ORDERED_QUEUE_TAG 0x22
|
||||
#define IGNORE_WIDE_RESIDUE 0x23
|
||||
#define ACA 0x24
|
||||
#define QAS_REQUEST 0x55
|
||||
|
||||
/* Old SCSI2 names, don't use in new code */
|
||||
#define BUS_DEVICE_RESET TARGET_RESET
|
||||
#define ABORT ABORT_TASK_SET
|
||||
|
||||
/*
|
||||
* Host byte codes
|
||||
*/
|
||||
|
||||
#define DID_OK 0x00 /* NO error */
|
||||
#define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */
|
||||
#define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */
|
||||
#define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */
|
||||
#define DID_BAD_TARGET 0x04 /* BAD target. */
|
||||
#define DID_ABORT 0x05 /* Told to abort for some other reason */
|
||||
#define DID_PARITY 0x06 /* Parity error */
|
||||
#define DID_ERROR 0x07 /* Internal error */
|
||||
#define DID_RESET 0x08 /* Reset by somebody. */
|
||||
#define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */
|
||||
#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer */
|
||||
#define DID_SOFT_ERROR 0x0b /* The low level driver just wish a retry */
|
||||
#define DID_IMM_RETRY 0x0c /* Retry without decrementing retry count */
|
||||
#define DID_REQUEUE 0x0d /* Requeue command (no immediate retry) also
|
||||
* without decrementing the retry count */
|
||||
#define DRIVER_OK 0x00 /* Driver status */
|
||||
|
||||
/*
|
||||
* These indicate the error that occurred, and what is available.
|
||||
*/
|
||||
|
||||
#define DRIVER_BUSY 0x01
|
||||
#define DRIVER_SOFT 0x02
|
||||
#define DRIVER_MEDIA 0x03
|
||||
#define DRIVER_ERROR 0x04
|
||||
|
||||
#define DRIVER_INVALID 0x05
|
||||
#define DRIVER_TIMEOUT 0x06
|
||||
#define DRIVER_HARD 0x07
|
||||
#define DRIVER_SENSE 0x08
|
||||
|
||||
#define SUGGEST_RETRY 0x10
|
||||
#define SUGGEST_ABORT 0x20
|
||||
#define SUGGEST_REMAP 0x30
|
||||
#define SUGGEST_DIE 0x40
|
||||
#define SUGGEST_SENSE 0x80
|
||||
#define SUGGEST_IS_OK 0xff
|
||||
|
||||
#define DRIVER_MASK 0x0f
|
||||
#define SUGGEST_MASK 0xf0
|
||||
|
||||
/*
|
||||
* Internal return values.
|
||||
*/
|
||||
|
||||
#define NEEDS_RETRY 0x2001
|
||||
#define SUCCESS 0x2002
|
||||
#define FAILED 0x2003
|
||||
#define QUEUED 0x2004
|
||||
#define SOFT_ERROR 0x2005
|
||||
#define ADD_TO_MLQUEUE 0x2006
|
||||
#define TIMEOUT_ERROR 0x2007
|
||||
|
||||
/*
|
||||
* Midlevel queue return values.
|
||||
*/
|
||||
#define SCSI_MLQUEUE_HOST_BUSY 0x1055
|
||||
#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056
|
||||
#define SCSI_MLQUEUE_EH_RETRY 0x1057
|
||||
|
||||
/*
|
||||
* Use these to separate status msg and our bytes
|
||||
*
|
||||
* These are set by:
|
||||
*
|
||||
* status byte = set from target device
|
||||
* msg_byte = return status from host adapter itself.
|
||||
* host_byte = set by low-level driver to indicate status.
|
||||
* driver_byte = set by mid-level.
|
||||
*/
|
||||
#define status_byte(result) (((result) >> 1) & 0x7f)
|
||||
#define msg_byte(result) (((result) >> 8) & 0xff)
|
||||
#define host_byte(result) (((result) >> 16) & 0xff)
|
||||
#define driver_byte(result) (((result) >> 24) & 0xff)
|
||||
#define suggestion(result) (driver_byte(result) & SUGGEST_MASK)
|
||||
|
||||
#define sense_class(sense) (((sense) >> 4) & 0x7)
|
||||
#define sense_error(sense) ((sense) & 0xf)
|
||||
#define sense_valid(sense) ((sense) & 0x80);
|
||||
|
||||
/*
|
||||
* default timeouts
|
||||
*/
|
||||
#define FORMAT_UNIT_TIMEOUT (2 * 60 * 60 * HZ)
|
||||
#define START_STOP_TIMEOUT (60 * HZ)
|
||||
#define MOVE_MEDIUM_TIMEOUT (5 * 60 * HZ)
|
||||
#define READ_ELEMENT_STATUS_TIMEOUT (5 * 60 * HZ)
|
||||
#define READ_DEFECT_DATA_TIMEOUT (60 * HZ )
|
||||
|
||||
|
||||
#define IDENTIFY_BASE 0x80
|
||||
#define IDENTIFY(can_disconnect, lun) (IDENTIFY_BASE |\
|
||||
((can_disconnect) ? 0x40 : 0) |\
|
||||
((lun) & 0x07))
|
||||
|
||||
/*
|
||||
* struct scsi_device::scsi_level values. For SCSI devices other than those
|
||||
* prior to SCSI-2 (i.e. over 12 years old) this value is (resp[2] + 1)
|
||||
* where "resp" is a byte array of the response to an INQUIRY. The scsi_level
|
||||
* variable is visible to the user via sysfs.
|
||||
*/
|
||||
|
||||
#define SCSI_UNKNOWN 0
|
||||
#define SCSI_1 1
|
||||
#define SCSI_1_CCS 2
|
||||
#define SCSI_2 3
|
||||
#define SCSI_3 4 /* SPC */
|
||||
#define SCSI_SPC_2 5
|
||||
#define SCSI_SPC_3 6
|
||||
|
||||
/*
|
||||
* INQ PERIPHERAL QUALIFIERS
|
||||
*/
|
||||
#define SCSI_INQ_PQ_CON 0x00
|
||||
#define SCSI_INQ_PQ_NOT_CON 0x01
|
||||
#define SCSI_INQ_PQ_NOT_CAP 0x03
|
||||
|
||||
|
||||
/*
|
||||
* Here are some scsi specific ioctl commands which are sometimes useful.
|
||||
*
|
||||
* Note that include/linux/cdrom.h also defines IOCTL 0x5300 - 0x5395
|
||||
*/
|
||||
|
||||
/* Used to obtain PUN and LUN info. Conflicts with CDROMAUDIOBUFSIZ */
|
||||
#define SCSI_IOCTL_GET_IDLUN 0x5382
|
||||
|
||||
/* 0x5383 and 0x5384 were used for SCSI_IOCTL_TAGGED_{ENABLE,DISABLE} */
|
||||
|
||||
/* Used to obtain the host number of a device. */
|
||||
#define SCSI_IOCTL_PROBE_HOST 0x5385
|
||||
|
||||
/* Used to obtain the bus number for a device */
|
||||
#define SCSI_IOCTL_GET_BUS_NUMBER 0x5386
|
||||
|
||||
/* Used to obtain the PCI location of a device */
|
||||
#define SCSI_IOCTL_GET_PCI 0x5387
|
||||
|
||||
/* Pull a u32 out of a SCSI message (using BE SCSI conventions) */
|
||||
static inline __u32 scsi_to_u32(__u8 *ptr)
|
||||
{
|
||||
return (ptr[0]<<24) + (ptr[1]<<16) + (ptr[2]<<8) + ptr[3];
|
||||
}
|
||||
|
||||
#endif /* _SCSI_SCSI_H */
|
||||
141
include/scsi/scsi_cmnd.h
Normal file
141
include/scsi/scsi_cmnd.h
Normal file
@@ -0,0 +1,141 @@
|
||||
#ifndef _SCSI_SCSI_CMND_H
|
||||
#define _SCSI_SCSI_CMND_H
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
struct request;
|
||||
struct scatterlist;
|
||||
struct Scsi_Host;
|
||||
struct scsi_device;
|
||||
|
||||
|
||||
/* embedded in scsi_cmnd */
|
||||
struct scsi_pointer {
|
||||
char *ptr; /* data pointer */
|
||||
int this_residual; /* left in this buffer */
|
||||
struct scatterlist *buffer; /* which buffer */
|
||||
int buffers_residual; /* how many buffers left */
|
||||
|
||||
dma_addr_t dma_handle;
|
||||
|
||||
volatile int Status;
|
||||
volatile int Message;
|
||||
volatile int have_data_in;
|
||||
volatile int sent_command;
|
||||
volatile int phase;
|
||||
};
|
||||
|
||||
struct scsi_cmnd {
|
||||
struct scsi_device *device;
|
||||
struct list_head list; /* scsi_cmnd participates in queue lists */
|
||||
struct list_head eh_entry; /* entry for the host eh_cmd_q */
|
||||
int eh_eflags; /* Used by error handlr */
|
||||
void (*done) (struct scsi_cmnd *); /* Mid-level done function */
|
||||
|
||||
/*
|
||||
* A SCSI Command is assigned a nonzero serial_number before passed
|
||||
* to the driver's queue command function. The serial_number is
|
||||
* cleared when scsi_done is entered indicating that the command
|
||||
* has been completed. It currently doesn't have much use other
|
||||
* than printk's. Some lldd's use this number for other purposes.
|
||||
* It's almost certain that such usages are either incorrect or
|
||||
* meaningless. Please kill all usages other than printk's. Also,
|
||||
* as this number is always identical to ->pid, please convert
|
||||
* printk's to use ->pid, so that we can kill this field.
|
||||
*/
|
||||
unsigned long serial_number;
|
||||
/*
|
||||
* This is set to jiffies as it was when the command was first
|
||||
* allocated. It is used to time how long the command has
|
||||
* been outstanding
|
||||
*/
|
||||
unsigned long jiffies_at_alloc;
|
||||
|
||||
int retries;
|
||||
int allowed;
|
||||
int timeout_per_command;
|
||||
|
||||
unsigned char cmd_len;
|
||||
enum dma_data_direction sc_data_direction;
|
||||
|
||||
/* These elements define the operation we are about to perform */
|
||||
#define MAX_COMMAND_SIZE 16
|
||||
unsigned char cmnd[MAX_COMMAND_SIZE];
|
||||
unsigned request_bufflen; /* Actual request size */
|
||||
|
||||
struct timer_list eh_timeout; /* Used to time out the command. */
|
||||
void *request_buffer; /* Actual requested buffer */
|
||||
|
||||
/* These elements define the operation we ultimately want to perform */
|
||||
unsigned short use_sg; /* Number of pieces of scatter-gather */
|
||||
unsigned short sglist_len; /* size of malloc'd scatter-gather list */
|
||||
|
||||
/* offset in cmd we are at (for multi-transfer tgt cmds) */
|
||||
unsigned offset;
|
||||
|
||||
unsigned underflow; /* Return error if less than
|
||||
this amount is transferred */
|
||||
|
||||
unsigned transfersize; /* How much we are guaranteed to
|
||||
transfer with each SCSI transfer
|
||||
(ie, between disconnect /
|
||||
reconnects. Probably == sector
|
||||
size */
|
||||
|
||||
int resid; /* Number of bytes requested to be
|
||||
transferred less actual number
|
||||
transferred (0 if not supported) */
|
||||
|
||||
struct request *request; /* The command we are
|
||||
working on */
|
||||
|
||||
#define SCSI_SENSE_BUFFERSIZE 96
|
||||
unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
|
||||
/* obtained by REQUEST SENSE when
|
||||
* CHECK CONDITION is received on original
|
||||
* command (auto-sense) */
|
||||
|
||||
/* Low-level done function - can be used by low-level driver to point
|
||||
* to completion function. Not used by mid/upper level code. */
|
||||
void (*scsi_done) (struct scsi_cmnd *);
|
||||
|
||||
/*
|
||||
* The following fields can be written to by the host specific code.
|
||||
* Everything else should be left alone.
|
||||
*/
|
||||
struct scsi_pointer SCp; /* Scratchpad used by some host adapters */
|
||||
|
||||
unsigned char *host_scribble; /* The host adapter is allowed to
|
||||
* call scsi_malloc and get some memory
|
||||
* and hang it here. The host adapter
|
||||
* is also expected to call scsi_free
|
||||
* to release this memory. (The memory
|
||||
* obtained by scsi_malloc is guaranteed
|
||||
* to be at an address < 16Mb). */
|
||||
|
||||
int result; /* Status code from lower level driver */
|
||||
|
||||
unsigned char tag; /* SCSI-II queued command tag */
|
||||
unsigned long pid; /* Process ID, starts at 0. Unique per host. */
|
||||
};
|
||||
|
||||
extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t);
|
||||
extern struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *, gfp_t);
|
||||
extern void scsi_put_command(struct scsi_cmnd *);
|
||||
extern void __scsi_put_command(struct Scsi_Host *, struct scsi_cmnd *,
|
||||
struct device *);
|
||||
extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
|
||||
extern void scsi_finish_command(struct scsi_cmnd *cmd);
|
||||
extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd);
|
||||
|
||||
extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
|
||||
size_t *offset, size_t *len);
|
||||
extern void scsi_kunmap_atomic_sg(void *virt);
|
||||
|
||||
extern struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *, gfp_t);
|
||||
extern void scsi_free_sgtable(struct scatterlist *, int);
|
||||
|
||||
#endif /* _SCSI_SCSI_CMND_H */
|
||||
20
include/scsi/scsi_dbg.h
Normal file
20
include/scsi/scsi_dbg.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef _SCSI_SCSI_DBG_H
|
||||
#define _SCSI_SCSI_DBG_H
|
||||
|
||||
struct scsi_cmnd;
|
||||
struct scsi_sense_hdr;
|
||||
|
||||
extern void scsi_print_command(struct scsi_cmnd *);
|
||||
extern void scsi_print_sense_hdr(const char *, struct scsi_sense_hdr *);
|
||||
extern void __scsi_print_command(unsigned char *);
|
||||
extern void scsi_print_sense(const char *, struct scsi_cmnd *);
|
||||
extern void __scsi_print_sense(const char *name,
|
||||
const unsigned char *sense_buffer,
|
||||
int sense_len);
|
||||
extern void scsi_print_driverbyte(int);
|
||||
extern void scsi_print_hostbyte(int);
|
||||
extern void scsi_print_status(unsigned char);
|
||||
extern const char *scsi_sense_key_string(unsigned char);
|
||||
extern const char *scsi_extd_sense_format(unsigned char, unsigned char);
|
||||
|
||||
#endif /* _SCSI_SCSI_DBG_H */
|
||||
356
include/scsi/scsi_device.h
Normal file
356
include/scsi/scsi_device.h
Normal file
@@ -0,0 +1,356 @@
|
||||
#ifndef _SCSI_SCSI_DEVICE_H
|
||||
#define _SCSI_SCSI_DEVICE_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
struct request_queue;
|
||||
struct scsi_cmnd;
|
||||
struct scsi_lun;
|
||||
struct scsi_sense_hdr;
|
||||
|
||||
struct scsi_mode_data {
|
||||
__u32 length;
|
||||
__u16 block_descriptor_length;
|
||||
__u8 medium_type;
|
||||
__u8 device_specific;
|
||||
__u8 header_length;
|
||||
__u8 longlba:1;
|
||||
};
|
||||
|
||||
/*
|
||||
* sdev state: If you alter this, you also need to alter scsi_sysfs.c
|
||||
* (for the ascii descriptions) and the state model enforcer:
|
||||
* scsi_lib:scsi_device_set_state().
|
||||
*/
|
||||
enum scsi_device_state {
|
||||
SDEV_CREATED = 1, /* device created but not added to sysfs
|
||||
* Only internal commands allowed (for inq) */
|
||||
SDEV_RUNNING, /* device properly configured
|
||||
* All commands allowed */
|
||||
SDEV_CANCEL, /* beginning to delete device
|
||||
* Only error handler commands allowed */
|
||||
SDEV_DEL, /* device deleted
|
||||
* no commands allowed */
|
||||
SDEV_QUIESCE, /* Device quiescent. No block commands
|
||||
* will be accepted, only specials (which
|
||||
* originate in the mid-layer) */
|
||||
SDEV_OFFLINE, /* Device offlined (by error handling or
|
||||
* user request */
|
||||
SDEV_BLOCK, /* Device blocked by scsi lld. No scsi
|
||||
* commands from user or midlayer should be issued
|
||||
* to the scsi lld. */
|
||||
};
|
||||
|
||||
struct scsi_device {
|
||||
struct Scsi_Host *host;
|
||||
struct request_queue *request_queue;
|
||||
|
||||
/* the next two are protected by the host->host_lock */
|
||||
struct list_head siblings; /* list of all devices on this host */
|
||||
struct list_head same_target_siblings; /* just the devices sharing same target id */
|
||||
|
||||
/* this is now protected by the request_queue->queue_lock */
|
||||
unsigned int device_busy; /* commands actually active on
|
||||
* low-level. protected by queue_lock. */
|
||||
spinlock_t list_lock;
|
||||
struct list_head cmd_list; /* queue of in use SCSI Command structures */
|
||||
struct list_head starved_entry;
|
||||
struct scsi_cmnd *current_cmnd; /* currently active command */
|
||||
unsigned short queue_depth; /* How deep of a queue we want */
|
||||
unsigned short last_queue_full_depth; /* These two are used by */
|
||||
unsigned short last_queue_full_count; /* scsi_track_queue_full() */
|
||||
unsigned long last_queue_full_time;/* don't let QUEUE_FULLs on the same
|
||||
jiffie count on our counter, they
|
||||
could all be from the same event. */
|
||||
|
||||
unsigned int id, lun, channel;
|
||||
|
||||
unsigned int manufacturer; /* Manufacturer of device, for using
|
||||
* vendor-specific cmd's */
|
||||
unsigned sector_size; /* size in bytes */
|
||||
|
||||
void *hostdata; /* available to low-level driver */
|
||||
char type;
|
||||
char scsi_level;
|
||||
char inq_periph_qual; /* PQ from INQUIRY data */
|
||||
unsigned char inquiry_len; /* valid bytes in 'inquiry' */
|
||||
unsigned char * inquiry; /* INQUIRY response data */
|
||||
const char * vendor; /* [back_compat] point into 'inquiry' ... */
|
||||
const char * model; /* ... after scan; point to static string */
|
||||
const char * rev; /* ... "nullnullnullnull" before scan */
|
||||
unsigned char current_tag; /* current tag */
|
||||
struct scsi_target *sdev_target; /* used only for single_lun */
|
||||
|
||||
unsigned int sdev_bflags; /* black/white flags as also found in
|
||||
* scsi_devinfo.[hc]. For now used only to
|
||||
* pass settings from slave_alloc to scsi
|
||||
* core. */
|
||||
unsigned writeable:1;
|
||||
unsigned removable:1;
|
||||
unsigned changed:1; /* Data invalid due to media change */
|
||||
unsigned busy:1; /* Used to prevent races */
|
||||
unsigned lockable:1; /* Able to prevent media removal */
|
||||
unsigned locked:1; /* Media removal disabled */
|
||||
unsigned borken:1; /* Tell the Seagate driver to be
|
||||
* painfully slow on this device */
|
||||
unsigned disconnect:1; /* can disconnect */
|
||||
unsigned soft_reset:1; /* Uses soft reset option */
|
||||
unsigned sdtr:1; /* Device supports SDTR messages */
|
||||
unsigned wdtr:1; /* Device supports WDTR messages */
|
||||
unsigned ppr:1; /* Device supports PPR messages */
|
||||
unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */
|
||||
unsigned simple_tags:1; /* simple queue tag messages are enabled */
|
||||
unsigned ordered_tags:1;/* ordered queue tag messages are enabled */
|
||||
unsigned single_lun:1; /* Indicates we should only allow I/O to
|
||||
* one of the luns for the device at a
|
||||
* time. */
|
||||
unsigned was_reset:1; /* There was a bus reset on the bus for
|
||||
* this device */
|
||||
unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN
|
||||
* because we did a bus reset. */
|
||||
unsigned use_10_for_rw:1; /* first try 10-byte read / write */
|
||||
unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */
|
||||
unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */
|
||||
unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */
|
||||
unsigned use_192_bytes_for_3f:1; /* ask for 192 bytes from page 0x3f */
|
||||
unsigned no_start_on_add:1; /* do not issue start on add */
|
||||
unsigned allow_restart:1; /* issue START_UNIT in error handler */
|
||||
unsigned no_uld_attach:1; /* disable connecting to upper level drivers */
|
||||
unsigned select_no_atn:1;
|
||||
unsigned fix_capacity:1; /* READ_CAPACITY is too high by 1 */
|
||||
unsigned guess_capacity:1; /* READ_CAPACITY might be too high by 1 */
|
||||
unsigned retry_hwerror:1; /* Retry HARDWARE_ERROR */
|
||||
|
||||
unsigned int device_blocked; /* Device returned QUEUE_FULL. */
|
||||
|
||||
unsigned int max_device_blocked; /* what device_blocked counts down from */
|
||||
#define SCSI_DEFAULT_DEVICE_BLOCKED 3
|
||||
|
||||
atomic_t iorequest_cnt;
|
||||
atomic_t iodone_cnt;
|
||||
atomic_t ioerr_cnt;
|
||||
|
||||
int timeout;
|
||||
|
||||
struct device sdev_gendev;
|
||||
struct class_device sdev_classdev;
|
||||
|
||||
struct execute_work ew; /* used to get process context on put */
|
||||
|
||||
enum scsi_device_state sdev_state;
|
||||
unsigned long sdev_data[0];
|
||||
} __attribute__((aligned(sizeof(unsigned long))));
|
||||
#define to_scsi_device(d) \
|
||||
container_of(d, struct scsi_device, sdev_gendev)
|
||||
#define class_to_sdev(d) \
|
||||
container_of(d, struct scsi_device, sdev_classdev)
|
||||
#define transport_class_to_sdev(class_dev) \
|
||||
to_scsi_device(class_dev->dev)
|
||||
|
||||
#define sdev_printk(prefix, sdev, fmt, a...) \
|
||||
dev_printk(prefix, &(sdev)->sdev_gendev, fmt, ##a)
|
||||
|
||||
#define scmd_printk(prefix, scmd, fmt, a...) \
|
||||
dev_printk(prefix, &(scmd)->device->sdev_gendev, fmt, ##a)
|
||||
|
||||
enum scsi_target_state {
|
||||
STARGET_RUNNING = 1,
|
||||
STARGET_DEL,
|
||||
};
|
||||
|
||||
/*
|
||||
* scsi_target: representation of a scsi target, for now, this is only
|
||||
* used for single_lun devices. If no one has active IO to the target,
|
||||
* starget_sdev_user is NULL, else it points to the active sdev.
|
||||
*/
|
||||
struct scsi_target {
|
||||
struct scsi_device *starget_sdev_user;
|
||||
struct list_head siblings;
|
||||
struct list_head devices;
|
||||
struct device dev;
|
||||
unsigned int reap_ref; /* protected by the host lock */
|
||||
unsigned int channel;
|
||||
unsigned int id; /* target id ... replace
|
||||
* scsi_device.id eventually */
|
||||
unsigned int create:1; /* signal that it needs to be added */
|
||||
unsigned int pdt_1f_for_no_lun; /* PDT = 0x1f */
|
||||
/* means no lun present */
|
||||
|
||||
char scsi_level;
|
||||
struct execute_work ew;
|
||||
enum scsi_target_state state;
|
||||
void *hostdata; /* available to low-level driver */
|
||||
unsigned long starget_data[0]; /* for the transport */
|
||||
/* starget_data must be the last element!!!! */
|
||||
} __attribute__((aligned(sizeof(unsigned long))));
|
||||
|
||||
#define to_scsi_target(d) container_of(d, struct scsi_target, dev)
|
||||
static inline struct scsi_target *scsi_target(struct scsi_device *sdev)
|
||||
{
|
||||
return to_scsi_target(sdev->sdev_gendev.parent);
|
||||
}
|
||||
#define transport_class_to_starget(class_dev) \
|
||||
to_scsi_target(class_dev->dev)
|
||||
|
||||
#define starget_printk(prefix, starget, fmt, a...) \
|
||||
dev_printk(prefix, &(starget)->dev, fmt, ##a)
|
||||
|
||||
extern struct scsi_device *__scsi_add_device(struct Scsi_Host *,
|
||||
uint, uint, uint, void *hostdata);
|
||||
extern int scsi_add_device(struct Scsi_Host *host, uint channel,
|
||||
uint target, uint lun);
|
||||
extern void scsi_remove_device(struct scsi_device *);
|
||||
extern int scsi_device_cancel(struct scsi_device *, int);
|
||||
|
||||
extern int scsi_device_get(struct scsi_device *);
|
||||
extern void scsi_device_put(struct scsi_device *);
|
||||
extern struct scsi_device *scsi_device_lookup(struct Scsi_Host *,
|
||||
uint, uint, uint);
|
||||
extern struct scsi_device *__scsi_device_lookup(struct Scsi_Host *,
|
||||
uint, uint, uint);
|
||||
extern struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *,
|
||||
uint);
|
||||
extern struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *,
|
||||
uint);
|
||||
extern void starget_for_each_device(struct scsi_target *, void *,
|
||||
void (*fn)(struct scsi_device *, void *));
|
||||
|
||||
/* only exposed to implement shost_for_each_device */
|
||||
extern struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *,
|
||||
struct scsi_device *);
|
||||
|
||||
/**
|
||||
* shost_for_each_device - iterate over all devices of a host
|
||||
* @sdev: the &struct scsi_device to use as a cursor
|
||||
* @shost: the &struct scsi_host to iterate over
|
||||
*
|
||||
* Iterator that returns each device attached to @shost. This loop
|
||||
* takes a reference on each device and releases it at the end. If
|
||||
* you break out of the loop, you must call scsi_device_put(sdev).
|
||||
*/
|
||||
#define shost_for_each_device(sdev, shost) \
|
||||
for ((sdev) = __scsi_iterate_devices((shost), NULL); \
|
||||
(sdev); \
|
||||
(sdev) = __scsi_iterate_devices((shost), (sdev)))
|
||||
|
||||
/**
|
||||
* __shost_for_each_device - iterate over all devices of a host (UNLOCKED)
|
||||
* @sdev: the &struct scsi_device to use as a cursor
|
||||
* @shost: the &struct scsi_host to iterate over
|
||||
*
|
||||
* Iterator that returns each device attached to @shost. It does _not_
|
||||
* take a reference on the scsi_device, so the whole loop must be
|
||||
* protected by shost->host_lock.
|
||||
*
|
||||
* Note: The only reason to use this is because you need to access the
|
||||
* device list in interrupt context. Otherwise you really want to use
|
||||
* shost_for_each_device instead.
|
||||
*/
|
||||
#define __shost_for_each_device(sdev, shost) \
|
||||
list_for_each_entry((sdev), &((shost)->__devices), siblings)
|
||||
|
||||
extern void scsi_adjust_queue_depth(struct scsi_device *, int, int);
|
||||
extern int scsi_track_queue_full(struct scsi_device *, int);
|
||||
|
||||
extern int scsi_set_medium_removal(struct scsi_device *, char);
|
||||
|
||||
extern int scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
|
||||
unsigned char *buffer, int len, int timeout,
|
||||
int retries, struct scsi_mode_data *data,
|
||||
struct scsi_sense_hdr *);
|
||||
extern int scsi_mode_select(struct scsi_device *sdev, int pf, int sp,
|
||||
int modepage, unsigned char *buffer, int len,
|
||||
int timeout, int retries,
|
||||
struct scsi_mode_data *data,
|
||||
struct scsi_sense_hdr *);
|
||||
extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout,
|
||||
int retries);
|
||||
extern int scsi_device_set_state(struct scsi_device *sdev,
|
||||
enum scsi_device_state state);
|
||||
extern int scsi_device_quiesce(struct scsi_device *sdev);
|
||||
extern void scsi_device_resume(struct scsi_device *sdev);
|
||||
extern void scsi_target_quiesce(struct scsi_target *);
|
||||
extern void scsi_target_resume(struct scsi_target *);
|
||||
extern void scsi_scan_target(struct device *parent, unsigned int channel,
|
||||
unsigned int id, unsigned int lun, int rescan);
|
||||
extern void scsi_target_reap(struct scsi_target *);
|
||||
extern void scsi_target_block(struct device *);
|
||||
extern void scsi_target_unblock(struct device *);
|
||||
extern void scsi_remove_target(struct device *);
|
||||
extern void int_to_scsilun(unsigned int, struct scsi_lun *);
|
||||
extern const char *scsi_device_state_name(enum scsi_device_state);
|
||||
extern int scsi_is_sdev_device(const struct device *);
|
||||
extern int scsi_is_target_device(const struct device *);
|
||||
extern int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
|
||||
int data_direction, void *buffer, unsigned bufflen,
|
||||
unsigned char *sense, int timeout, int retries,
|
||||
int flag);
|
||||
extern int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd,
|
||||
int data_direction, void *buffer, unsigned bufflen,
|
||||
struct scsi_sense_hdr *, int timeout, int retries);
|
||||
extern int scsi_execute_async(struct scsi_device *sdev,
|
||||
const unsigned char *cmd, int cmd_len, int data_direction,
|
||||
void *buffer, unsigned bufflen, int use_sg,
|
||||
int timeout, int retries, void *privdata,
|
||||
void (*done)(void *, char *, int, int),
|
||||
gfp_t gfp);
|
||||
|
||||
static inline int __must_check scsi_device_reprobe(struct scsi_device *sdev)
|
||||
{
|
||||
return device_reprobe(&sdev->sdev_gendev);
|
||||
}
|
||||
|
||||
static inline unsigned int sdev_channel(struct scsi_device *sdev)
|
||||
{
|
||||
return sdev->channel;
|
||||
}
|
||||
|
||||
static inline unsigned int sdev_id(struct scsi_device *sdev)
|
||||
{
|
||||
return sdev->id;
|
||||
}
|
||||
|
||||
#define scmd_id(scmd) sdev_id((scmd)->device)
|
||||
#define scmd_channel(scmd) sdev_channel((scmd)->device)
|
||||
|
||||
static inline int scsi_device_online(struct scsi_device *sdev)
|
||||
{
|
||||
return sdev->sdev_state != SDEV_OFFLINE;
|
||||
}
|
||||
|
||||
/* accessor functions for the SCSI parameters */
|
||||
static inline int scsi_device_sync(struct scsi_device *sdev)
|
||||
{
|
||||
return sdev->sdtr;
|
||||
}
|
||||
static inline int scsi_device_wide(struct scsi_device *sdev)
|
||||
{
|
||||
return sdev->wdtr;
|
||||
}
|
||||
static inline int scsi_device_dt(struct scsi_device *sdev)
|
||||
{
|
||||
return sdev->ppr;
|
||||
}
|
||||
static inline int scsi_device_dt_only(struct scsi_device *sdev)
|
||||
{
|
||||
if (sdev->inquiry_len < 57)
|
||||
return 0;
|
||||
return (sdev->inquiry[56] & 0x0c) == 0x04;
|
||||
}
|
||||
static inline int scsi_device_ius(struct scsi_device *sdev)
|
||||
{
|
||||
if (sdev->inquiry_len < 57)
|
||||
return 0;
|
||||
return sdev->inquiry[56] & 0x01;
|
||||
}
|
||||
static inline int scsi_device_qas(struct scsi_device *sdev)
|
||||
{
|
||||
if (sdev->inquiry_len < 57)
|
||||
return 0;
|
||||
return sdev->inquiry[56] & 0x02;
|
||||
}
|
||||
#endif /* _SCSI_SCSI_DEVICE_H */
|
||||
33
include/scsi/scsi_devinfo.h
Normal file
33
include/scsi/scsi_devinfo.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef _SCSI_SCSI_DEVINFO_H
|
||||
#define _SCSI_SCSI_DEVINFO_H
|
||||
/*
|
||||
* Flags for SCSI devices that need special treatment
|
||||
*/
|
||||
#define BLIST_NOLUN 0x001 /* Only scan LUN 0 */
|
||||
#define BLIST_FORCELUN 0x002 /* Known to have LUNs, force scanning,
|
||||
deprecated: Use max_luns=N */
|
||||
#define BLIST_BORKEN 0x004 /* Flag for broken handshaking */
|
||||
#define BLIST_KEY 0x008 /* unlock by special command */
|
||||
#define BLIST_SINGLELUN 0x010 /* Do not use LUNs in parallel */
|
||||
#define BLIST_NOTQ 0x020 /* Buggy Tagged Command Queuing */
|
||||
#define BLIST_SPARSELUN 0x040 /* Non consecutive LUN numbering */
|
||||
#define BLIST_MAX5LUN 0x080 /* Avoid LUNS >= 5 */
|
||||
#define BLIST_ISROM 0x100 /* Treat as (removable) CD-ROM */
|
||||
#define BLIST_LARGELUN 0x200 /* LUNs past 7 on a SCSI-2 device */
|
||||
#define BLIST_INQUIRY_36 0x400 /* override additional length field */
|
||||
#define BLIST_INQUIRY_58 0x800 /* ... for broken inquiry responses */
|
||||
#define BLIST_NOSTARTONADD 0x1000 /* do not do automatic start on add */
|
||||
#define BLIST_MS_SKIP_PAGE_08 0x2000 /* do not send ms page 0x08 */
|
||||
#define BLIST_MS_SKIP_PAGE_3F 0x4000 /* do not send ms page 0x3f */
|
||||
#define BLIST_USE_10_BYTE_MS 0x8000 /* use 10 byte ms before 6 byte ms */
|
||||
#define BLIST_MS_192_BYTES_FOR_3F 0x10000 /* 192 byte ms page 0x3f request */
|
||||
#define BLIST_REPORTLUN2 0x20000 /* try REPORT_LUNS even for SCSI-2 devs
|
||||
(if HBA supports more than 8 LUNs) */
|
||||
#define BLIST_NOREPORTLUN 0x40000 /* don't try REPORT_LUNS scan (SCSI-3 devs) */
|
||||
#define BLIST_NOT_LOCKABLE 0x80000 /* don't use PREVENT-ALLOW commands */
|
||||
#define BLIST_NO_ULD_ATTACH 0x100000 /* device is actually for RAID config */
|
||||
#define BLIST_SELECT_NO_ATN 0x200000 /* select without ATN */
|
||||
#define BLIST_RETRY_HWERROR 0x400000 /* retry HARDWARE_ERROR */
|
||||
#define BLIST_MAX_512 0x800000 /* maximum 512 sector cdb length */
|
||||
#define BLIST_ATTACH_PQ3 0x1000000 /* Scan: Attach to PQ3 devices */
|
||||
#endif
|
||||
30
include/scsi/scsi_driver.h
Normal file
30
include/scsi/scsi_driver.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef _SCSI_SCSI_DRIVER_H
|
||||
#define _SCSI_SCSI_DRIVER_H
|
||||
|
||||
#include <linux/device.h>
|
||||
|
||||
struct module;
|
||||
struct scsi_cmnd;
|
||||
|
||||
|
||||
struct scsi_driver {
|
||||
struct module *owner;
|
||||
struct device_driver gendrv;
|
||||
|
||||
int (*init_command)(struct scsi_cmnd *);
|
||||
void (*rescan)(struct device *);
|
||||
int (*issue_flush)(struct device *, sector_t *);
|
||||
int (*prepare_flush)(struct request_queue *, struct request *);
|
||||
};
|
||||
#define to_scsi_driver(drv) \
|
||||
container_of((drv), struct scsi_driver, gendrv)
|
||||
|
||||
extern int scsi_register_driver(struct device_driver *);
|
||||
#define scsi_unregister_driver(drv) \
|
||||
driver_unregister(drv);
|
||||
|
||||
extern int scsi_register_interface(struct class_interface *);
|
||||
#define scsi_unregister_interface(intf) \
|
||||
class_interface_unregister(intf)
|
||||
|
||||
#endif /* _SCSI_SCSI_DRIVER_H */
|
||||
68
include/scsi/scsi_eh.h
Normal file
68
include/scsi/scsi_eh.h
Normal file
@@ -0,0 +1,68 @@
|
||||
#ifndef _SCSI_SCSI_EH_H
|
||||
#define _SCSI_SCSI_EH_H
|
||||
|
||||
struct scsi_cmnd;
|
||||
struct scsi_device;
|
||||
struct Scsi_Host;
|
||||
|
||||
/*
|
||||
* This is a slightly modified SCSI sense "descriptor" format header.
|
||||
* The addition is to allow the 0x70 and 0x71 response codes. The idea
|
||||
* is to place the salient data from either "fixed" or "descriptor" sense
|
||||
* format into one structure to ease application processing.
|
||||
*
|
||||
* The original sense buffer should be kept around for those cases
|
||||
* in which more information is required (e.g. the LBA of a MEDIUM ERROR).
|
||||
*/
|
||||
struct scsi_sense_hdr { /* See SPC-3 section 4.5 */
|
||||
u8 response_code; /* permit: 0x0, 0x70, 0x71, 0x72, 0x73 */
|
||||
u8 sense_key;
|
||||
u8 asc;
|
||||
u8 ascq;
|
||||
u8 byte4;
|
||||
u8 byte5;
|
||||
u8 byte6;
|
||||
u8 additional_length; /* always 0 for fixed sense format */
|
||||
};
|
||||
|
||||
static inline int scsi_sense_valid(struct scsi_sense_hdr *sshdr)
|
||||
{
|
||||
if (!sshdr)
|
||||
return 0;
|
||||
|
||||
return (sshdr->response_code & 0x70) == 0x70;
|
||||
}
|
||||
|
||||
|
||||
extern void scsi_eh_finish_cmd(struct scsi_cmnd *scmd,
|
||||
struct list_head *done_q);
|
||||
extern void scsi_eh_flush_done_q(struct list_head *done_q);
|
||||
extern void scsi_report_bus_reset(struct Scsi_Host *, int);
|
||||
extern void scsi_report_device_reset(struct Scsi_Host *, int, int);
|
||||
extern int scsi_block_when_processing_errors(struct scsi_device *);
|
||||
extern int scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
|
||||
struct scsi_sense_hdr *sshdr);
|
||||
extern int scsi_command_normalize_sense(struct scsi_cmnd *cmd,
|
||||
struct scsi_sense_hdr *sshdr);
|
||||
|
||||
static inline int scsi_sense_is_deferred(struct scsi_sense_hdr *sshdr)
|
||||
{
|
||||
return ((sshdr->response_code >= 0x70) && (sshdr->response_code & 1));
|
||||
}
|
||||
|
||||
extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
|
||||
int desc_type);
|
||||
|
||||
extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len,
|
||||
u64 * info_out);
|
||||
|
||||
/*
|
||||
* Reset request from external source
|
||||
*/
|
||||
#define SCSI_TRY_RESET_DEVICE 1
|
||||
#define SCSI_TRY_RESET_BUS 2
|
||||
#define SCSI_TRY_RESET_HOST 3
|
||||
|
||||
extern int scsi_reset_provider(struct scsi_device *, int);
|
||||
|
||||
#endif /* _SCSI_SCSI_EH_H */
|
||||
748
include/scsi/scsi_host.h
Normal file
748
include/scsi/scsi_host.h
Normal file
@@ -0,0 +1,748 @@
|
||||
#ifndef _SCSI_SCSI_HOST_H
|
||||
#define _SCSI_SCSI_HOST_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
struct request_queue;
|
||||
struct block_device;
|
||||
struct completion;
|
||||
struct module;
|
||||
struct scsi_cmnd;
|
||||
struct scsi_device;
|
||||
struct scsi_target;
|
||||
struct Scsi_Host;
|
||||
struct scsi_host_cmd_pool;
|
||||
struct scsi_transport_template;
|
||||
struct blk_queue_tags;
|
||||
|
||||
|
||||
/*
|
||||
* The various choices mean:
|
||||
* NONE: Self evident. Host adapter is not capable of scatter-gather.
|
||||
* ALL: Means that the host adapter module can do scatter-gather,
|
||||
* and that there is no limit to the size of the table to which
|
||||
* we scatter/gather data.
|
||||
* Anything else: Indicates the maximum number of chains that can be
|
||||
* used in one scatter-gather request.
|
||||
*/
|
||||
#define SG_NONE 0
|
||||
#define SG_ALL 0xff
|
||||
|
||||
|
||||
#define DISABLE_CLUSTERING 0
|
||||
#define ENABLE_CLUSTERING 1
|
||||
|
||||
enum scsi_eh_timer_return {
|
||||
EH_NOT_HANDLED,
|
||||
EH_HANDLED,
|
||||
EH_RESET_TIMER,
|
||||
};
|
||||
|
||||
|
||||
struct scsi_host_template {
|
||||
struct module *module;
|
||||
const char *name;
|
||||
|
||||
/*
|
||||
* Used to initialize old-style drivers. For new-style drivers
|
||||
* just perform all work in your module initialization function.
|
||||
*
|
||||
* Status: OBSOLETE
|
||||
*/
|
||||
int (* detect)(struct scsi_host_template *);
|
||||
|
||||
/*
|
||||
* Used as unload callback for hosts with old-style drivers.
|
||||
*
|
||||
* Status: OBSOLETE
|
||||
*/
|
||||
int (* release)(struct Scsi_Host *);
|
||||
|
||||
/*
|
||||
* The info function will return whatever useful information the
|
||||
* developer sees fit. If not provided, then the name field will
|
||||
* be used instead.
|
||||
*
|
||||
* Status: OPTIONAL
|
||||
*/
|
||||
const char *(* info)(struct Scsi_Host *);
|
||||
|
||||
/*
|
||||
* Ioctl interface
|
||||
*
|
||||
* Status: OPTIONAL
|
||||
*/
|
||||
int (* ioctl)(struct scsi_device *dev, int cmd, void __user *arg);
|
||||
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
/*
|
||||
* Compat handler. Handle 32bit ABI.
|
||||
* When unknown ioctl is passed return -ENOIOCTLCMD.
|
||||
*
|
||||
* Status: OPTIONAL
|
||||
*/
|
||||
int (* compat_ioctl)(struct scsi_device *dev, int cmd, void __user *arg);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The queuecommand function is used to queue up a scsi
|
||||
* command block to the LLDD. When the driver finished
|
||||
* processing the command the done callback is invoked.
|
||||
*
|
||||
* If queuecommand returns 0, then the HBA has accepted the
|
||||
* command. The done() function must be called on the command
|
||||
* when the driver has finished with it. (you may call done on the
|
||||
* command before queuecommand returns, but in this case you
|
||||
* *must* return 0 from queuecommand).
|
||||
*
|
||||
* Queuecommand may also reject the command, in which case it may
|
||||
* not touch the command and must not call done() for it.
|
||||
*
|
||||
* There are two possible rejection returns:
|
||||
*
|
||||
* SCSI_MLQUEUE_DEVICE_BUSY: Block this device temporarily, but
|
||||
* allow commands to other devices serviced by this host.
|
||||
*
|
||||
* SCSI_MLQUEUE_HOST_BUSY: Block all devices served by this
|
||||
* host temporarily.
|
||||
*
|
||||
* For compatibility, any other non-zero return is treated the
|
||||
* same as SCSI_MLQUEUE_HOST_BUSY.
|
||||
*
|
||||
* NOTE: "temporarily" means either until the next command for#
|
||||
* this device/host completes, or a period of time determined by
|
||||
* I/O pressure in the system if there are no other outstanding
|
||||
* commands.
|
||||
*
|
||||
* STATUS: REQUIRED
|
||||
*/
|
||||
int (* queuecommand)(struct scsi_cmnd *,
|
||||
void (*done)(struct scsi_cmnd *));
|
||||
|
||||
/*
|
||||
* The transfer functions are used to queue a scsi command to
|
||||
* the LLD. When the driver is finished processing the command
|
||||
* the done callback is invoked.
|
||||
*
|
||||
* return values: see queuecommand
|
||||
*
|
||||
* If the LLD accepts the cmd, it should set the result to an
|
||||
* appropriate value when completed before calling the done function.
|
||||
*
|
||||
* STATUS: REQUIRED FOR TARGET DRIVERS
|
||||
*/
|
||||
/* TODO: rename */
|
||||
int (* transfer_response)(struct scsi_cmnd *,
|
||||
void (*done)(struct scsi_cmnd *));
|
||||
/*
|
||||
* This is called to inform the LLD to transfer cmd->request_bufflen
|
||||
* bytes of the cmd at cmd->offset in the cmd. The cmd->use_sg
|
||||
* speciefies the number of scatterlist entried in the command
|
||||
* and cmd->request_buffer contains the scatterlist.
|
||||
*
|
||||
* If the command cannot be processed in one transfer_data call
|
||||
* becuase a scatterlist within the LLD's limits cannot be
|
||||
* created then transfer_data will be called multiple times.
|
||||
* It is initially called from process context, and later
|
||||
* calls are from the interrup context.
|
||||
*/
|
||||
int (* transfer_data)(struct scsi_cmnd *,
|
||||
void (*done)(struct scsi_cmnd *));
|
||||
|
||||
/* Used as callback for the completion of task management request. */
|
||||
int (* tsk_mgmt_response)(u64 mid, int result);
|
||||
|
||||
/*
|
||||
* This is an error handling strategy routine. You don't need to
|
||||
* define one of these if you don't want to - there is a default
|
||||
* routine that is present that should work in most cases. For those
|
||||
* driver authors that have the inclination and ability to write their
|
||||
* own strategy routine, this is where it is specified. Note - the
|
||||
* strategy routine is *ALWAYS* run in the context of the kernel eh
|
||||
* thread. Thus you are guaranteed to *NOT* be in an interrupt
|
||||
* handler when you execute this, and you are also guaranteed to
|
||||
* *NOT* have any other commands being queued while you are in the
|
||||
* strategy routine. When you return from this function, operations
|
||||
* return to normal.
|
||||
*
|
||||
* See scsi_error.c scsi_unjam_host for additional comments about
|
||||
* what this function should and should not be attempting to do.
|
||||
*
|
||||
* Status: REQUIRED (at least one of them)
|
||||
*/
|
||||
int (* eh_abort_handler)(struct scsi_cmnd *);
|
||||
int (* eh_device_reset_handler)(struct scsi_cmnd *);
|
||||
int (* eh_bus_reset_handler)(struct scsi_cmnd *);
|
||||
int (* eh_host_reset_handler)(struct scsi_cmnd *);
|
||||
|
||||
/*
|
||||
* Before the mid layer attempts to scan for a new device where none
|
||||
* currently exists, it will call this entry in your driver. Should
|
||||
* your driver need to allocate any structs or perform any other init
|
||||
* items in order to send commands to a currently unused target/lun
|
||||
* combo, then this is where you can perform those allocations. This
|
||||
* is specifically so that drivers won't have to perform any kind of
|
||||
* "is this a new device" checks in their queuecommand routine,
|
||||
* thereby making the hot path a bit quicker.
|
||||
*
|
||||
* Return values: 0 on success, non-0 on failure
|
||||
*
|
||||
* Deallocation: If we didn't find any devices at this ID, you will
|
||||
* get an immediate call to slave_destroy(). If we find something
|
||||
* here then you will get a call to slave_configure(), then the
|
||||
* device will be used for however long it is kept around, then when
|
||||
* the device is removed from the system (or * possibly at reboot
|
||||
* time), you will then get a call to slave_destroy(). This is
|
||||
* assuming you implement slave_configure and slave_destroy.
|
||||
* However, if you allocate memory and hang it off the device struct,
|
||||
* then you must implement the slave_destroy() routine at a minimum
|
||||
* in order to avoid leaking memory
|
||||
* each time a device is tore down.
|
||||
*
|
||||
* Status: OPTIONAL
|
||||
*/
|
||||
int (* slave_alloc)(struct scsi_device *);
|
||||
|
||||
/*
|
||||
* Once the device has responded to an INQUIRY and we know the
|
||||
* device is online, we call into the low level driver with the
|
||||
* struct scsi_device *. If the low level device driver implements
|
||||
* this function, it *must* perform the task of setting the queue
|
||||
* depth on the device. All other tasks are optional and depend
|
||||
* on what the driver supports and various implementation details.
|
||||
*
|
||||
* Things currently recommended to be handled at this time include:
|
||||
*
|
||||
* 1. Setting the device queue depth. Proper setting of this is
|
||||
* described in the comments for scsi_adjust_queue_depth.
|
||||
* 2. Determining if the device supports the various synchronous
|
||||
* negotiation protocols. The device struct will already have
|
||||
* responded to INQUIRY and the results of the standard items
|
||||
* will have been shoved into the various device flag bits, eg.
|
||||
* device->sdtr will be true if the device supports SDTR messages.
|
||||
* 3. Allocating command structs that the device will need.
|
||||
* 4. Setting the default timeout on this device (if needed).
|
||||
* 5. Anything else the low level driver might want to do on a device
|
||||
* specific setup basis...
|
||||
* 6. Return 0 on success, non-0 on error. The device will be marked
|
||||
* as offline on error so that no access will occur. If you return
|
||||
* non-0, your slave_destroy routine will never get called for this
|
||||
* device, so don't leave any loose memory hanging around, clean
|
||||
* up after yourself before returning non-0
|
||||
*
|
||||
* Status: OPTIONAL
|
||||
*/
|
||||
int (* slave_configure)(struct scsi_device *);
|
||||
|
||||
/*
|
||||
* Immediately prior to deallocating the device and after all activity
|
||||
* has ceased the mid layer calls this point so that the low level
|
||||
* driver may completely detach itself from the scsi device and vice
|
||||
* versa. The low level driver is responsible for freeing any memory
|
||||
* it allocated in the slave_alloc or slave_configure calls.
|
||||
*
|
||||
* Status: OPTIONAL
|
||||
*/
|
||||
void (* slave_destroy)(struct scsi_device *);
|
||||
|
||||
/*
|
||||
* Before the mid layer attempts to scan for a new device attached
|
||||
* to a target where no target currently exists, it will call this
|
||||
* entry in your driver. Should your driver need to allocate any
|
||||
* structs or perform any other init items in order to send commands
|
||||
* to a currently unused target, then this is where you can perform
|
||||
* those allocations.
|
||||
*
|
||||
* Return values: 0 on success, non-0 on failure
|
||||
*
|
||||
* Status: OPTIONAL
|
||||
*/
|
||||
int (* target_alloc)(struct scsi_target *);
|
||||
|
||||
/*
|
||||
* Immediately prior to deallocating the target structure, and
|
||||
* after all activity to attached scsi devices has ceased, the
|
||||
* midlayer calls this point so that the driver may deallocate
|
||||
* and terminate any references to the target.
|
||||
*
|
||||
* Status: OPTIONAL
|
||||
*/
|
||||
void (* target_destroy)(struct scsi_target *);
|
||||
|
||||
/*
|
||||
* If a host has the ability to discover targets on its own instead
|
||||
* of scanning the entire bus, it can fill in this function and
|
||||
* call scsi_scan_host(). This function will be called periodically
|
||||
* until it returns 1 with the scsi_host and the elapsed time of
|
||||
* the scan in jiffies.
|
||||
*
|
||||
* Status: OPTIONAL
|
||||
*/
|
||||
int (* scan_finished)(struct Scsi_Host *, unsigned long);
|
||||
|
||||
/*
|
||||
* If the host wants to be called before the scan starts, but
|
||||
* after the midlayer has set up ready for the scan, it can fill
|
||||
* in this function.
|
||||
*/
|
||||
void (* scan_start)(struct Scsi_Host *);
|
||||
|
||||
/*
|
||||
* fill in this function to allow the queue depth of this host
|
||||
* to be changeable (on a per device basis). returns either
|
||||
* the current queue depth setting (may be different from what
|
||||
* was passed in) or an error. An error should only be
|
||||
* returned if the requested depth is legal but the driver was
|
||||
* unable to set it. If the requested depth is illegal, the
|
||||
* driver should set and return the closest legal queue depth.
|
||||
*
|
||||
*/
|
||||
int (* change_queue_depth)(struct scsi_device *, int);
|
||||
|
||||
/*
|
||||
* fill in this function to allow the changing of tag types
|
||||
* (this also allows the enabling/disabling of tag command
|
||||
* queueing). An error should only be returned if something
|
||||
* went wrong in the driver while trying to set the tag type.
|
||||
* If the driver doesn't support the requested tag type, then
|
||||
* it should set the closest type it does support without
|
||||
* returning an error. Returns the actual tag type set.
|
||||
*/
|
||||
int (* change_queue_type)(struct scsi_device *, int);
|
||||
|
||||
/*
|
||||
* This function determines the bios parameters for a given
|
||||
* harddisk. These tend to be numbers that are made up by
|
||||
* the host adapter. Parameters:
|
||||
* size, device, list (heads, sectors, cylinders)
|
||||
*
|
||||
* Status: OPTIONAL */
|
||||
int (* bios_param)(struct scsi_device *, struct block_device *,
|
||||
sector_t, int []);
|
||||
|
||||
/*
|
||||
* Can be used to export driver statistics and other infos to the
|
||||
* world outside the kernel ie. userspace and it also provides an
|
||||
* interface to feed the driver with information.
|
||||
*
|
||||
* Status: OBSOLETE
|
||||
*/
|
||||
int (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int);
|
||||
|
||||
/*
|
||||
* suspend support
|
||||
*/
|
||||
int (*resume)(struct scsi_device *);
|
||||
int (*suspend)(struct scsi_device *, pm_message_t state);
|
||||
|
||||
/*
|
||||
* Name of proc directory
|
||||
*/
|
||||
char *proc_name;
|
||||
|
||||
/*
|
||||
* Used to store the procfs directory if a driver implements the
|
||||
* proc_info method.
|
||||
*/
|
||||
struct proc_dir_entry *proc_dir;
|
||||
|
||||
/*
|
||||
* This determines if we will use a non-interrupt driven
|
||||
* or an interrupt driven scheme, It is set to the maximum number
|
||||
* of simultaneous commands a given host adapter will accept.
|
||||
*/
|
||||
int can_queue;
|
||||
|
||||
/*
|
||||
* In many instances, especially where disconnect / reconnect are
|
||||
* supported, our host also has an ID on the SCSI bus. If this is
|
||||
* the case, then it must be reserved. Please set this_id to -1 if
|
||||
* your setup is in single initiator mode, and the host lacks an
|
||||
* ID.
|
||||
*/
|
||||
int this_id;
|
||||
|
||||
/*
|
||||
* This determines the degree to which the host adapter is capable
|
||||
* of scatter-gather.
|
||||
*/
|
||||
unsigned short sg_tablesize;
|
||||
|
||||
/*
|
||||
* If the host adapter has limitations beside segment count
|
||||
*/
|
||||
unsigned short max_sectors;
|
||||
|
||||
/*
|
||||
* dma scatter gather segment boundary limit. a segment crossing this
|
||||
* boundary will be split in two.
|
||||
*/
|
||||
unsigned long dma_boundary;
|
||||
|
||||
/*
|
||||
* This specifies "machine infinity" for host templates which don't
|
||||
* limit the transfer size. Note this limit represents an absolute
|
||||
* maximum, and may be over the transfer limits allowed for
|
||||
* individual devices (e.g. 256 for SCSI-1)
|
||||
*/
|
||||
#define SCSI_DEFAULT_MAX_SECTORS 1024
|
||||
|
||||
/*
|
||||
* True if this host adapter can make good use of linked commands.
|
||||
* This will allow more than one command to be queued to a given
|
||||
* unit on a given host. Set this to the maximum number of command
|
||||
* blocks to be provided for each device. Set this to 1 for one
|
||||
* command block per lun, 2 for two, etc. Do not set this to 0.
|
||||
* You should make sure that the host adapter will do the right thing
|
||||
* before you try setting this above 1.
|
||||
*/
|
||||
short cmd_per_lun;
|
||||
|
||||
/*
|
||||
* present contains counter indicating how many boards of this
|
||||
* type were found when we did the scan.
|
||||
*/
|
||||
unsigned char present;
|
||||
|
||||
/*
|
||||
* true if this host adapter uses unchecked DMA onto an ISA bus.
|
||||
*/
|
||||
unsigned unchecked_isa_dma:1;
|
||||
|
||||
/*
|
||||
* true if this host adapter can make good use of clustering.
|
||||
* I originally thought that if the tablesize was large that it
|
||||
* was a waste of CPU cycles to prepare a cluster list, but
|
||||
* it works out that the Buslogic is faster if you use a smaller
|
||||
* number of segments (i.e. use clustering). I guess it is
|
||||
* inefficient.
|
||||
*/
|
||||
unsigned use_clustering:1;
|
||||
|
||||
/*
|
||||
* True for emulated SCSI host adapters (e.g. ATAPI)
|
||||
*/
|
||||
unsigned emulated:1;
|
||||
|
||||
/*
|
||||
* True if the low-level driver performs its own reset-settle delays.
|
||||
*/
|
||||
unsigned skip_settle_delay:1;
|
||||
|
||||
/*
|
||||
* ordered write support
|
||||
*/
|
||||
unsigned ordered_tag:1;
|
||||
|
||||
/*
|
||||
* Countdown for host blocking with no commands outstanding
|
||||
*/
|
||||
unsigned int max_host_blocked;
|
||||
|
||||
/*
|
||||
* Default value for the blocking. If the queue is empty,
|
||||
* host_blocked counts down in the request_fn until it restarts
|
||||
* host operations as zero is reached.
|
||||
*
|
||||
* FIXME: This should probably be a value in the template
|
||||
*/
|
||||
#define SCSI_DEFAULT_HOST_BLOCKED 7
|
||||
|
||||
/*
|
||||
* Pointer to the sysfs class properties for this host, NULL terminated.
|
||||
*/
|
||||
struct class_device_attribute **shost_attrs;
|
||||
|
||||
/*
|
||||
* Pointer to the SCSI device properties for this host, NULL terminated.
|
||||
*/
|
||||
struct device_attribute **sdev_attrs;
|
||||
|
||||
/*
|
||||
* List of hosts per template.
|
||||
*
|
||||
* This is only for use by scsi_module.c for legacy templates.
|
||||
* For these access to it is synchronized implicitly by
|
||||
* module_init/module_exit.
|
||||
*/
|
||||
struct list_head legacy_hosts;
|
||||
};
|
||||
|
||||
/*
|
||||
* shost state: If you alter this, you also need to alter scsi_sysfs.c
|
||||
* (for the ascii descriptions) and the state model enforcer:
|
||||
* scsi_host_set_state()
|
||||
*/
|
||||
enum scsi_host_state {
|
||||
SHOST_CREATED = 1,
|
||||
SHOST_RUNNING,
|
||||
SHOST_CANCEL,
|
||||
SHOST_DEL,
|
||||
SHOST_RECOVERY,
|
||||
SHOST_CANCEL_RECOVERY,
|
||||
SHOST_DEL_RECOVERY,
|
||||
};
|
||||
|
||||
struct Scsi_Host {
|
||||
/*
|
||||
* __devices is protected by the host_lock, but you should
|
||||
* usually use scsi_device_lookup / shost_for_each_device
|
||||
* to access it and don't care about locking yourself.
|
||||
* In the rare case of beeing in irq context you can use
|
||||
* their __ prefixed variants with the lock held. NEVER
|
||||
* access this list directly from a driver.
|
||||
*/
|
||||
struct list_head __devices;
|
||||
struct list_head __targets;
|
||||
|
||||
struct scsi_host_cmd_pool *cmd_pool;
|
||||
spinlock_t free_list_lock;
|
||||
struct list_head free_list; /* backup store of cmd structs */
|
||||
struct list_head starved_list;
|
||||
|
||||
spinlock_t default_lock;
|
||||
spinlock_t *host_lock;
|
||||
|
||||
struct mutex scan_mutex;/* serialize scanning activity */
|
||||
|
||||
struct list_head eh_cmd_q;
|
||||
struct task_struct * ehandler; /* Error recovery thread. */
|
||||
struct completion * eh_action; /* Wait for specific actions on the
|
||||
host. */
|
||||
wait_queue_head_t host_wait;
|
||||
struct scsi_host_template *hostt;
|
||||
struct scsi_transport_template *transportt;
|
||||
|
||||
/*
|
||||
* area to keep a shared tag map (if needed, will be
|
||||
* NULL if not)
|
||||
*/
|
||||
struct blk_queue_tag *bqt;
|
||||
|
||||
/*
|
||||
* The following two fields are protected with host_lock;
|
||||
* however, eh routines can safely access during eh processing
|
||||
* without acquiring the lock.
|
||||
*/
|
||||
unsigned int host_busy; /* commands actually active on low-level */
|
||||
unsigned int host_failed; /* commands that failed. */
|
||||
unsigned int host_eh_scheduled; /* EH scheduled without command */
|
||||
|
||||
unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
|
||||
int resetting; /* if set, it means that last_reset is a valid value */
|
||||
unsigned long last_reset;
|
||||
|
||||
/*
|
||||
* These three parameters can be used to allow for wide scsi,
|
||||
* and for host adapters that support multiple busses
|
||||
* The first two should be set to 1 more than the actual max id
|
||||
* or lun (i.e. 8 for normal systems).
|
||||
*/
|
||||
unsigned int max_id;
|
||||
unsigned int max_lun;
|
||||
unsigned int max_channel;
|
||||
|
||||
/*
|
||||
* This is a unique identifier that must be assigned so that we
|
||||
* have some way of identifying each detected host adapter properly
|
||||
* and uniquely. For hosts that do not support more than one card
|
||||
* in the system at one time, this does not need to be set. It is
|
||||
* initialized to 0 in scsi_register.
|
||||
*/
|
||||
unsigned int unique_id;
|
||||
|
||||
/*
|
||||
* The maximum length of SCSI commands that this host can accept.
|
||||
* Probably 12 for most host adapters, but could be 16 for others.
|
||||
* For drivers that don't set this field, a value of 12 is
|
||||
* assumed. I am leaving this as a number rather than a bit
|
||||
* because you never know what subsequent SCSI standards might do
|
||||
* (i.e. could there be a 20 byte or a 24-byte command a few years
|
||||
* down the road?).
|
||||
*/
|
||||
unsigned char max_cmd_len;
|
||||
|
||||
int this_id;
|
||||
int can_queue;
|
||||
short cmd_per_lun;
|
||||
short unsigned int sg_tablesize;
|
||||
short unsigned int max_sectors;
|
||||
unsigned long dma_boundary;
|
||||
/*
|
||||
* Used to assign serial numbers to the cmds.
|
||||
* Protected by the host lock.
|
||||
*/
|
||||
unsigned long cmd_serial_number, cmd_pid;
|
||||
|
||||
unsigned unchecked_isa_dma:1;
|
||||
unsigned use_clustering:1;
|
||||
unsigned use_blk_tcq:1;
|
||||
|
||||
/*
|
||||
* Host has requested that no further requests come through for the
|
||||
* time being.
|
||||
*/
|
||||
unsigned host_self_blocked:1;
|
||||
|
||||
/*
|
||||
* Host uses correct SCSI ordering not PC ordering. The bit is
|
||||
* set for the minority of drivers whose authors actually read
|
||||
* the spec ;)
|
||||
*/
|
||||
unsigned reverse_ordering:1;
|
||||
|
||||
/*
|
||||
* ordered write support
|
||||
*/
|
||||
unsigned ordered_tag:1;
|
||||
|
||||
/* task mgmt function in progress */
|
||||
unsigned tmf_in_progress:1;
|
||||
|
||||
/* Asynchronous scan in progress */
|
||||
unsigned async_scan:1;
|
||||
|
||||
/*
|
||||
* Optional work queue to be utilized by the transport
|
||||
*/
|
||||
char work_q_name[KOBJ_NAME_LEN];
|
||||
struct workqueue_struct *work_q;
|
||||
|
||||
/*
|
||||
* Host has rejected a command because it was busy.
|
||||
*/
|
||||
unsigned int host_blocked;
|
||||
|
||||
/*
|
||||
* Value host_blocked counts down from
|
||||
*/
|
||||
unsigned int max_host_blocked;
|
||||
|
||||
/*
|
||||
* q used for scsi_tgt msgs, async events or any other requests that
|
||||
* need to be processed in userspace
|
||||
*/
|
||||
struct request_queue *uspace_req_q;
|
||||
|
||||
/* legacy crap */
|
||||
unsigned long base;
|
||||
unsigned long io_port;
|
||||
unsigned char n_io_port;
|
||||
unsigned char dma_channel;
|
||||
unsigned int irq;
|
||||
|
||||
|
||||
enum scsi_host_state shost_state;
|
||||
|
||||
/* ldm bits */
|
||||
struct device shost_gendev;
|
||||
struct class_device shost_classdev;
|
||||
|
||||
/*
|
||||
* List of hosts per template.
|
||||
*
|
||||
* This is only for use by scsi_module.c for legacy templates.
|
||||
* For these access to it is synchronized implicitly by
|
||||
* module_init/module_exit.
|
||||
*/
|
||||
struct list_head sht_legacy_list;
|
||||
|
||||
/*
|
||||
* Points to the transport data (if any) which is allocated
|
||||
* separately
|
||||
*/
|
||||
void *shost_data;
|
||||
|
||||
/*
|
||||
* We should ensure that this is aligned, both for better performance
|
||||
* and also because some compilers (m68k) don't automatically force
|
||||
* alignment to a long boundary.
|
||||
*/
|
||||
unsigned long hostdata[0] /* Used for storage of host specific stuff */
|
||||
__attribute__ ((aligned (sizeof(unsigned long))));
|
||||
};
|
||||
|
||||
#define class_to_shost(d) \
|
||||
container_of(d, struct Scsi_Host, shost_classdev)
|
||||
|
||||
#define shost_printk(prefix, shost, fmt, a...) \
|
||||
dev_printk(prefix, &(shost)->shost_gendev, fmt, ##a)
|
||||
|
||||
|
||||
int scsi_is_host_device(const struct device *);
|
||||
|
||||
static inline struct Scsi_Host *dev_to_shost(struct device *dev)
|
||||
{
|
||||
while (!scsi_is_host_device(dev)) {
|
||||
if (!dev->parent)
|
||||
return NULL;
|
||||
dev = dev->parent;
|
||||
}
|
||||
return container_of(dev, struct Scsi_Host, shost_gendev);
|
||||
}
|
||||
|
||||
static inline int scsi_host_in_recovery(struct Scsi_Host *shost)
|
||||
{
|
||||
return shost->shost_state == SHOST_RECOVERY ||
|
||||
shost->shost_state == SHOST_CANCEL_RECOVERY ||
|
||||
shost->shost_state == SHOST_DEL_RECOVERY ||
|
||||
shost->tmf_in_progress;
|
||||
}
|
||||
|
||||
extern int scsi_queue_work(struct Scsi_Host *, struct work_struct *);
|
||||
extern void scsi_flush_work(struct Scsi_Host *);
|
||||
|
||||
extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int);
|
||||
extern int __must_check scsi_add_host(struct Scsi_Host *, struct device *);
|
||||
extern void scsi_scan_host(struct Scsi_Host *);
|
||||
extern void scsi_rescan_device(struct device *);
|
||||
extern void scsi_remove_host(struct Scsi_Host *);
|
||||
extern struct Scsi_Host *scsi_host_get(struct Scsi_Host *);
|
||||
extern void scsi_host_put(struct Scsi_Host *t);
|
||||
extern struct Scsi_Host *scsi_host_lookup(unsigned short);
|
||||
extern const char *scsi_host_state_name(enum scsi_host_state);
|
||||
|
||||
extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *);
|
||||
|
||||
static inline struct device *scsi_get_device(struct Scsi_Host *shost)
|
||||
{
|
||||
return shost->shost_gendev.parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* scsi_host_scan_allowed - Is scanning of this host allowed
|
||||
* @shost: Pointer to Scsi_Host.
|
||||
**/
|
||||
static inline int scsi_host_scan_allowed(struct Scsi_Host *shost)
|
||||
{
|
||||
return shost->shost_state == SHOST_RUNNING;
|
||||
}
|
||||
|
||||
extern void scsi_unblock_requests(struct Scsi_Host *);
|
||||
extern void scsi_block_requests(struct Scsi_Host *);
|
||||
|
||||
struct class_container;
|
||||
|
||||
extern struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
|
||||
void (*) (struct request_queue *));
|
||||
/*
|
||||
* These two functions are used to allocate and free a pseudo device
|
||||
* which will connect to the host adapter itself rather than any
|
||||
* physical device. You must deallocate when you are done with the
|
||||
* thing. This physical pseudo-device isn't real and won't be available
|
||||
* from any high-level drivers.
|
||||
*/
|
||||
extern void scsi_free_host_dev(struct scsi_device *);
|
||||
extern struct scsi_device *scsi_get_host_dev(struct Scsi_Host *);
|
||||
|
||||
/* legacy interfaces */
|
||||
extern struct Scsi_Host *scsi_register(struct scsi_host_template *, int);
|
||||
extern void scsi_unregister(struct Scsi_Host *);
|
||||
extern int scsi_host_set_state(struct Scsi_Host *, enum scsi_host_state);
|
||||
|
||||
#endif /* _SCSI_SCSI_HOST_H */
|
||||
48
include/scsi/scsi_ioctl.h
Normal file
48
include/scsi/scsi_ioctl.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef _SCSI_IOCTL_H
|
||||
#define _SCSI_IOCTL_H
|
||||
|
||||
#define SCSI_IOCTL_SEND_COMMAND 1
|
||||
#define SCSI_IOCTL_TEST_UNIT_READY 2
|
||||
#define SCSI_IOCTL_BENCHMARK_COMMAND 3
|
||||
#define SCSI_IOCTL_SYNC 4 /* Request synchronous parameters */
|
||||
#define SCSI_IOCTL_START_UNIT 5
|
||||
#define SCSI_IOCTL_STOP_UNIT 6
|
||||
/* The door lock/unlock constants are compatible with Sun constants for
|
||||
the cdrom */
|
||||
#define SCSI_IOCTL_DOORLOCK 0x5380 /* lock the eject mechanism */
|
||||
#define SCSI_IOCTL_DOORUNLOCK 0x5381 /* unlock the mechanism */
|
||||
|
||||
#define SCSI_REMOVAL_PREVENT 1
|
||||
#define SCSI_REMOVAL_ALLOW 0
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
struct scsi_device;
|
||||
|
||||
/*
|
||||
* Structures used for scsi_ioctl et al.
|
||||
*/
|
||||
|
||||
typedef struct scsi_ioctl_command {
|
||||
unsigned int inlen;
|
||||
unsigned int outlen;
|
||||
unsigned char data[0];
|
||||
} Scsi_Ioctl_Command;
|
||||
|
||||
typedef struct scsi_idlun {
|
||||
__u32 dev_id;
|
||||
__u32 host_unique_id;
|
||||
} Scsi_Idlun;
|
||||
|
||||
/* Fibre Channel WWN, port_id struct */
|
||||
typedef struct scsi_fctargaddress {
|
||||
__u32 host_port_id;
|
||||
unsigned char host_wwn[8]; // include NULL term.
|
||||
} Scsi_FCTargAddress;
|
||||
|
||||
extern int scsi_ioctl(struct scsi_device *, int, void __user *);
|
||||
extern int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
|
||||
void __user *arg, struct file *filp);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _SCSI_IOCTL_H */
|
||||
87
include/scsi/scsi_netlink.h
Normal file
87
include/scsi/scsi_netlink.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* SCSI Transport Netlink Interface
|
||||
* Used for the posting of outbound SCSI transport events
|
||||
*
|
||||
* Copyright (C) 2006 James Smart, Emulex Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#ifndef SCSI_NETLINK_H
|
||||
#define SCSI_NETLINK_H
|
||||
|
||||
/*
|
||||
* This file intended to be included by both kernel and user space
|
||||
*/
|
||||
|
||||
/* Single Netlink Message type to send all SCSI Transport messages */
|
||||
#define SCSI_TRANSPORT_MSG NLMSG_MIN_TYPE + 1
|
||||
|
||||
/* SCSI Transport Broadcast Groups */
|
||||
/* leaving groups 0 and 1 unassigned */
|
||||
#define SCSI_NL_GRP_FC_EVENTS (1<<2) /* Group 2 */
|
||||
#define SCSI_NL_GRP_CNT 3
|
||||
|
||||
|
||||
/* SCSI_TRANSPORT_MSG event message header */
|
||||
struct scsi_nl_hdr {
|
||||
uint8_t version;
|
||||
uint8_t transport;
|
||||
uint16_t magic;
|
||||
uint16_t msgtype;
|
||||
uint16_t msglen;
|
||||
} __attribute__((aligned(sizeof(uint64_t))));
|
||||
|
||||
/* scsi_nl_hdr->version value */
|
||||
#define SCSI_NL_VERSION 1
|
||||
|
||||
/* scsi_nl_hdr->magic value */
|
||||
#define SCSI_NL_MAGIC 0xA1B2
|
||||
|
||||
/* scsi_nl_hdr->transport value */
|
||||
#define SCSI_NL_TRANSPORT 0
|
||||
#define SCSI_NL_TRANSPORT_FC 1
|
||||
#define SCSI_NL_MAX_TRANSPORTS 2
|
||||
|
||||
/* scsi_nl_hdr->msgtype values are defined in each transport */
|
||||
|
||||
|
||||
/*
|
||||
* Vendor ID:
|
||||
* If transports post vendor-unique events, they must pass a well-known
|
||||
* 32-bit vendor identifier. This identifier consists of 8 bits indicating
|
||||
* the "type" of identifier contained, and 24 bits of id data.
|
||||
*
|
||||
* Identifiers for each type:
|
||||
* PCI : ID data is the 16 bit PCI Registered Vendor ID
|
||||
*/
|
||||
#define SCSI_NL_VID_TYPE_SHIFT 56
|
||||
#define SCSI_NL_VID_TYPE_MASK ((u64)0xFF << SCSI_NL_VID_TYPE_SHIFT)
|
||||
#define SCSI_NL_VID_TYPE_PCI ((u64)0x01 << SCSI_NL_VID_TYPE_SHIFT)
|
||||
#define SCSI_NL_VID_ID_MASK (~ SCSI_NL_VID_TYPE_MASK)
|
||||
|
||||
|
||||
#define INIT_SCSI_NL_HDR(hdr, t, mtype, mlen) \
|
||||
{ \
|
||||
(hdr)->version = SCSI_NL_VERSION; \
|
||||
(hdr)->transport = t; \
|
||||
(hdr)->magic = SCSI_NL_MAGIC; \
|
||||
(hdr)->msgtype = mtype; \
|
||||
(hdr)->msglen = mlen; \
|
||||
}
|
||||
|
||||
|
||||
#endif /* SCSI_NETLINK_H */
|
||||
|
||||
71
include/scsi/scsi_netlink_fc.h
Normal file
71
include/scsi/scsi_netlink_fc.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* FC Transport Netlink Interface
|
||||
*
|
||||
* Copyright (C) 2006 James Smart, Emulex Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#ifndef SCSI_NETLINK_FC_H
|
||||
#define SCSI_NETLINK_FC_H
|
||||
|
||||
#include <scsi/scsi_netlink.h>
|
||||
|
||||
/*
|
||||
* This file intended to be included by both kernel and user space
|
||||
*/
|
||||
|
||||
/*
|
||||
* FC Transport Message Types
|
||||
*/
|
||||
/* kernel -> user */
|
||||
#define FC_NL_ASYNC_EVENT 0x0100
|
||||
/* user -> kernel */
|
||||
/* none */
|
||||
|
||||
|
||||
/*
|
||||
* Message Structures :
|
||||
*/
|
||||
|
||||
/* macro to round up message lengths to 8byte boundary */
|
||||
#define FC_NL_MSGALIGN(len) (((len) + 7) & ~7)
|
||||
|
||||
|
||||
/*
|
||||
* FC Transport Broadcast Event Message :
|
||||
* FC_NL_ASYNC_EVENT
|
||||
*
|
||||
* Note: if Vendor Unique message, &event_data will be start of
|
||||
* vendor unique payload, and the length of the payload is
|
||||
* per event_datalen
|
||||
*
|
||||
* Note: When specifying vendor_id, be sure to read the Vendor Type and ID
|
||||
* formatting requirements specified in scsi_netlink.h
|
||||
*/
|
||||
struct fc_nl_event {
|
||||
struct scsi_nl_hdr snlh; /* must be 1st element ! */
|
||||
uint64_t seconds;
|
||||
uint64_t vendor_id;
|
||||
uint16_t host_no;
|
||||
uint16_t event_datalen;
|
||||
uint32_t event_num;
|
||||
uint32_t event_code;
|
||||
uint32_t event_data;
|
||||
} __attribute__((aligned(sizeof(uint64_t))));
|
||||
|
||||
|
||||
#endif /* SCSI_NETLINK_FC_H */
|
||||
|
||||
168
include/scsi/scsi_tcq.h
Normal file
168
include/scsi/scsi_tcq.h
Normal file
@@ -0,0 +1,168 @@
|
||||
#ifndef _SCSI_SCSI_TCQ_H
|
||||
#define _SCSI_SCSI_TCQ_H
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
|
||||
#define MSG_SIMPLE_TAG 0x20
|
||||
#define MSG_HEAD_TAG 0x21
|
||||
#define MSG_ORDERED_TAG 0x22
|
||||
|
||||
#define SCSI_NO_TAG (-1) /* identify no tag in use */
|
||||
|
||||
|
||||
#ifdef CONFIG_BLOCK
|
||||
|
||||
/**
|
||||
* scsi_get_tag_type - get the type of tag the device supports
|
||||
* @sdev: the scsi device
|
||||
*
|
||||
* Notes:
|
||||
* If the drive only supports simple tags, returns MSG_SIMPLE_TAG
|
||||
* if it supports all tag types, returns MSG_ORDERED_TAG.
|
||||
*/
|
||||
static inline int scsi_get_tag_type(struct scsi_device *sdev)
|
||||
{
|
||||
if (!sdev->tagged_supported)
|
||||
return 0;
|
||||
if (sdev->ordered_tags)
|
||||
return MSG_ORDERED_TAG;
|
||||
if (sdev->simple_tags)
|
||||
return MSG_SIMPLE_TAG;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void scsi_set_tag_type(struct scsi_device *sdev, int tag)
|
||||
{
|
||||
switch (tag) {
|
||||
case MSG_ORDERED_TAG:
|
||||
sdev->ordered_tags = 1;
|
||||
/* fall through */
|
||||
case MSG_SIMPLE_TAG:
|
||||
sdev->simple_tags = 1;
|
||||
break;
|
||||
case 0:
|
||||
/* fall through */
|
||||
default:
|
||||
sdev->ordered_tags = 0;
|
||||
sdev->simple_tags = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* scsi_activate_tcq - turn on tag command queueing
|
||||
* @SDpnt: device to turn on TCQ for
|
||||
* @depth: queue depth
|
||||
*
|
||||
* Notes:
|
||||
* Eventually, I hope depth would be the maximum depth
|
||||
* the device could cope with and the real queue depth
|
||||
* would be adjustable from 0 to depth.
|
||||
**/
|
||||
static inline void scsi_activate_tcq(struct scsi_device *sdev, int depth)
|
||||
{
|
||||
if (!sdev->tagged_supported)
|
||||
return;
|
||||
|
||||
if (!blk_queue_tagged(sdev->request_queue))
|
||||
blk_queue_init_tags(sdev->request_queue, depth,
|
||||
sdev->host->bqt);
|
||||
|
||||
scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
|
||||
}
|
||||
|
||||
/**
|
||||
* scsi_deactivate_tcq - turn off tag command queueing
|
||||
* @SDpnt: device to turn off TCQ for
|
||||
**/
|
||||
static inline void scsi_deactivate_tcq(struct scsi_device *sdev, int depth)
|
||||
{
|
||||
if (blk_queue_tagged(sdev->request_queue))
|
||||
blk_queue_free_tags(sdev->request_queue);
|
||||
scsi_adjust_queue_depth(sdev, 0, depth);
|
||||
}
|
||||
|
||||
/**
|
||||
* scsi_populate_tag_msg - place a tag message in a buffer
|
||||
* @SCpnt: pointer to the Scsi_Cmnd for the tag
|
||||
* @msg: pointer to the area to place the tag
|
||||
*
|
||||
* Notes:
|
||||
* designed to create the correct type of tag message for the
|
||||
* particular request. Returns the size of the tag message.
|
||||
* May return 0 if TCQ is disabled for this device.
|
||||
**/
|
||||
static inline int scsi_populate_tag_msg(struct scsi_cmnd *cmd, char *msg)
|
||||
{
|
||||
struct request *req = cmd->request;
|
||||
struct scsi_device *sdev = cmd->device;
|
||||
|
||||
if (blk_rq_tagged(req)) {
|
||||
if (sdev->ordered_tags && req->cmd_flags & REQ_HARDBARRIER)
|
||||
*msg++ = MSG_ORDERED_TAG;
|
||||
else
|
||||
*msg++ = MSG_SIMPLE_TAG;
|
||||
*msg++ = req->tag;
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* scsi_find_tag - find a tagged command by device
|
||||
* @SDpnt: pointer to the ScSI device
|
||||
* @tag: the tag number
|
||||
*
|
||||
* Notes:
|
||||
* Only works with tags allocated by the generic blk layer.
|
||||
**/
|
||||
static inline struct scsi_cmnd *scsi_find_tag(struct scsi_device *sdev, int tag)
|
||||
{
|
||||
|
||||
struct request *req;
|
||||
|
||||
if (tag != SCSI_NO_TAG) {
|
||||
req = blk_queue_find_tag(sdev->request_queue, tag);
|
||||
return req ? (struct scsi_cmnd *)req->special : NULL;
|
||||
}
|
||||
|
||||
/* single command, look in space */
|
||||
return sdev->current_cmnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* scsi_init_shared_tag_map - create a shared tag map
|
||||
* @shost: the host to share the tag map among all devices
|
||||
* @depth: the total depth of the map
|
||||
*/
|
||||
static inline int scsi_init_shared_tag_map(struct Scsi_Host *shost, int depth)
|
||||
{
|
||||
shost->bqt = blk_init_tags(depth);
|
||||
return shost->bqt ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* scsi_host_find_tag - find the tagged command by host
|
||||
* @shost: pointer to scsi_host
|
||||
* @tag: tag of the scsi_cmnd
|
||||
*
|
||||
* Notes:
|
||||
* Only works with tags allocated by the generic blk layer.
|
||||
**/
|
||||
static inline struct scsi_cmnd *scsi_host_find_tag(struct Scsi_Host *shost,
|
||||
int tag)
|
||||
{
|
||||
struct request *req;
|
||||
|
||||
if (tag != SCSI_NO_TAG) {
|
||||
req = blk_map_queue_find_tag(shost->bqt, tag);
|
||||
return req ? (struct scsi_cmnd *)req->special : NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BLOCK */
|
||||
#endif /* _SCSI_SCSI_TCQ_H */
|
||||
19
include/scsi/scsi_tgt.h
Normal file
19
include/scsi/scsi_tgt.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* SCSI target definitions
|
||||
*/
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
struct Scsi_Host;
|
||||
struct scsi_cmnd;
|
||||
struct scsi_lun;
|
||||
|
||||
extern struct Scsi_Host *scsi_tgt_cmd_to_host(struct scsi_cmnd *);
|
||||
extern int scsi_tgt_alloc_queue(struct Scsi_Host *);
|
||||
extern void scsi_tgt_free_queue(struct Scsi_Host *);
|
||||
extern int scsi_tgt_queue_command(struct scsi_cmnd *, struct scsi_lun *, u64);
|
||||
extern int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *, int, u64, struct scsi_lun *,
|
||||
void *);
|
||||
extern struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *,
|
||||
enum dma_data_direction, gfp_t);
|
||||
extern void scsi_host_put_command(struct Scsi_Host *, struct scsi_cmnd *);
|
||||
87
include/scsi/scsi_tgt_if.h
Normal file
87
include/scsi/scsi_tgt_if.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* SCSI target kernel/user interface
|
||||
*
|
||||
* Copyright (C) 2005 FUJITA Tomonori <tomof@acm.org>
|
||||
* Copyright (C) 2005 Mike Christie <michaelc@cs.wisc.edu>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
#ifndef __SCSI_TARGET_IF_H
|
||||
#define __SCSI_TARGET_IF_H
|
||||
|
||||
/* user -> kernel */
|
||||
#define TGT_UEVENT_CMD_RSP 0x0001
|
||||
#define TGT_UEVENT_TSK_MGMT_RSP 0x0002
|
||||
|
||||
/* kernel -> user */
|
||||
#define TGT_KEVENT_CMD_REQ 0x1001
|
||||
#define TGT_KEVENT_CMD_DONE 0x1002
|
||||
#define TGT_KEVENT_TSK_MGMT_REQ 0x1003
|
||||
|
||||
struct tgt_event_hdr {
|
||||
uint16_t version;
|
||||
uint16_t status;
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
} __attribute__ ((aligned (sizeof(uint64_t))));
|
||||
|
||||
struct tgt_event {
|
||||
struct tgt_event_hdr hdr;
|
||||
|
||||
union {
|
||||
/* user-> kernel */
|
||||
struct {
|
||||
int host_no;
|
||||
uint32_t len;
|
||||
int result;
|
||||
aligned_u64 uaddr;
|
||||
uint8_t rw;
|
||||
aligned_u64 tag;
|
||||
} cmd_rsp;
|
||||
struct {
|
||||
int host_no;
|
||||
aligned_u64 mid;
|
||||
int result;
|
||||
} tsk_mgmt_rsp;
|
||||
|
||||
|
||||
/* kernel -> user */
|
||||
struct {
|
||||
int host_no;
|
||||
uint32_t data_len;
|
||||
uint8_t scb[16];
|
||||
uint8_t lun[8];
|
||||
int attribute;
|
||||
aligned_u64 tag;
|
||||
} cmd_req;
|
||||
struct {
|
||||
int host_no;
|
||||
aligned_u64 tag;
|
||||
int result;
|
||||
} cmd_done;
|
||||
struct {
|
||||
int host_no;
|
||||
int function;
|
||||
aligned_u64 tag;
|
||||
uint8_t lun[8];
|
||||
aligned_u64 mid;
|
||||
} tsk_mgmt_req;
|
||||
} p;
|
||||
} __attribute__ ((aligned (sizeof(uint64_t))));
|
||||
|
||||
#define TGT_RING_SIZE (1UL << 16)
|
||||
|
||||
#endif
|
||||
108
include/scsi/scsi_transport.h
Normal file
108
include/scsi/scsi_transport.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Transport specific attributes.
|
||||
*
|
||||
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef SCSI_TRANSPORT_H
|
||||
#define SCSI_TRANSPORT_H
|
||||
|
||||
#include <linux/transport_class.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
|
||||
struct scsi_transport_template {
|
||||
/* the attribute containers */
|
||||
struct transport_container host_attrs;
|
||||
struct transport_container target_attrs;
|
||||
struct transport_container device_attrs;
|
||||
|
||||
/*
|
||||
* If set, called from sysfs and legacy procfs rescanning code.
|
||||
*/
|
||||
int (*user_scan)(struct Scsi_Host *, uint, uint, uint);
|
||||
|
||||
/* The size of the specific transport attribute structure (a
|
||||
* space of this size will be left at the end of the
|
||||
* scsi_* structure */
|
||||
int device_size;
|
||||
int device_private_offset;
|
||||
int target_size;
|
||||
int target_private_offset;
|
||||
int host_size;
|
||||
/* no private offset for the host; there's an alternative mechanism */
|
||||
|
||||
/*
|
||||
* True if the transport wants to use a host-based work-queue
|
||||
*/
|
||||
unsigned int create_work_queue : 1;
|
||||
|
||||
/*
|
||||
* Allows a transport to override the default error handler.
|
||||
*/
|
||||
void (* eh_strategy_handler)(struct Scsi_Host *);
|
||||
|
||||
/*
|
||||
* This is an optional routine that allows the transport to become
|
||||
* involved when a scsi io timer fires. The return value tells the
|
||||
* timer routine how to finish the io timeout handling:
|
||||
* EH_HANDLED: I fixed the error, please complete the command
|
||||
* EH_RESET_TIMER: I need more time, reset the timer and
|
||||
* begin counting again
|
||||
* EH_NOT_HANDLED Begin normal error recovery
|
||||
*/
|
||||
enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
|
||||
};
|
||||
|
||||
#define transport_class_to_shost(tc) \
|
||||
dev_to_shost((tc)->dev)
|
||||
|
||||
|
||||
/* Private area maintenance. The driver requested allocations come
|
||||
* directly after the transport class allocations (if any). The idea
|
||||
* is that you *must* call these only once. The code assumes that the
|
||||
* initial values are the ones the transport specific code requires */
|
||||
static inline void
|
||||
scsi_transport_reserve_target(struct scsi_transport_template * t, int space)
|
||||
{
|
||||
BUG_ON(t->target_private_offset != 0);
|
||||
t->target_private_offset = ALIGN(t->target_size, sizeof(void *));
|
||||
t->target_size = t->target_private_offset + space;
|
||||
}
|
||||
static inline void
|
||||
scsi_transport_reserve_device(struct scsi_transport_template * t, int space)
|
||||
{
|
||||
BUG_ON(t->device_private_offset != 0);
|
||||
t->device_private_offset = ALIGN(t->device_size, sizeof(void *));
|
||||
t->device_size = t->device_private_offset + space;
|
||||
}
|
||||
static inline void *
|
||||
scsi_transport_target_data(struct scsi_target *starget)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
|
||||
return (u8 *)starget->starget_data
|
||||
+ shost->transportt->target_private_offset;
|
||||
|
||||
}
|
||||
static inline void *
|
||||
scsi_transport_device_data(struct scsi_device *sdev)
|
||||
{
|
||||
struct Scsi_Host *shost = sdev->host;
|
||||
return (u8 *)sdev->sdev_data
|
||||
+ shost->transportt->device_private_offset;
|
||||
}
|
||||
|
||||
#endif /* SCSI_TRANSPORT_H */
|
||||
569
include/scsi/scsi_transport_fc.h
Normal file
569
include/scsi/scsi_transport_fc.h
Normal file
@@ -0,0 +1,569 @@
|
||||
/*
|
||||
* FiberChannel transport specific attributes exported to sysfs.
|
||||
*
|
||||
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* ========
|
||||
*
|
||||
* Copyright (C) 2004-2005 James Smart, Emulex Corporation
|
||||
* Rewrite for host, target, device, and remote port attributes,
|
||||
* statistics, and service functions...
|
||||
*
|
||||
*/
|
||||
#ifndef SCSI_TRANSPORT_FC_H
|
||||
#define SCSI_TRANSPORT_FC_H
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_netlink.h>
|
||||
|
||||
struct scsi_transport_template;
|
||||
|
||||
|
||||
/*
|
||||
* FC Port definitions - Following FC HBAAPI guidelines
|
||||
*
|
||||
* Note: Not all binary values for the different fields match HBAAPI.
|
||||
* Instead, we use densely packed ordinal values or enums.
|
||||
* We get away with this as we never present the actual binary values
|
||||
* externally. For sysfs, we always present the string that describes
|
||||
* the value. Thus, an admin doesn't need a magic HBAAPI decoder ring
|
||||
* to understand the values. The HBAAPI user-space library is free to
|
||||
* convert the strings into the HBAAPI-specified binary values.
|
||||
*
|
||||
* Note: Not all HBAAPI-defined values are contained in the definitions
|
||||
* below. Those not appropriate to an fc_host (e.g. FCP initiator) have
|
||||
* been removed.
|
||||
*/
|
||||
|
||||
/*
|
||||
* fc_port_type: If you alter this, you also need to alter scsi_transport_fc.c
|
||||
* (for the ascii descriptions).
|
||||
*/
|
||||
enum fc_port_type {
|
||||
FC_PORTTYPE_UNKNOWN,
|
||||
FC_PORTTYPE_OTHER,
|
||||
FC_PORTTYPE_NOTPRESENT,
|
||||
FC_PORTTYPE_NPORT, /* Attached to FPort */
|
||||
FC_PORTTYPE_NLPORT, /* (Public) Loop w/ FLPort */
|
||||
FC_PORTTYPE_LPORT, /* (Private) Loop w/o FLPort */
|
||||
FC_PORTTYPE_PTP, /* Point to Point w/ another NPort */
|
||||
};
|
||||
|
||||
/*
|
||||
* fc_port_state: If you alter this, you also need to alter scsi_transport_fc.c
|
||||
* (for the ascii descriptions).
|
||||
*/
|
||||
enum fc_port_state {
|
||||
FC_PORTSTATE_UNKNOWN,
|
||||
FC_PORTSTATE_NOTPRESENT,
|
||||
FC_PORTSTATE_ONLINE,
|
||||
FC_PORTSTATE_OFFLINE, /* User has taken Port Offline */
|
||||
FC_PORTSTATE_BLOCKED,
|
||||
FC_PORTSTATE_BYPASSED,
|
||||
FC_PORTSTATE_DIAGNOSTICS,
|
||||
FC_PORTSTATE_LINKDOWN,
|
||||
FC_PORTSTATE_ERROR,
|
||||
FC_PORTSTATE_LOOPBACK,
|
||||
FC_PORTSTATE_DELETED,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* FC Classes of Service
|
||||
* Note: values are not enumerated, as they can be "or'd" together
|
||||
* for reporting (e.g. report supported_classes). If you alter this list,
|
||||
* you also need to alter scsi_transport_fc.c (for the ascii descriptions).
|
||||
*/
|
||||
#define FC_COS_UNSPECIFIED 0
|
||||
#define FC_COS_CLASS1 2
|
||||
#define FC_COS_CLASS2 4
|
||||
#define FC_COS_CLASS3 8
|
||||
#define FC_COS_CLASS4 0x10
|
||||
#define FC_COS_CLASS6 0x40
|
||||
|
||||
/*
|
||||
* FC Port Speeds
|
||||
* Note: values are not enumerated, as they can be "or'd" together
|
||||
* for reporting (e.g. report supported_speeds). If you alter this list,
|
||||
* you also need to alter scsi_transport_fc.c (for the ascii descriptions).
|
||||
*/
|
||||
#define FC_PORTSPEED_UNKNOWN 0 /* Unknown - transceiver
|
||||
incapable of reporting */
|
||||
#define FC_PORTSPEED_1GBIT 1
|
||||
#define FC_PORTSPEED_2GBIT 2
|
||||
#define FC_PORTSPEED_4GBIT 4
|
||||
#define FC_PORTSPEED_10GBIT 8
|
||||
#define FC_PORTSPEED_NOT_NEGOTIATED (1 << 15) /* Speed not established */
|
||||
|
||||
/*
|
||||
* fc_tgtid_binding_type: If you alter this, you also need to alter
|
||||
* scsi_transport_fc.c (for the ascii descriptions).
|
||||
*/
|
||||
enum fc_tgtid_binding_type {
|
||||
FC_TGTID_BIND_NONE,
|
||||
FC_TGTID_BIND_BY_WWPN,
|
||||
FC_TGTID_BIND_BY_WWNN,
|
||||
FC_TGTID_BIND_BY_ID,
|
||||
};
|
||||
|
||||
/*
|
||||
* FC Remote Port Roles
|
||||
* Note: values are not enumerated, as they can be "or'd" together
|
||||
* for reporting (e.g. report roles). If you alter this list,
|
||||
* you also need to alter scsi_transport_fc.c (for the ascii descriptions).
|
||||
*/
|
||||
#define FC_RPORT_ROLE_UNKNOWN 0x00
|
||||
#define FC_RPORT_ROLE_FCP_TARGET 0x01
|
||||
#define FC_RPORT_ROLE_FCP_INITIATOR 0x02
|
||||
#define FC_RPORT_ROLE_IP_PORT 0x04
|
||||
|
||||
|
||||
/*
|
||||
* fc_rport_identifiers: This set of data contains all elements
|
||||
* to uniquely identify a remote FC port. The driver uses this data
|
||||
* to report the existence of a remote FC port in the topology. Internally,
|
||||
* the transport uses this data for attributes and to manage consistent
|
||||
* target id bindings.
|
||||
*/
|
||||
struct fc_rport_identifiers {
|
||||
u64 node_name;
|
||||
u64 port_name;
|
||||
u32 port_id;
|
||||
u32 roles;
|
||||
};
|
||||
|
||||
/* Macro for use in defining Remote Port attributes */
|
||||
#define FC_RPORT_ATTR(_name,_mode,_show,_store) \
|
||||
struct class_device_attribute class_device_attr_rport_##_name = \
|
||||
__ATTR(_name,_mode,_show,_store)
|
||||
|
||||
|
||||
/*
|
||||
* FC Remote Port Attributes
|
||||
*
|
||||
* This structure exists for each remote FC port that a LLDD notifies
|
||||
* the subsystem of. A remote FC port may or may not be a SCSI Target,
|
||||
* also be a SCSI initiator, IP endpoint, etc. As such, the remote
|
||||
* port is considered a separate entity, independent of "role" (such
|
||||
* as scsi target).
|
||||
*
|
||||
* --
|
||||
*
|
||||
* Attributes are based on HBAAPI V2.0 definitions. Only those
|
||||
* attributes that are determinable by the local port (aka Host)
|
||||
* are contained.
|
||||
*
|
||||
* Fixed attributes are not expected to change. The driver is
|
||||
* expected to set these values after successfully calling
|
||||
* fc_remote_port_add(). The transport fully manages all get functions
|
||||
* w/o driver interaction.
|
||||
*
|
||||
* Dynamic attributes are expected to change. The driver participates
|
||||
* in all get/set operations via functions provided by the driver.
|
||||
*
|
||||
* Private attributes are transport-managed values. They are fully
|
||||
* managed by the transport w/o driver interaction.
|
||||
*/
|
||||
|
||||
struct fc_rport { /* aka fc_starget_attrs */
|
||||
/* Fixed Attributes */
|
||||
u32 maxframe_size;
|
||||
u32 supported_classes;
|
||||
|
||||
/* Dynamic Attributes */
|
||||
u32 dev_loss_tmo; /* Remote Port loss timeout in seconds. */
|
||||
|
||||
/* Private (Transport-managed) Attributes */
|
||||
u64 node_name;
|
||||
u64 port_name;
|
||||
u32 port_id;
|
||||
u32 roles;
|
||||
enum fc_port_state port_state; /* Will only be ONLINE or UNKNOWN */
|
||||
u32 scsi_target_id;
|
||||
u32 fast_io_fail_tmo;
|
||||
|
||||
/* exported data */
|
||||
void *dd_data; /* Used for driver-specific storage */
|
||||
|
||||
/* internal data */
|
||||
unsigned int channel;
|
||||
u32 number;
|
||||
u8 flags;
|
||||
struct list_head peers;
|
||||
struct device dev;
|
||||
struct delayed_work dev_loss_work;
|
||||
struct work_struct scan_work;
|
||||
struct delayed_work fail_io_work;
|
||||
struct work_struct stgt_delete_work;
|
||||
struct work_struct rport_delete_work;
|
||||
} __attribute__((aligned(sizeof(unsigned long))));
|
||||
|
||||
/* bit field values for struct fc_rport "flags" field: */
|
||||
#define FC_RPORT_DEVLOSS_PENDING 0x01
|
||||
#define FC_RPORT_SCAN_PENDING 0x02
|
||||
|
||||
#define dev_to_rport(d) \
|
||||
container_of(d, struct fc_rport, dev)
|
||||
#define transport_class_to_rport(classdev) \
|
||||
dev_to_rport(classdev->dev)
|
||||
#define rport_to_shost(r) \
|
||||
dev_to_shost(r->dev.parent)
|
||||
|
||||
/*
|
||||
* FC SCSI Target Attributes
|
||||
*
|
||||
* The SCSI Target is considered an extention of a remote port (as
|
||||
* a remote port can be more than a SCSI Target). Within the scsi
|
||||
* subsystem, we leave the Target as a separate entity. Doing so
|
||||
* provides backward compatibility with prior FC transport api's,
|
||||
* and lets remote ports be handled entirely within the FC transport
|
||||
* and independently from the scsi subsystem. The drawback is that
|
||||
* some data will be duplicated.
|
||||
*/
|
||||
|
||||
struct fc_starget_attrs { /* aka fc_target_attrs */
|
||||
/* Dynamic Attributes */
|
||||
u64 node_name;
|
||||
u64 port_name;
|
||||
u32 port_id;
|
||||
};
|
||||
|
||||
#define fc_starget_node_name(x) \
|
||||
(((struct fc_starget_attrs *)&(x)->starget_data)->node_name)
|
||||
#define fc_starget_port_name(x) \
|
||||
(((struct fc_starget_attrs *)&(x)->starget_data)->port_name)
|
||||
#define fc_starget_port_id(x) \
|
||||
(((struct fc_starget_attrs *)&(x)->starget_data)->port_id)
|
||||
|
||||
#define starget_to_rport(s) \
|
||||
scsi_is_fc_rport(s->dev.parent) ? dev_to_rport(s->dev.parent) : NULL
|
||||
|
||||
|
||||
/*
|
||||
* FC Local Port (Host) Statistics
|
||||
*/
|
||||
|
||||
/* FC Statistics - Following FC HBAAPI v2.0 guidelines */
|
||||
struct fc_host_statistics {
|
||||
/* port statistics */
|
||||
u64 seconds_since_last_reset;
|
||||
u64 tx_frames;
|
||||
u64 tx_words;
|
||||
u64 rx_frames;
|
||||
u64 rx_words;
|
||||
u64 lip_count;
|
||||
u64 nos_count;
|
||||
u64 error_frames;
|
||||
u64 dumped_frames;
|
||||
u64 link_failure_count;
|
||||
u64 loss_of_sync_count;
|
||||
u64 loss_of_signal_count;
|
||||
u64 prim_seq_protocol_err_count;
|
||||
u64 invalid_tx_word_count;
|
||||
u64 invalid_crc_count;
|
||||
|
||||
/* fc4 statistics (only FCP supported currently) */
|
||||
u64 fcp_input_requests;
|
||||
u64 fcp_output_requests;
|
||||
u64 fcp_control_requests;
|
||||
u64 fcp_input_megabytes;
|
||||
u64 fcp_output_megabytes;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* FC Event Codes - Polled and Async, following FC HBAAPI v2.0 guidelines
|
||||
*/
|
||||
|
||||
/*
|
||||
* fc_host_event_code: If you alter this, you also need to alter
|
||||
* scsi_transport_fc.c (for the ascii descriptions).
|
||||
*/
|
||||
enum fc_host_event_code {
|
||||
FCH_EVT_LIP = 0x1,
|
||||
FCH_EVT_LINKUP = 0x2,
|
||||
FCH_EVT_LINKDOWN = 0x3,
|
||||
FCH_EVT_LIPRESET = 0x4,
|
||||
FCH_EVT_RSCN = 0x5,
|
||||
FCH_EVT_ADAPTER_CHANGE = 0x103,
|
||||
FCH_EVT_PORT_UNKNOWN = 0x200,
|
||||
FCH_EVT_PORT_OFFLINE = 0x201,
|
||||
FCH_EVT_PORT_ONLINE = 0x202,
|
||||
FCH_EVT_PORT_FABRIC = 0x204,
|
||||
FCH_EVT_LINK_UNKNOWN = 0x500,
|
||||
FCH_EVT_VENDOR_UNIQUE = 0xffff,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* FC Local Port (Host) Attributes
|
||||
*
|
||||
* Attributes are based on HBAAPI V2.0 definitions.
|
||||
* Note: OSDeviceName is determined by user-space library
|
||||
*
|
||||
* Fixed attributes are not expected to change. The driver is
|
||||
* expected to set these values after successfully calling scsi_add_host().
|
||||
* The transport fully manages all get functions w/o driver interaction.
|
||||
*
|
||||
* Dynamic attributes are expected to change. The driver participates
|
||||
* in all get/set operations via functions provided by the driver.
|
||||
*
|
||||
* Private attributes are transport-managed values. They are fully
|
||||
* managed by the transport w/o driver interaction.
|
||||
*/
|
||||
|
||||
#define FC_FC4_LIST_SIZE 32
|
||||
#define FC_SYMBOLIC_NAME_SIZE 256
|
||||
#define FC_VERSION_STRING_SIZE 64
|
||||
#define FC_SERIAL_NUMBER_SIZE 80
|
||||
|
||||
struct fc_host_attrs {
|
||||
/* Fixed Attributes */
|
||||
u64 node_name;
|
||||
u64 port_name;
|
||||
u64 permanent_port_name;
|
||||
u32 supported_classes;
|
||||
u8 supported_fc4s[FC_FC4_LIST_SIZE];
|
||||
u32 supported_speeds;
|
||||
u32 maxframe_size;
|
||||
char serial_number[FC_SERIAL_NUMBER_SIZE];
|
||||
|
||||
/* Dynamic Attributes */
|
||||
u32 port_id;
|
||||
enum fc_port_type port_type;
|
||||
enum fc_port_state port_state;
|
||||
u8 active_fc4s[FC_FC4_LIST_SIZE];
|
||||
u32 speed;
|
||||
u64 fabric_name;
|
||||
char symbolic_name[FC_SYMBOLIC_NAME_SIZE];
|
||||
char system_hostname[FC_SYMBOLIC_NAME_SIZE];
|
||||
|
||||
/* Private (Transport-managed) Attributes */
|
||||
enum fc_tgtid_binding_type tgtid_bind_type;
|
||||
|
||||
/* internal data */
|
||||
struct list_head rports;
|
||||
struct list_head rport_bindings;
|
||||
u32 next_rport_number;
|
||||
u32 next_target_id;
|
||||
|
||||
/* work queues for rport state manipulation */
|
||||
char work_q_name[KOBJ_NAME_LEN];
|
||||
struct workqueue_struct *work_q;
|
||||
char devloss_work_q_name[KOBJ_NAME_LEN];
|
||||
struct workqueue_struct *devloss_work_q;
|
||||
};
|
||||
|
||||
#define shost_to_fc_host(x) \
|
||||
((struct fc_host_attrs *)(x)->shost_data)
|
||||
|
||||
#define fc_host_node_name(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->node_name)
|
||||
#define fc_host_port_name(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->port_name)
|
||||
#define fc_host_permanent_port_name(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->permanent_port_name)
|
||||
#define fc_host_supported_classes(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->supported_classes)
|
||||
#define fc_host_supported_fc4s(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->supported_fc4s)
|
||||
#define fc_host_supported_speeds(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->supported_speeds)
|
||||
#define fc_host_maxframe_size(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->maxframe_size)
|
||||
#define fc_host_serial_number(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->serial_number)
|
||||
#define fc_host_port_id(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->port_id)
|
||||
#define fc_host_port_type(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->port_type)
|
||||
#define fc_host_port_state(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->port_state)
|
||||
#define fc_host_active_fc4s(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->active_fc4s)
|
||||
#define fc_host_speed(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->speed)
|
||||
#define fc_host_fabric_name(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->fabric_name)
|
||||
#define fc_host_symbolic_name(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->symbolic_name)
|
||||
#define fc_host_system_hostname(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->system_hostname)
|
||||
#define fc_host_tgtid_bind_type(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->tgtid_bind_type)
|
||||
#define fc_host_rports(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->rports)
|
||||
#define fc_host_rport_bindings(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->rport_bindings)
|
||||
#define fc_host_next_rport_number(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->next_rport_number)
|
||||
#define fc_host_next_target_id(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->next_target_id)
|
||||
#define fc_host_work_q_name(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->work_q_name)
|
||||
#define fc_host_work_q(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->work_q)
|
||||
#define fc_host_devloss_work_q_name(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q_name)
|
||||
#define fc_host_devloss_work_q(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q)
|
||||
|
||||
|
||||
/* The functions by which the transport class and the driver communicate */
|
||||
struct fc_function_template {
|
||||
void (*get_rport_dev_loss_tmo)(struct fc_rport *);
|
||||
void (*set_rport_dev_loss_tmo)(struct fc_rport *, u32);
|
||||
|
||||
void (*get_starget_node_name)(struct scsi_target *);
|
||||
void (*get_starget_port_name)(struct scsi_target *);
|
||||
void (*get_starget_port_id)(struct scsi_target *);
|
||||
|
||||
void (*get_host_port_id)(struct Scsi_Host *);
|
||||
void (*get_host_port_type)(struct Scsi_Host *);
|
||||
void (*get_host_port_state)(struct Scsi_Host *);
|
||||
void (*get_host_active_fc4s)(struct Scsi_Host *);
|
||||
void (*get_host_speed)(struct Scsi_Host *);
|
||||
void (*get_host_fabric_name)(struct Scsi_Host *);
|
||||
void (*get_host_symbolic_name)(struct Scsi_Host *);
|
||||
void (*set_host_system_hostname)(struct Scsi_Host *);
|
||||
|
||||
struct fc_host_statistics * (*get_fc_host_stats)(struct Scsi_Host *);
|
||||
void (*reset_fc_host_stats)(struct Scsi_Host *);
|
||||
|
||||
int (*issue_fc_host_lip)(struct Scsi_Host *);
|
||||
|
||||
void (*dev_loss_tmo_callbk)(struct fc_rport *);
|
||||
void (*terminate_rport_io)(struct fc_rport *);
|
||||
|
||||
/* allocation lengths for host-specific data */
|
||||
u32 dd_fcrport_size;
|
||||
|
||||
/*
|
||||
* The driver sets these to tell the transport class it
|
||||
* wants the attributes displayed in sysfs. If the show_ flag
|
||||
* is not set, the attribute will be private to the transport
|
||||
* class
|
||||
*/
|
||||
|
||||
/* remote port fixed attributes */
|
||||
unsigned long show_rport_maxframe_size:1;
|
||||
unsigned long show_rport_supported_classes:1;
|
||||
unsigned long show_rport_dev_loss_tmo:1;
|
||||
|
||||
/*
|
||||
* target dynamic attributes
|
||||
* These should all be "1" if the driver uses the remote port
|
||||
* add/delete functions (so attributes reflect rport values).
|
||||
*/
|
||||
unsigned long show_starget_node_name:1;
|
||||
unsigned long show_starget_port_name:1;
|
||||
unsigned long show_starget_port_id:1;
|
||||
|
||||
/* host fixed attributes */
|
||||
unsigned long show_host_node_name:1;
|
||||
unsigned long show_host_port_name:1;
|
||||
unsigned long show_host_permanent_port_name:1;
|
||||
unsigned long show_host_supported_classes:1;
|
||||
unsigned long show_host_supported_fc4s:1;
|
||||
unsigned long show_host_supported_speeds:1;
|
||||
unsigned long show_host_maxframe_size:1;
|
||||
unsigned long show_host_serial_number:1;
|
||||
/* host dynamic attributes */
|
||||
unsigned long show_host_port_id:1;
|
||||
unsigned long show_host_port_type:1;
|
||||
unsigned long show_host_port_state:1;
|
||||
unsigned long show_host_active_fc4s:1;
|
||||
unsigned long show_host_speed:1;
|
||||
unsigned long show_host_fabric_name:1;
|
||||
unsigned long show_host_symbolic_name:1;
|
||||
unsigned long show_host_system_hostname:1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* fc_remote_port_chkready - called to validate the remote port state
|
||||
* prior to initiating io to the port.
|
||||
*
|
||||
* Returns a scsi result code that can be returned by the LLDD.
|
||||
*
|
||||
* @rport: remote port to be checked
|
||||
**/
|
||||
static inline int
|
||||
fc_remote_port_chkready(struct fc_rport *rport)
|
||||
{
|
||||
int result;
|
||||
|
||||
switch (rport->port_state) {
|
||||
case FC_PORTSTATE_ONLINE:
|
||||
if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
|
||||
result = 0;
|
||||
else if (rport->flags & FC_RPORT_DEVLOSS_PENDING)
|
||||
result = DID_IMM_RETRY << 16;
|
||||
else
|
||||
result = DID_NO_CONNECT << 16;
|
||||
break;
|
||||
case FC_PORTSTATE_BLOCKED:
|
||||
result = DID_IMM_RETRY << 16;
|
||||
break;
|
||||
default:
|
||||
result = DID_NO_CONNECT << 16;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline u64 wwn_to_u64(u8 *wwn)
|
||||
{
|
||||
return (u64)wwn[0] << 56 | (u64)wwn[1] << 48 |
|
||||
(u64)wwn[2] << 40 | (u64)wwn[3] << 32 |
|
||||
(u64)wwn[4] << 24 | (u64)wwn[5] << 16 |
|
||||
(u64)wwn[6] << 8 | (u64)wwn[7];
|
||||
}
|
||||
|
||||
static inline void u64_to_wwn(u64 inm, u8 *wwn)
|
||||
{
|
||||
wwn[0] = (inm >> 56) & 0xff;
|
||||
wwn[1] = (inm >> 48) & 0xff;
|
||||
wwn[2] = (inm >> 40) & 0xff;
|
||||
wwn[3] = (inm >> 32) & 0xff;
|
||||
wwn[4] = (inm >> 24) & 0xff;
|
||||
wwn[5] = (inm >> 16) & 0xff;
|
||||
wwn[6] = (inm >> 8) & 0xff;
|
||||
wwn[7] = inm & 0xff;
|
||||
}
|
||||
|
||||
struct scsi_transport_template *fc_attach_transport(
|
||||
struct fc_function_template *);
|
||||
void fc_release_transport(struct scsi_transport_template *);
|
||||
void fc_remove_host(struct Scsi_Host *);
|
||||
struct fc_rport *fc_remote_port_add(struct Scsi_Host *shost,
|
||||
int channel, struct fc_rport_identifiers *ids);
|
||||
void fc_remote_port_delete(struct fc_rport *rport);
|
||||
void fc_remote_port_rolechg(struct fc_rport *rport, u32 roles);
|
||||
int scsi_is_fc_rport(const struct device *);
|
||||
u32 fc_get_event_number(void);
|
||||
void fc_host_post_event(struct Scsi_Host *shost, u32 event_number,
|
||||
enum fc_host_event_code event_code, u32 event_data);
|
||||
void fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
|
||||
u32 data_len, char * data_buf, u64 vendor_id);
|
||||
/* Note: when specifying vendor_id to fc_host_post_vendor_event()
|
||||
* be sure to read the Vendor Type and ID formatting requirements
|
||||
* specified in scsi_netlink.h
|
||||
*/
|
||||
|
||||
#endif /* SCSI_TRANSPORT_FC_H */
|
||||
224
include/scsi/scsi_transport_iscsi.h
Normal file
224
include/scsi/scsi_transport_iscsi.h
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* iSCSI transport class definitions
|
||||
*
|
||||
* Copyright (C) IBM Corporation, 2004
|
||||
* Copyright (C) Mike Christie, 2004 - 2006
|
||||
* Copyright (C) Dmitry Yusupov, 2004 - 2005
|
||||
* Copyright (C) Alex Aizman, 2004 - 2005
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef SCSI_TRANSPORT_ISCSI_H
|
||||
#define SCSI_TRANSPORT_ISCSI_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <scsi/iscsi_if.h>
|
||||
|
||||
struct scsi_transport_template;
|
||||
struct iscsi_transport;
|
||||
struct Scsi_Host;
|
||||
struct iscsi_cls_conn;
|
||||
struct iscsi_conn;
|
||||
struct iscsi_cmd_task;
|
||||
struct iscsi_mgmt_task;
|
||||
struct sockaddr;
|
||||
|
||||
/**
|
||||
* struct iscsi_transport - iSCSI Transport template
|
||||
*
|
||||
* @name: transport name
|
||||
* @caps: iSCSI Data-Path capabilities
|
||||
* @create_session: create new iSCSI session object
|
||||
* @destroy_session: destroy existing iSCSI session object
|
||||
* @create_conn: create new iSCSI connection
|
||||
* @bind_conn: associate this connection with existing iSCSI session
|
||||
* and specified transport descriptor
|
||||
* @destroy_conn: destroy inactive iSCSI connection
|
||||
* @set_param: set iSCSI parameter. Return 0 on success, -ENODATA
|
||||
* when param is not supported, and a -Exx value on other
|
||||
* error.
|
||||
* @get_param get iSCSI parameter. Must return number of bytes
|
||||
* copied to buffer on success, -ENODATA when param
|
||||
* is not supported, and a -Exx value on other error
|
||||
* @start_conn: set connection to be operational
|
||||
* @stop_conn: suspend/recover/terminate connection
|
||||
* @send_pdu: send iSCSI PDU, Login, Logout, NOP-Out, Reject, Text.
|
||||
* @session_recovery_timedout: notify LLD a block during recovery timed out
|
||||
* @init_cmd_task: Initialize a iscsi_cmd_task and any internal structs.
|
||||
* Called from queuecommand with session lock held.
|
||||
* @init_mgmt_task: Initialize a iscsi_mgmt_task and any internal structs.
|
||||
* Called from iscsi_conn_send_generic with xmitmutex.
|
||||
* @xmit_cmd_task: Requests LLD to transfer cmd task. Returns 0 or the
|
||||
* the number of bytes transferred on success, and -Exyz
|
||||
* value on error.
|
||||
* @xmit_mgmt_task: Requests LLD to transfer mgmt task. Returns 0 or the
|
||||
* the number of bytes transferred on success, and -Exyz
|
||||
* value on error.
|
||||
* @cleanup_cmd_task: requests LLD to fail cmd task. Called with xmitmutex
|
||||
* and session->lock after the connection has been
|
||||
* suspended and terminated during recovery. If called
|
||||
* from abort task then connection is not suspended
|
||||
* or terminated but sk_callback_lock is held
|
||||
*
|
||||
* Template API provided by iSCSI Transport
|
||||
*/
|
||||
struct iscsi_transport {
|
||||
struct module *owner;
|
||||
char *name;
|
||||
unsigned int caps;
|
||||
/* LLD sets this to indicate what values it can export to sysfs */
|
||||
unsigned int param_mask;
|
||||
struct scsi_host_template *host_template;
|
||||
/* LLD connection data size */
|
||||
int conndata_size;
|
||||
/* LLD session data size */
|
||||
int sessiondata_size;
|
||||
int max_lun;
|
||||
unsigned int max_conn;
|
||||
unsigned int max_cmd_len;
|
||||
struct iscsi_cls_session *(*create_session) (struct iscsi_transport *it,
|
||||
struct scsi_transport_template *t, uint32_t sn, uint32_t *hn);
|
||||
void (*destroy_session) (struct iscsi_cls_session *session);
|
||||
struct iscsi_cls_conn *(*create_conn) (struct iscsi_cls_session *sess,
|
||||
uint32_t cid);
|
||||
int (*bind_conn) (struct iscsi_cls_session *session,
|
||||
struct iscsi_cls_conn *cls_conn,
|
||||
uint64_t transport_eph, int is_leading);
|
||||
int (*start_conn) (struct iscsi_cls_conn *conn);
|
||||
void (*stop_conn) (struct iscsi_cls_conn *conn, int flag);
|
||||
void (*destroy_conn) (struct iscsi_cls_conn *conn);
|
||||
int (*set_param) (struct iscsi_cls_conn *conn, enum iscsi_param param,
|
||||
char *buf, int buflen);
|
||||
int (*get_conn_param) (struct iscsi_cls_conn *conn,
|
||||
enum iscsi_param param, char *buf);
|
||||
int (*get_session_param) (struct iscsi_cls_session *session,
|
||||
enum iscsi_param param, char *buf);
|
||||
int (*send_pdu) (struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
|
||||
char *data, uint32_t data_size);
|
||||
void (*get_stats) (struct iscsi_cls_conn *conn,
|
||||
struct iscsi_stats *stats);
|
||||
void (*init_cmd_task) (struct iscsi_cmd_task *ctask);
|
||||
void (*init_mgmt_task) (struct iscsi_conn *conn,
|
||||
struct iscsi_mgmt_task *mtask,
|
||||
char *data, uint32_t data_size);
|
||||
int (*xmit_cmd_task) (struct iscsi_conn *conn,
|
||||
struct iscsi_cmd_task *ctask);
|
||||
void (*cleanup_cmd_task) (struct iscsi_conn *conn,
|
||||
struct iscsi_cmd_task *ctask);
|
||||
int (*xmit_mgmt_task) (struct iscsi_conn *conn,
|
||||
struct iscsi_mgmt_task *mtask);
|
||||
void (*session_recovery_timedout) (struct iscsi_cls_session *session);
|
||||
int (*ep_connect) (struct sockaddr *dst_addr, int non_blocking,
|
||||
uint64_t *ep_handle);
|
||||
int (*ep_poll) (uint64_t ep_handle, int timeout_ms);
|
||||
void (*ep_disconnect) (uint64_t ep_handle);
|
||||
int (*tgt_dscvr) (enum iscsi_tgt_dscvr type, uint32_t host_no,
|
||||
uint32_t enable, struct sockaddr *dst_addr);
|
||||
};
|
||||
|
||||
/*
|
||||
* transport registration upcalls
|
||||
*/
|
||||
extern struct scsi_transport_template *iscsi_register_transport(struct iscsi_transport *tt);
|
||||
extern int iscsi_unregister_transport(struct iscsi_transport *tt);
|
||||
|
||||
/*
|
||||
* control plane upcalls
|
||||
*/
|
||||
extern void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error);
|
||||
extern int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
|
||||
char *data, uint32_t data_size);
|
||||
|
||||
|
||||
/* Connection's states */
|
||||
#define ISCSI_CONN_INITIAL_STAGE 0
|
||||
#define ISCSI_CONN_STARTED 1
|
||||
#define ISCSI_CONN_STOPPED 2
|
||||
#define ISCSI_CONN_CLEANUP_WAIT 3
|
||||
|
||||
struct iscsi_cls_conn {
|
||||
struct list_head conn_list; /* item in connlist */
|
||||
void *dd_data; /* LLD private data */
|
||||
struct iscsi_transport *transport;
|
||||
uint32_t cid; /* connection id */
|
||||
|
||||
int active; /* must be accessed with the connlock */
|
||||
struct device dev; /* sysfs transport/container device */
|
||||
};
|
||||
|
||||
#define iscsi_dev_to_conn(_dev) \
|
||||
container_of(_dev, struct iscsi_cls_conn, dev)
|
||||
|
||||
/* Session's states */
|
||||
#define ISCSI_STATE_FREE 1
|
||||
#define ISCSI_STATE_LOGGED_IN 2
|
||||
#define ISCSI_STATE_FAILED 3
|
||||
#define ISCSI_STATE_TERMINATE 4
|
||||
#define ISCSI_STATE_IN_RECOVERY 5
|
||||
#define ISCSI_STATE_RECOVERY_FAILED 6
|
||||
|
||||
struct iscsi_cls_session {
|
||||
struct list_head sess_list; /* item in session_list */
|
||||
struct list_head host_list;
|
||||
struct iscsi_transport *transport;
|
||||
|
||||
/* recovery fields */
|
||||
int recovery_tmo;
|
||||
struct delayed_work recovery_work;
|
||||
|
||||
int target_id;
|
||||
|
||||
int sid; /* session id */
|
||||
void *dd_data; /* LLD private data */
|
||||
struct device dev; /* sysfs transport/container device */
|
||||
};
|
||||
|
||||
#define iscsi_dev_to_session(_dev) \
|
||||
container_of(_dev, struct iscsi_cls_session, dev)
|
||||
|
||||
#define iscsi_session_to_shost(_session) \
|
||||
dev_to_shost(_session->dev.parent)
|
||||
|
||||
#define starget_to_session(_stgt) \
|
||||
iscsi_dev_to_session(_stgt->dev.parent)
|
||||
|
||||
struct iscsi_host {
|
||||
struct list_head sessions;
|
||||
struct mutex mutex;
|
||||
};
|
||||
|
||||
/*
|
||||
* session and connection functions that can be used by HW iSCSI LLDs
|
||||
*/
|
||||
extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost,
|
||||
struct iscsi_transport *transport);
|
||||
extern int iscsi_add_session(struct iscsi_cls_session *session,
|
||||
unsigned int target_id);
|
||||
extern int iscsi_if_create_session_done(struct iscsi_cls_conn *conn);
|
||||
extern int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn);
|
||||
extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost,
|
||||
struct iscsi_transport *t,
|
||||
unsigned int target_id);
|
||||
extern void iscsi_remove_session(struct iscsi_cls_session *session);
|
||||
extern void iscsi_free_session(struct iscsi_cls_session *session);
|
||||
extern int iscsi_destroy_session(struct iscsi_cls_session *session);
|
||||
extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess,
|
||||
uint32_t cid);
|
||||
extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn);
|
||||
extern void iscsi_unblock_session(struct iscsi_cls_session *session);
|
||||
extern void iscsi_block_session(struct iscsi_cls_session *session);
|
||||
|
||||
|
||||
#endif
|
||||
217
include/scsi/scsi_transport_sas.h
Normal file
217
include/scsi/scsi_transport_sas.h
Normal file
@@ -0,0 +1,217 @@
|
||||
#ifndef SCSI_TRANSPORT_SAS_H
|
||||
#define SCSI_TRANSPORT_SAS_H
|
||||
|
||||
#include <linux/transport_class.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
struct scsi_transport_template;
|
||||
struct sas_rphy;
|
||||
|
||||
|
||||
enum sas_device_type {
|
||||
SAS_PHY_UNUSED,
|
||||
SAS_END_DEVICE,
|
||||
SAS_EDGE_EXPANDER_DEVICE,
|
||||
SAS_FANOUT_EXPANDER_DEVICE,
|
||||
};
|
||||
|
||||
enum sas_protocol {
|
||||
SAS_PROTOCOL_SATA = 0x01,
|
||||
SAS_PROTOCOL_SMP = 0x02,
|
||||
SAS_PROTOCOL_STP = 0x04,
|
||||
SAS_PROTOCOL_SSP = 0x08,
|
||||
};
|
||||
|
||||
enum sas_linkrate {
|
||||
/* These Values are defined in the SAS standard */
|
||||
SAS_LINK_RATE_UNKNOWN = 0,
|
||||
SAS_PHY_DISABLED = 1,
|
||||
SAS_PHY_RESET_PROBLEM = 2,
|
||||
SAS_SATA_SPINUP_HOLD = 3,
|
||||
SAS_SATA_PORT_SELECTOR = 4,
|
||||
SAS_PHY_RESET_IN_PROGRESS = 5,
|
||||
SAS_LINK_RATE_1_5_GBPS = 8,
|
||||
SAS_LINK_RATE_G1 = SAS_LINK_RATE_1_5_GBPS,
|
||||
SAS_LINK_RATE_3_0_GBPS = 9,
|
||||
SAS_LINK_RATE_G2 = SAS_LINK_RATE_3_0_GBPS,
|
||||
SAS_LINK_RATE_6_0_GBPS = 10,
|
||||
/* These are virtual to the transport class and may never
|
||||
* be signalled normally since the standard defined field
|
||||
* is only 4 bits */
|
||||
SAS_LINK_RATE_FAILED = 0x10,
|
||||
SAS_PHY_VIRTUAL = 0x11,
|
||||
};
|
||||
|
||||
struct sas_identify {
|
||||
enum sas_device_type device_type;
|
||||
enum sas_protocol initiator_port_protocols;
|
||||
enum sas_protocol target_port_protocols;
|
||||
u64 sas_address;
|
||||
u8 phy_identifier;
|
||||
};
|
||||
|
||||
struct sas_phy {
|
||||
struct device dev;
|
||||
int number;
|
||||
int enabled;
|
||||
|
||||
/* phy identification */
|
||||
struct sas_identify identify;
|
||||
|
||||
/* phy attributes */
|
||||
enum sas_linkrate negotiated_linkrate;
|
||||
enum sas_linkrate minimum_linkrate_hw;
|
||||
enum sas_linkrate minimum_linkrate;
|
||||
enum sas_linkrate maximum_linkrate_hw;
|
||||
enum sas_linkrate maximum_linkrate;
|
||||
|
||||
/* link error statistics */
|
||||
u32 invalid_dword_count;
|
||||
u32 running_disparity_error_count;
|
||||
u32 loss_of_dword_sync_count;
|
||||
u32 phy_reset_problem_count;
|
||||
|
||||
/* for the list of phys belonging to a port */
|
||||
struct list_head port_siblings;
|
||||
|
||||
struct work_struct reset_work;
|
||||
};
|
||||
|
||||
#define dev_to_phy(d) \
|
||||
container_of((d), struct sas_phy, dev)
|
||||
#define transport_class_to_phy(cdev) \
|
||||
dev_to_phy((cdev)->dev)
|
||||
#define phy_to_shost(phy) \
|
||||
dev_to_shost((phy)->dev.parent)
|
||||
|
||||
struct sas_rphy {
|
||||
struct device dev;
|
||||
struct sas_identify identify;
|
||||
struct list_head list;
|
||||
u32 scsi_target_id;
|
||||
};
|
||||
|
||||
#define dev_to_rphy(d) \
|
||||
container_of((d), struct sas_rphy, dev)
|
||||
#define transport_class_to_rphy(cdev) \
|
||||
dev_to_rphy((cdev)->dev)
|
||||
#define rphy_to_shost(rphy) \
|
||||
dev_to_shost((rphy)->dev.parent)
|
||||
#define target_to_rphy(targ) \
|
||||
dev_to_rphy((targ)->dev.parent)
|
||||
|
||||
struct sas_end_device {
|
||||
struct sas_rphy rphy;
|
||||
/* flags */
|
||||
unsigned ready_led_meaning:1;
|
||||
/* parameters */
|
||||
u16 I_T_nexus_loss_timeout;
|
||||
u16 initiator_response_timeout;
|
||||
};
|
||||
#define rphy_to_end_device(r) \
|
||||
container_of((r), struct sas_end_device, rphy)
|
||||
|
||||
struct sas_expander_device {
|
||||
int level;
|
||||
int next_port_id;
|
||||
|
||||
#define SAS_EXPANDER_VENDOR_ID_LEN 8
|
||||
char vendor_id[SAS_EXPANDER_VENDOR_ID_LEN+1];
|
||||
#define SAS_EXPANDER_PRODUCT_ID_LEN 16
|
||||
char product_id[SAS_EXPANDER_PRODUCT_ID_LEN+1];
|
||||
#define SAS_EXPANDER_PRODUCT_REV_LEN 4
|
||||
char product_rev[SAS_EXPANDER_PRODUCT_REV_LEN+1];
|
||||
#define SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN 8
|
||||
char component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN+1];
|
||||
u16 component_id;
|
||||
u8 component_revision_id;
|
||||
|
||||
struct sas_rphy rphy;
|
||||
|
||||
};
|
||||
#define rphy_to_expander_device(r) \
|
||||
container_of((r), struct sas_expander_device, rphy)
|
||||
|
||||
struct sas_port {
|
||||
struct device dev;
|
||||
|
||||
int port_identifier;
|
||||
int num_phys;
|
||||
/* port flags */
|
||||
unsigned int is_backlink:1;
|
||||
|
||||
/* the other end of the link */
|
||||
struct sas_rphy *rphy;
|
||||
|
||||
struct mutex phy_list_mutex;
|
||||
struct list_head phy_list;
|
||||
};
|
||||
|
||||
#define dev_to_sas_port(d) \
|
||||
container_of((d), struct sas_port, dev)
|
||||
#define transport_class_to_sas_port(cdev) \
|
||||
dev_to_sas_port((cdev)->dev)
|
||||
|
||||
struct sas_phy_linkrates {
|
||||
enum sas_linkrate maximum_linkrate;
|
||||
enum sas_linkrate minimum_linkrate;
|
||||
};
|
||||
|
||||
/* The functions by which the transport class and the driver communicate */
|
||||
struct sas_function_template {
|
||||
int (*get_linkerrors)(struct sas_phy *);
|
||||
int (*get_enclosure_identifier)(struct sas_rphy *, u64 *);
|
||||
int (*get_bay_identifier)(struct sas_rphy *);
|
||||
int (*phy_reset)(struct sas_phy *, int);
|
||||
int (*phy_enable)(struct sas_phy *, int);
|
||||
int (*set_phy_speed)(struct sas_phy *, struct sas_phy_linkrates *);
|
||||
};
|
||||
|
||||
|
||||
void sas_remove_children(struct device *);
|
||||
extern void sas_remove_host(struct Scsi_Host *);
|
||||
|
||||
extern struct sas_phy *sas_phy_alloc(struct device *, int);
|
||||
extern void sas_phy_free(struct sas_phy *);
|
||||
extern int sas_phy_add(struct sas_phy *);
|
||||
extern void sas_phy_delete(struct sas_phy *);
|
||||
extern int scsi_is_sas_phy(const struct device *);
|
||||
|
||||
extern struct sas_rphy *sas_end_device_alloc(struct sas_port *);
|
||||
extern struct sas_rphy *sas_expander_alloc(struct sas_port *, enum sas_device_type);
|
||||
void sas_rphy_free(struct sas_rphy *);
|
||||
extern int sas_rphy_add(struct sas_rphy *);
|
||||
extern void sas_rphy_remove(struct sas_rphy *);
|
||||
extern void sas_rphy_delete(struct sas_rphy *);
|
||||
extern int scsi_is_sas_rphy(const struct device *);
|
||||
|
||||
struct sas_port *sas_port_alloc(struct device *, int);
|
||||
struct sas_port *sas_port_alloc_num(struct device *);
|
||||
int sas_port_add(struct sas_port *);
|
||||
void sas_port_free(struct sas_port *);
|
||||
void sas_port_delete(struct sas_port *);
|
||||
void sas_port_add_phy(struct sas_port *, struct sas_phy *);
|
||||
void sas_port_delete_phy(struct sas_port *, struct sas_phy *);
|
||||
void sas_port_mark_backlink(struct sas_port *);
|
||||
int scsi_is_sas_port(const struct device *);
|
||||
|
||||
extern struct scsi_transport_template *
|
||||
sas_attach_transport(struct sas_function_template *);
|
||||
extern void sas_release_transport(struct scsi_transport_template *);
|
||||
int sas_read_port_mode_page(struct scsi_device *);
|
||||
|
||||
static inline int
|
||||
scsi_is_sas_expander_device(struct device *dev)
|
||||
{
|
||||
struct sas_rphy *rphy;
|
||||
if (!scsi_is_sas_rphy(dev))
|
||||
return 0;
|
||||
rphy = dev_to_rphy(dev);
|
||||
return rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE ||
|
||||
rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE;
|
||||
}
|
||||
|
||||
#define scsi_is_sas_phy_local(phy) scsi_is_host_device((phy)->dev.parent)
|
||||
|
||||
#endif /* SCSI_TRANSPORT_SAS_H */
|
||||
157
include/scsi/scsi_transport_spi.h
Normal file
157
include/scsi/scsi_transport_spi.h
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Parallel SCSI (SPI) transport specific attributes exported to sysfs.
|
||||
*
|
||||
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef SCSI_TRANSPORT_SPI_H
|
||||
#define SCSI_TRANSPORT_SPI_H
|
||||
|
||||
#include <linux/transport_class.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
struct scsi_transport_template;
|
||||
struct scsi_target;
|
||||
struct scsi_device;
|
||||
struct Scsi_Host;
|
||||
|
||||
struct spi_transport_attrs {
|
||||
int period; /* value in the PPR/SDTR command */
|
||||
int min_period;
|
||||
int offset;
|
||||
int max_offset;
|
||||
unsigned int width:1; /* 0 - narrow, 1 - wide */
|
||||
unsigned int max_width:1;
|
||||
unsigned int iu:1; /* Information Units enabled */
|
||||
unsigned int dt:1; /* DT clocking enabled */
|
||||
unsigned int qas:1; /* Quick Arbitration and Selection enabled */
|
||||
unsigned int wr_flow:1; /* Write Flow control enabled */
|
||||
unsigned int rd_strm:1; /* Read streaming enabled */
|
||||
unsigned int rti:1; /* Retain Training Information */
|
||||
unsigned int pcomp_en:1;/* Precompensation enabled */
|
||||
unsigned int hold_mcs:1;/* Hold Margin Control Settings */
|
||||
unsigned int initial_dv:1; /* DV done to this target yet */
|
||||
unsigned long flags; /* flags field for drivers to use */
|
||||
/* Device Properties fields */
|
||||
unsigned int support_sync:1; /* synchronous support */
|
||||
unsigned int support_wide:1; /* wide support */
|
||||
unsigned int support_dt:1; /* allows DT phases */
|
||||
unsigned int support_dt_only; /* disallows ST phases */
|
||||
unsigned int support_ius; /* support Information Units */
|
||||
unsigned int support_qas; /* supports quick arbitration and selection */
|
||||
/* Private Fields */
|
||||
unsigned int dv_pending:1; /* Internal flag: DV Requested */
|
||||
unsigned int dv_in_progress:1; /* Internal: DV started */
|
||||
struct mutex dv_mutex; /* semaphore to serialise dv */
|
||||
};
|
||||
|
||||
enum spi_signal_type {
|
||||
SPI_SIGNAL_UNKNOWN = 1,
|
||||
SPI_SIGNAL_SE,
|
||||
SPI_SIGNAL_LVD,
|
||||
SPI_SIGNAL_HVD,
|
||||
};
|
||||
|
||||
struct spi_host_attrs {
|
||||
enum spi_signal_type signalling;
|
||||
};
|
||||
|
||||
/* accessor functions */
|
||||
#define spi_period(x) (((struct spi_transport_attrs *)&(x)->starget_data)->period)
|
||||
#define spi_min_period(x) (((struct spi_transport_attrs *)&(x)->starget_data)->min_period)
|
||||
#define spi_offset(x) (((struct spi_transport_attrs *)&(x)->starget_data)->offset)
|
||||
#define spi_max_offset(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_offset)
|
||||
#define spi_width(x) (((struct spi_transport_attrs *)&(x)->starget_data)->width)
|
||||
#define spi_max_width(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_width)
|
||||
#define spi_iu(x) (((struct spi_transport_attrs *)&(x)->starget_data)->iu)
|
||||
#define spi_dt(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dt)
|
||||
#define spi_qas(x) (((struct spi_transport_attrs *)&(x)->starget_data)->qas)
|
||||
#define spi_wr_flow(x) (((struct spi_transport_attrs *)&(x)->starget_data)->wr_flow)
|
||||
#define spi_rd_strm(x) (((struct spi_transport_attrs *)&(x)->starget_data)->rd_strm)
|
||||
#define spi_rti(x) (((struct spi_transport_attrs *)&(x)->starget_data)->rti)
|
||||
#define spi_pcomp_en(x) (((struct spi_transport_attrs *)&(x)->starget_data)->pcomp_en)
|
||||
#define spi_hold_mcs(x) (((struct spi_transport_attrs *)&(x)->starget_data)->hold_mcs)
|
||||
#define spi_initial_dv(x) (((struct spi_transport_attrs *)&(x)->starget_data)->initial_dv)
|
||||
#define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending)
|
||||
|
||||
#define spi_support_sync(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_sync)
|
||||
#define spi_support_wide(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_wide)
|
||||
#define spi_support_dt(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_dt)
|
||||
#define spi_support_dt_only(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_dt_only)
|
||||
#define spi_support_ius(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_ius)
|
||||
#define spi_support_qas(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_qas)
|
||||
|
||||
#define spi_flags(x) (((struct spi_transport_attrs *)&(x)->starget_data)->flags)
|
||||
#define spi_signalling(h) (((struct spi_host_attrs *)(h)->shost_data)->signalling)
|
||||
|
||||
|
||||
|
||||
/* The functions by which the transport class and the driver communicate */
|
||||
struct spi_function_template {
|
||||
void (*get_period)(struct scsi_target *);
|
||||
void (*set_period)(struct scsi_target *, int);
|
||||
void (*get_offset)(struct scsi_target *);
|
||||
void (*set_offset)(struct scsi_target *, int);
|
||||
void (*get_width)(struct scsi_target *);
|
||||
void (*set_width)(struct scsi_target *, int);
|
||||
void (*get_iu)(struct scsi_target *);
|
||||
void (*set_iu)(struct scsi_target *, int);
|
||||
void (*get_dt)(struct scsi_target *);
|
||||
void (*set_dt)(struct scsi_target *, int);
|
||||
void (*get_qas)(struct scsi_target *);
|
||||
void (*set_qas)(struct scsi_target *, int);
|
||||
void (*get_wr_flow)(struct scsi_target *);
|
||||
void (*set_wr_flow)(struct scsi_target *, int);
|
||||
void (*get_rd_strm)(struct scsi_target *);
|
||||
void (*set_rd_strm)(struct scsi_target *, int);
|
||||
void (*get_rti)(struct scsi_target *);
|
||||
void (*set_rti)(struct scsi_target *, int);
|
||||
void (*get_pcomp_en)(struct scsi_target *);
|
||||
void (*set_pcomp_en)(struct scsi_target *, int);
|
||||
void (*get_hold_mcs)(struct scsi_target *);
|
||||
void (*set_hold_mcs)(struct scsi_target *, int);
|
||||
void (*get_signalling)(struct Scsi_Host *);
|
||||
void (*set_signalling)(struct Scsi_Host *, enum spi_signal_type);
|
||||
int (*deny_binding)(struct scsi_target *);
|
||||
/* The driver sets these to tell the transport class it
|
||||
* wants the attributes displayed in sysfs. If the show_ flag
|
||||
* is not set, the attribute will be private to the transport
|
||||
* class */
|
||||
unsigned long show_period:1;
|
||||
unsigned long show_offset:1;
|
||||
unsigned long show_width:1;
|
||||
unsigned long show_iu:1;
|
||||
unsigned long show_dt:1;
|
||||
unsigned long show_qas:1;
|
||||
unsigned long show_wr_flow:1;
|
||||
unsigned long show_rd_strm:1;
|
||||
unsigned long show_rti:1;
|
||||
unsigned long show_pcomp_en:1;
|
||||
unsigned long show_hold_mcs:1;
|
||||
};
|
||||
|
||||
struct scsi_transport_template *spi_attach_transport(struct spi_function_template *);
|
||||
void spi_release_transport(struct scsi_transport_template *);
|
||||
void spi_schedule_dv_device(struct scsi_device *);
|
||||
void spi_dv_device(struct scsi_device *);
|
||||
void spi_display_xfer_agreement(struct scsi_target *);
|
||||
int spi_print_msg(const unsigned char *);
|
||||
int spi_populate_width_msg(unsigned char *msg, int width);
|
||||
int spi_populate_sync_msg(unsigned char *msg, int period, int offset);
|
||||
int spi_populate_ppr_msg(unsigned char *msg, int period, int offset, int width,
|
||||
int options);
|
||||
|
||||
#endif /* SCSI_TRANSPORT_SPI_H */
|
||||
19
include/scsi/scsicam.h
Normal file
19
include/scsi/scsicam.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* scsicam.h - SCSI CAM support functions, use for HDIO_GETGEO, etc.
|
||||
*
|
||||
* Copyright 1993, 1994 Drew Eckhardt
|
||||
* Visionary Computing
|
||||
* (Unix and Linux consulting and custom programming)
|
||||
* drew@Colorado.EDU
|
||||
* +1 (303) 786-7975
|
||||
*
|
||||
* For more information, please consult the SCSI-CAM draft.
|
||||
*/
|
||||
|
||||
#ifndef SCSICAM_H
|
||||
#define SCSICAM_H
|
||||
extern int scsicam_bios_param (struct block_device *bdev, sector_t capacity, int *ip);
|
||||
extern int scsi_partsize(unsigned char *buf, unsigned long capacity,
|
||||
unsigned int *cyls, unsigned int *hds, unsigned int *secs);
|
||||
extern unsigned char *scsi_bios_ptable(struct block_device *bdev);
|
||||
#endif /* def SCSICAM_H */
|
||||
307
include/scsi/sg.h
Normal file
307
include/scsi/sg.h
Normal file
@@ -0,0 +1,307 @@
|
||||
#ifndef _SCSI_GENERIC_H
|
||||
#define _SCSI_GENERIC_H
|
||||
|
||||
#include <linux/compiler.h>
|
||||
|
||||
/*
|
||||
History:
|
||||
Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user
|
||||
process control of SCSI devices.
|
||||
Development Sponsored by Killy Corp. NY NY
|
||||
Original driver (sg.h):
|
||||
* Copyright (C) 1992 Lawrence Foard
|
||||
Version 2 and 3 extensions to driver:
|
||||
* Copyright (C) 1998 - 2006 Douglas Gilbert
|
||||
|
||||
Version: 3.5.34 (20060920)
|
||||
This version is for 2.6 series kernels.
|
||||
|
||||
For a full changelog see http://www.torque.net/sg
|
||||
|
||||
Map of SG verions to the Linux kernels in which they appear:
|
||||
---------- ----------------------------------
|
||||
original all kernels < 2.2.6
|
||||
2.1.40 2.2.20
|
||||
3.0.x optional version 3 sg driver for 2.2 series
|
||||
3.1.17++ 2.4.0++
|
||||
3.5.30++ 2.6.0++
|
||||
|
||||
Major new features in SG 3.x driver (cf SG 2.x drivers)
|
||||
- SG_IO ioctl() combines function if write() and read()
|
||||
- new interface (sg_io_hdr_t) but still supports old interface
|
||||
- scatter/gather in user space, direct IO, and mmap supported
|
||||
|
||||
The normal action of this driver is to use the adapter (HBA) driver to DMA
|
||||
data into kernel buffers and then use the CPU to copy the data into the
|
||||
user space (vice versa for writes). That is called "indirect" IO due to
|
||||
the double handling of data. There are two methods offered to remove the
|
||||
redundant copy: 1) direct IO and 2) using the mmap() system call to map
|
||||
the reserve buffer (this driver has one reserve buffer per fd) into the
|
||||
user space. Both have their advantages.
|
||||
In terms of absolute speed mmap() is faster. If speed is not a concern,
|
||||
indirect IO should be fine. Read the documentation for more information.
|
||||
|
||||
** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' or
|
||||
'echo 1 > /sys/module/sg/parameters/allow_dio' is needed.
|
||||
That attribute is 0 by default. **
|
||||
|
||||
Historical note: this SCSI pass-through driver has been known as "sg" for
|
||||
a decade. In broader kernel discussions "sg" is used to refer to scatter
|
||||
gather techniques. The context should clarify which "sg" is referred to.
|
||||
|
||||
Documentation
|
||||
=============
|
||||
A web site for the SG device driver can be found at:
|
||||
http://www.torque.net/sg [alternatively check the MAINTAINERS file]
|
||||
The documentation for the sg version 3 driver can be found at:
|
||||
http://www.torque.net/sg/p/sg_v3_ho.html
|
||||
This is a rendering from DocBook source [change the extension to "sgml"
|
||||
or "xml"]. There are renderings in "ps", "pdf", "rtf" and "txt" (soon).
|
||||
The SG_IO ioctl is now found in other parts kernel (e.g. the block layer).
|
||||
For more information see http://www.torque.net/sg/sg_io.html
|
||||
|
||||
The older, version 2 documents discuss the original sg interface in detail:
|
||||
http://www.torque.net/sg/p/scsi-generic.txt
|
||||
http://www.torque.net/sg/p/scsi-generic_long.txt
|
||||
Also available: <kernel_source>/Documentation/scsi/scsi-generic.txt
|
||||
|
||||
Utility and test programs are available at the sg web site. They are
|
||||
packaged as sg3_utils (for the lk 2.4 and 2.6 series) and sg_utils
|
||||
(for the lk 2.2 series).
|
||||
*/
|
||||
|
||||
|
||||
/* New interface introduced in the 3.x SG drivers follows */
|
||||
|
||||
typedef struct sg_iovec /* same structure as used by readv() Linux system */
|
||||
{ /* call. It defines one scatter-gather element. */
|
||||
void __user *iov_base; /* Starting address */
|
||||
size_t iov_len; /* Length in bytes */
|
||||
} sg_iovec_t;
|
||||
|
||||
|
||||
typedef struct sg_io_hdr
|
||||
{
|
||||
int interface_id; /* [i] 'S' for SCSI generic (required) */
|
||||
int dxfer_direction; /* [i] data transfer direction */
|
||||
unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */
|
||||
unsigned char mx_sb_len; /* [i] max length to write to sbp */
|
||||
unsigned short iovec_count; /* [i] 0 implies no scatter gather */
|
||||
unsigned int dxfer_len; /* [i] byte count of data transfer */
|
||||
void __user *dxferp; /* [i], [*io] points to data transfer memory
|
||||
or scatter gather list */
|
||||
unsigned char __user *cmdp; /* [i], [*i] points to command to perform */
|
||||
void __user *sbp; /* [i], [*o] points to sense_buffer memory */
|
||||
unsigned int timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */
|
||||
unsigned int flags; /* [i] 0 -> default, see SG_FLAG... */
|
||||
int pack_id; /* [i->o] unused internally (normally) */
|
||||
void __user * usr_ptr; /* [i->o] unused internally */
|
||||
unsigned char status; /* [o] scsi status */
|
||||
unsigned char masked_status;/* [o] shifted, masked scsi status */
|
||||
unsigned char msg_status; /* [o] messaging level data (optional) */
|
||||
unsigned char sb_len_wr; /* [o] byte count actually written to sbp */
|
||||
unsigned short host_status; /* [o] errors from host adapter */
|
||||
unsigned short driver_status;/* [o] errors from software driver */
|
||||
int resid; /* [o] dxfer_len - actual_transferred */
|
||||
unsigned int duration; /* [o] time taken by cmd (unit: millisec) */
|
||||
unsigned int info; /* [o] auxiliary information */
|
||||
} sg_io_hdr_t; /* 64 bytes long (on i386) */
|
||||
|
||||
#define SG_INTERFACE_ID_ORIG 'S'
|
||||
|
||||
/* Use negative values to flag difference from original sg_header structure */
|
||||
#define SG_DXFER_NONE (-1) /* e.g. a SCSI Test Unit Ready command */
|
||||
#define SG_DXFER_TO_DEV (-2) /* e.g. a SCSI WRITE command */
|
||||
#define SG_DXFER_FROM_DEV (-3) /* e.g. a SCSI READ command */
|
||||
#define SG_DXFER_TO_FROM_DEV (-4) /* treated like SG_DXFER_FROM_DEV with the
|
||||
additional property than during indirect
|
||||
IO the user buffer is copied into the
|
||||
kernel buffers before the transfer */
|
||||
#define SG_DXFER_UNKNOWN (-5) /* Unknown data direction */
|
||||
|
||||
/* following flag values can be "or"-ed together */
|
||||
#define SG_FLAG_DIRECT_IO 1 /* default is indirect IO */
|
||||
#define SG_FLAG_UNUSED_LUN_INHIBIT 2 /* default is overwrite lun in SCSI */
|
||||
/* command block (when <= SCSI_2) */
|
||||
#define SG_FLAG_MMAP_IO 4 /* request memory mapped IO */
|
||||
#define SG_FLAG_NO_DXFER 0x10000 /* no transfer of kernel buffers to/from */
|
||||
/* user space (debug indirect IO) */
|
||||
|
||||
/* following 'info' values are "or"-ed together */
|
||||
#define SG_INFO_OK_MASK 0x1
|
||||
#define SG_INFO_OK 0x0 /* no sense, host nor driver "noise" */
|
||||
#define SG_INFO_CHECK 0x1 /* something abnormal happened */
|
||||
|
||||
#define SG_INFO_DIRECT_IO_MASK 0x6
|
||||
#define SG_INFO_INDIRECT_IO 0x0 /* data xfer via kernel buffers (or no xfer) */
|
||||
#define SG_INFO_DIRECT_IO 0x2 /* direct IO requested and performed */
|
||||
#define SG_INFO_MIXED_IO 0x4 /* part direct, part indirect IO */
|
||||
|
||||
|
||||
typedef struct sg_scsi_id { /* used by SG_GET_SCSI_ID ioctl() */
|
||||
int host_no; /* as in "scsi<n>" where 'n' is one of 0, 1, 2 etc */
|
||||
int channel;
|
||||
int scsi_id; /* scsi id of target device */
|
||||
int lun;
|
||||
int scsi_type; /* TYPE_... defined in scsi/scsi.h */
|
||||
short h_cmd_per_lun;/* host (adapter) maximum commands per lun */
|
||||
short d_queue_depth;/* device (or adapter) maximum queue length */
|
||||
int unused[2]; /* probably find a good use, set 0 for now */
|
||||
} sg_scsi_id_t; /* 32 bytes long on i386 */
|
||||
|
||||
typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
|
||||
char req_state; /* 0 -> not used, 1 -> written, 2 -> ready to read */
|
||||
char orphan; /* 0 -> normal request, 1 -> from interruped SG_IO */
|
||||
char sg_io_owned; /* 0 -> complete with read(), 1 -> owned by SG_IO */
|
||||
char problem; /* 0 -> no problem detected, 1 -> error to report */
|
||||
int pack_id; /* pack_id associated with request */
|
||||
void __user *usr_ptr; /* user provided pointer (in new interface) */
|
||||
unsigned int duration; /* millisecs elapsed since written (req_state==1)
|
||||
or request duration (req_state==2) */
|
||||
int unused;
|
||||
} sg_req_info_t; /* 20 bytes long on i386 */
|
||||
|
||||
|
||||
/* IOCTLs: Those ioctls that are relevant to the SG 3.x drivers follow.
|
||||
[Those that only apply to the SG 2.x drivers are at the end of the file.]
|
||||
(_GET_s yield result via 'int *' 3rd argument unless otherwise indicated) */
|
||||
|
||||
#define SG_EMULATED_HOST 0x2203 /* true for emulated host adapter (ATAPI) */
|
||||
|
||||
/* Used to configure SCSI command transformation layer for ATAPI devices */
|
||||
/* Only supported by the ide-scsi driver */
|
||||
#define SG_SET_TRANSFORM 0x2204 /* N.B. 3rd arg is not pointer but value: */
|
||||
/* 3rd arg = 0 to disable transform, 1 to enable it */
|
||||
#define SG_GET_TRANSFORM 0x2205
|
||||
|
||||
#define SG_SET_RESERVED_SIZE 0x2275 /* request a new reserved buffer size */
|
||||
#define SG_GET_RESERVED_SIZE 0x2272 /* actual size of reserved buffer */
|
||||
|
||||
/* The following ioctl has a 'sg_scsi_id_t *' object as its 3rd argument. */
|
||||
#define SG_GET_SCSI_ID 0x2276 /* Yields fd's bus, chan, dev, lun + type */
|
||||
/* SCSI id information can also be obtained from SCSI_IOCTL_GET_IDLUN */
|
||||
|
||||
/* Override host setting and always DMA using low memory ( <16MB on i386) */
|
||||
#define SG_SET_FORCE_LOW_DMA 0x2279 /* 0-> use adapter setting, 1-> force */
|
||||
#define SG_GET_LOW_DMA 0x227a /* 0-> use all ram for dma; 1-> low dma ram */
|
||||
|
||||
/* When SG_SET_FORCE_PACK_ID set to 1, pack_id is input to read() which
|
||||
tries to fetch a packet with a matching pack_id, waits, or returns EAGAIN.
|
||||
If pack_id is -1 then read oldest waiting. When ...FORCE_PACK_ID set to 0
|
||||
then pack_id ignored by read() and oldest readable fetched. */
|
||||
#define SG_SET_FORCE_PACK_ID 0x227b
|
||||
#define SG_GET_PACK_ID 0x227c /* Yields oldest readable pack_id (or -1) */
|
||||
|
||||
#define SG_GET_NUM_WAITING 0x227d /* Number of commands awaiting read() */
|
||||
|
||||
/* Yields max scatter gather tablesize allowed by current host adapter */
|
||||
#define SG_GET_SG_TABLESIZE 0x227F /* 0 implies can't do scatter gather */
|
||||
|
||||
#define SG_GET_VERSION_NUM 0x2282 /* Example: version 2.1.34 yields 20134 */
|
||||
|
||||
/* Returns -EBUSY if occupied. 3rd argument pointer to int (see next) */
|
||||
#define SG_SCSI_RESET 0x2284
|
||||
/* Associated values that can be given to SG_SCSI_RESET follow */
|
||||
#define SG_SCSI_RESET_NOTHING 0
|
||||
#define SG_SCSI_RESET_DEVICE 1
|
||||
#define SG_SCSI_RESET_BUS 2
|
||||
#define SG_SCSI_RESET_HOST 3
|
||||
|
||||
/* synchronous SCSI command ioctl, (only in version 3 interface) */
|
||||
#define SG_IO 0x2285 /* similar effect as write() followed by read() */
|
||||
|
||||
#define SG_GET_REQUEST_TABLE 0x2286 /* yields table of active requests */
|
||||
|
||||
/* How to treat EINTR during SG_IO ioctl(), only in SG 3.x series */
|
||||
#define SG_SET_KEEP_ORPHAN 0x2287 /* 1 -> hold for read(), 0 -> drop (def) */
|
||||
#define SG_GET_KEEP_ORPHAN 0x2288
|
||||
|
||||
/* yields scsi midlevel's access_count for this SCSI device */
|
||||
#define SG_GET_ACCESS_COUNT 0x2289
|
||||
|
||||
|
||||
#define SG_SCATTER_SZ (8 * 4096)
|
||||
/* Largest size (in bytes) a single scatter-gather list element can have.
|
||||
The value used by the driver is 'max(SG_SCATTER_SZ, PAGE_SIZE)'.
|
||||
This value should be a power of 2 (and may be rounded up internally).
|
||||
If scatter-gather is not supported by adapter then this value is the
|
||||
largest data block that can be read/written by a single scsi command. */
|
||||
|
||||
#define SG_DEFAULT_RETRIES 0
|
||||
|
||||
/* Defaults, commented if they differ from original sg driver */
|
||||
#define SG_DEF_FORCE_LOW_DMA 0 /* was 1 -> memory below 16MB on i386 */
|
||||
#define SG_DEF_FORCE_PACK_ID 0
|
||||
#define SG_DEF_KEEP_ORPHAN 0
|
||||
#define SG_DEF_RESERVED_SIZE SG_SCATTER_SZ /* load time option */
|
||||
|
||||
/* maximum outstanding requests, write() yields EDOM if exceeded */
|
||||
#define SG_MAX_QUEUE 16
|
||||
|
||||
#define SG_BIG_BUFF SG_DEF_RESERVED_SIZE /* for backward compatibility */
|
||||
|
||||
/* Alternate style type names, "..._t" variants preferred */
|
||||
typedef struct sg_io_hdr Sg_io_hdr;
|
||||
typedef struct sg_io_vec Sg_io_vec;
|
||||
typedef struct sg_scsi_id Sg_scsi_id;
|
||||
typedef struct sg_req_info Sg_req_info;
|
||||
|
||||
|
||||
/* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
|
||||
/* The older SG interface based on the 'sg_header' structure follows. */
|
||||
/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
|
||||
|
||||
#define SG_MAX_SENSE 16 /* this only applies to the sg_header interface */
|
||||
|
||||
struct sg_header
|
||||
{
|
||||
int pack_len; /* [o] reply_len (ie useless), ignored as input */
|
||||
int reply_len; /* [i] max length of expected reply (inc. sg_header) */
|
||||
int pack_id; /* [io] id number of packet (use ints >= 0) */
|
||||
int result; /* [o] 0==ok, else (+ve) Unix errno (best ignored) */
|
||||
unsigned int twelve_byte:1;
|
||||
/* [i] Force 12 byte command length for group 6 & 7 commands */
|
||||
unsigned int target_status:5; /* [o] scsi status from target */
|
||||
unsigned int host_status:8; /* [o] host status (see "DID" codes) */
|
||||
unsigned int driver_status:8; /* [o] driver status+suggestion */
|
||||
unsigned int other_flags:10; /* unused */
|
||||
unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] Output in 3 cases:
|
||||
when target_status is CHECK_CONDITION or
|
||||
when target_status is COMMAND_TERMINATED or
|
||||
when (driver_status & DRIVER_SENSE) is true. */
|
||||
}; /* This structure is 36 bytes long on i386 */
|
||||
|
||||
|
||||
/* IOCTLs: The following are not required (or ignored) when the sg_io_hdr_t
|
||||
interface is used. They are kept for backward compatibility with
|
||||
the original and version 2 drivers. */
|
||||
|
||||
#define SG_SET_TIMEOUT 0x2201 /* unit: jiffies (10ms on i386) */
|
||||
#define SG_GET_TIMEOUT 0x2202 /* yield timeout as _return_ value */
|
||||
|
||||
/* Get/set command queuing state per fd (default is SG_DEF_COMMAND_Q.
|
||||
Each time a sg_io_hdr_t object is seen on this file descriptor, this
|
||||
command queuing flag is set on (overriding the previous setting). */
|
||||
#define SG_GET_COMMAND_Q 0x2270 /* Yields 0 (queuing off) or 1 (on) */
|
||||
#define SG_SET_COMMAND_Q 0x2271 /* Change queuing state with 0 or 1 */
|
||||
|
||||
/* Turn on/off error sense trace (1 and 0 respectively, default is off).
|
||||
Try using: "# cat /proc/scsi/sg/debug" instead in the v3 driver */
|
||||
#define SG_SET_DEBUG 0x227e /* 0 -> turn off debug */
|
||||
|
||||
#define SG_NEXT_CMD_LEN 0x2283 /* override SCSI command length with given
|
||||
number on the next write() on this file descriptor */
|
||||
|
||||
|
||||
/* Defaults, commented if they differ from original sg driver */
|
||||
#ifdef __KERNEL__
|
||||
#define SG_DEFAULT_TIMEOUT_USER (60*USER_HZ) /* HZ == 'jiffies in 1 second' */
|
||||
#else
|
||||
#define SG_DEFAULT_TIMEOUT (60*HZ) /* HZ == 'jiffies in 1 second' */
|
||||
#endif
|
||||
|
||||
#define SG_DEF_COMMAND_Q 0 /* command queuing is always on when
|
||||
the new interface is used */
|
||||
#define SG_DEF_UNDERRUN_FLAG 0
|
||||
|
||||
#endif
|
||||
242
include/scsi/srp.h
Normal file
242
include/scsi/srp.h
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Copyright (c) 2005 Cisco Systems. All rights reserved.
|
||||
*
|
||||
* This software is available to you under a choice of one of two
|
||||
* licenses. You may choose to be licensed under the terms of the GNU
|
||||
* General Public License (GPL) Version 2, available from the file
|
||||
* COPYING in the main directory of this source tree, or the
|
||||
* OpenIB.org BSD license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* $Id: srp.h,v 1.1.1.1 2007/06/12 07:27:16 eyryu Exp $
|
||||
*/
|
||||
|
||||
#ifndef SCSI_SRP_H
|
||||
#define SCSI_SRP_H
|
||||
|
||||
/*
|
||||
* Structures and constants for the SCSI RDMA Protocol (SRP) as
|
||||
* defined by the INCITS T10 committee. This file was written using
|
||||
* draft Revision 16a of the SRP standard.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
enum {
|
||||
SRP_LOGIN_REQ = 0x00,
|
||||
SRP_TSK_MGMT = 0x01,
|
||||
SRP_CMD = 0x02,
|
||||
SRP_I_LOGOUT = 0x03,
|
||||
SRP_LOGIN_RSP = 0xc0,
|
||||
SRP_RSP = 0xc1,
|
||||
SRP_LOGIN_REJ = 0xc2,
|
||||
SRP_T_LOGOUT = 0x80,
|
||||
SRP_CRED_REQ = 0x81,
|
||||
SRP_AER_REQ = 0x82,
|
||||
SRP_CRED_RSP = 0x41,
|
||||
SRP_AER_RSP = 0x42
|
||||
};
|
||||
|
||||
enum {
|
||||
SRP_BUF_FORMAT_DIRECT = 1 << 1,
|
||||
SRP_BUF_FORMAT_INDIRECT = 1 << 2
|
||||
};
|
||||
|
||||
enum {
|
||||
SRP_NO_DATA_DESC = 0,
|
||||
SRP_DATA_DESC_DIRECT = 1,
|
||||
SRP_DATA_DESC_INDIRECT = 2
|
||||
};
|
||||
|
||||
enum {
|
||||
SRP_TSK_ABORT_TASK = 0x01,
|
||||
SRP_TSK_ABORT_TASK_SET = 0x02,
|
||||
SRP_TSK_CLEAR_TASK_SET = 0x04,
|
||||
SRP_TSK_LUN_RESET = 0x08,
|
||||
SRP_TSK_CLEAR_ACA = 0x40
|
||||
};
|
||||
|
||||
enum srp_login_rej_reason {
|
||||
SRP_LOGIN_REJ_UNABLE_ESTABLISH_CHANNEL = 0x00010000,
|
||||
SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES = 0x00010001,
|
||||
SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE = 0x00010002,
|
||||
SRP_LOGIN_REJ_UNABLE_ASSOCIATE_CHANNEL = 0x00010003,
|
||||
SRP_LOGIN_REJ_UNSUPPORTED_DESCRIPTOR_FMT = 0x00010004,
|
||||
SRP_LOGIN_REJ_MULTI_CHANNEL_UNSUPPORTED = 0x00010005,
|
||||
SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED = 0x00010006
|
||||
};
|
||||
|
||||
enum {
|
||||
SRP_REV10_IB_IO_CLASS = 0xff00,
|
||||
SRP_REV16A_IB_IO_CLASS = 0x0100
|
||||
};
|
||||
|
||||
struct srp_direct_buf {
|
||||
__be64 va;
|
||||
__be32 key;
|
||||
__be32 len;
|
||||
};
|
||||
|
||||
/*
|
||||
* We need the packed attribute because the SRP spec puts the list of
|
||||
* descriptors at an offset of 20, which is not aligned to the size of
|
||||
* struct srp_direct_buf. The whole structure must be packed to avoid
|
||||
* having the 20-byte structure padded to 24 bytes on 64-bit architectures.
|
||||
*/
|
||||
struct srp_indirect_buf {
|
||||
struct srp_direct_buf table_desc;
|
||||
__be32 len;
|
||||
struct srp_direct_buf desc_list[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
enum {
|
||||
SRP_MULTICHAN_SINGLE = 0,
|
||||
SRP_MULTICHAN_MULTI = 1
|
||||
};
|
||||
|
||||
struct srp_login_req {
|
||||
u8 opcode;
|
||||
u8 reserved1[7];
|
||||
u64 tag;
|
||||
__be32 req_it_iu_len;
|
||||
u8 reserved2[4];
|
||||
__be16 req_buf_fmt;
|
||||
u8 req_flags;
|
||||
u8 reserved3[5];
|
||||
u8 initiator_port_id[16];
|
||||
u8 target_port_id[16];
|
||||
};
|
||||
|
||||
/*
|
||||
* The SRP spec defines the size of the LOGIN_RSP structure to be 52
|
||||
* bytes, so it needs to be packed to avoid having it padded to 56
|
||||
* bytes on 64-bit architectures.
|
||||
*/
|
||||
struct srp_login_rsp {
|
||||
u8 opcode;
|
||||
u8 reserved1[3];
|
||||
__be32 req_lim_delta;
|
||||
u64 tag;
|
||||
__be32 max_it_iu_len;
|
||||
__be32 max_ti_iu_len;
|
||||
__be16 buf_fmt;
|
||||
u8 rsp_flags;
|
||||
u8 reserved2[25];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct srp_login_rej {
|
||||
u8 opcode;
|
||||
u8 reserved1[3];
|
||||
__be32 reason;
|
||||
u64 tag;
|
||||
u8 reserved2[8];
|
||||
__be16 buf_fmt;
|
||||
u8 reserved3[6];
|
||||
};
|
||||
|
||||
struct srp_i_logout {
|
||||
u8 opcode;
|
||||
u8 reserved[7];
|
||||
u64 tag;
|
||||
};
|
||||
|
||||
struct srp_t_logout {
|
||||
u8 opcode;
|
||||
u8 sol_not;
|
||||
u8 reserved[2];
|
||||
__be32 reason;
|
||||
u64 tag;
|
||||
};
|
||||
|
||||
/*
|
||||
* We need the packed attribute because the SRP spec only aligns the
|
||||
* 8-byte LUN field to 4 bytes.
|
||||
*/
|
||||
struct srp_tsk_mgmt {
|
||||
u8 opcode;
|
||||
u8 sol_not;
|
||||
u8 reserved1[6];
|
||||
u64 tag;
|
||||
u8 reserved2[4];
|
||||
__be64 lun __attribute__((packed));
|
||||
u8 reserved3[2];
|
||||
u8 tsk_mgmt_func;
|
||||
u8 reserved4;
|
||||
u64 task_tag;
|
||||
u8 reserved5[8];
|
||||
};
|
||||
|
||||
/*
|
||||
* We need the packed attribute because the SRP spec only aligns the
|
||||
* 8-byte LUN field to 4 bytes.
|
||||
*/
|
||||
struct srp_cmd {
|
||||
u8 opcode;
|
||||
u8 sol_not;
|
||||
u8 reserved1[3];
|
||||
u8 buf_fmt;
|
||||
u8 data_out_desc_cnt;
|
||||
u8 data_in_desc_cnt;
|
||||
u64 tag;
|
||||
u8 reserved2[4];
|
||||
__be64 lun __attribute__((packed));
|
||||
u8 reserved3;
|
||||
u8 task_attr;
|
||||
u8 reserved4;
|
||||
u8 add_cdb_len;
|
||||
u8 cdb[16];
|
||||
u8 add_data[0];
|
||||
};
|
||||
|
||||
enum {
|
||||
SRP_RSP_FLAG_RSPVALID = 1 << 0,
|
||||
SRP_RSP_FLAG_SNSVALID = 1 << 1,
|
||||
SRP_RSP_FLAG_DOOVER = 1 << 2,
|
||||
SRP_RSP_FLAG_DOUNDER = 1 << 3,
|
||||
SRP_RSP_FLAG_DIOVER = 1 << 4,
|
||||
SRP_RSP_FLAG_DIUNDER = 1 << 5
|
||||
};
|
||||
|
||||
/*
|
||||
* The SRP spec defines the size of the RSP structure to be 36 bytes,
|
||||
* so it needs to be packed to avoid having it padded to 40 bytes on
|
||||
* 64-bit architectures.
|
||||
*/
|
||||
struct srp_rsp {
|
||||
u8 opcode;
|
||||
u8 sol_not;
|
||||
u8 reserved1[2];
|
||||
__be32 req_lim_delta;
|
||||
u64 tag;
|
||||
u8 reserved2[2];
|
||||
u8 flags;
|
||||
u8 status;
|
||||
__be32 data_out_res_cnt;
|
||||
__be32 data_in_res_cnt;
|
||||
__be32 sense_data_len;
|
||||
__be32 resp_data_len;
|
||||
u8 data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif /* SCSI_SRP_H */
|
||||
Reference in New Issue
Block a user