Start to move the in-kernel iSCSI initiator, kindly contributed to the
NetBSD Foundation by Wasabi Systems, from othersrc/external/bsd/iscsi/sys/dev/iscsi to src/sys/dev/iscsi
This commit is contained in:
parent
75a17f3ce7
commit
e01460c073
|
@ -0,0 +1,7 @@
|
|||
# $wasabi: Makefile,v 1.2 2006/04/19 02:06:26 wrstuden Exp $
|
||||
|
||||
INCSDIR= /usr/include/dev/iscsi
|
||||
|
||||
INCS= iscsi.h iscsi_ioctl.h iscsi_test.h iscsi_perf.h
|
||||
|
||||
.include <bsd.kinc.mk>
|
|
@ -0,0 +1,182 @@
|
|||
/* $NetBSD: base64.c,v 1.1 2011/10/23 21:15:02 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Wasabi Systems, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* Adapted for kernel mode use with minimal changes from
|
||||
* /usr/src/crypto/dist/heimdal/lib/roken/base64.c
|
||||
*
|
||||
* Original:
|
||||
* Copyright (c) 1995-2001 Kungliga Tekniska Högskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. 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.
|
||||
*
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "iscsi_globals.h"
|
||||
#include "base64.h"
|
||||
|
||||
static char base64_chars[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
static int
|
||||
pos(char c)
|
||||
{
|
||||
char *p;
|
||||
|
||||
for (p = base64_chars; *p; p++) {
|
||||
if (*p == c) {
|
||||
return (int)(p - base64_chars);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
base64_encode(const void *data, int size, uint8_t * buffer)
|
||||
{
|
||||
uint8_t *p;
|
||||
int i;
|
||||
int c;
|
||||
const uint8_t *q;
|
||||
|
||||
p = buffer;
|
||||
q = (const uint8_t *) data;
|
||||
*p++ = '0';
|
||||
*p++ = 'b';
|
||||
|
||||
i = 0;
|
||||
for (i = 0; i < size;) {
|
||||
c = q[i++];
|
||||
c *= 256;
|
||||
if (i < size) {
|
||||
c += q[i];
|
||||
}
|
||||
i++;
|
||||
c *= 256;
|
||||
if (i < size) {
|
||||
c += q[i];
|
||||
}
|
||||
i++;
|
||||
p[0] = base64_chars[(c & 0x00fc0000) >> 18];
|
||||
p[1] = base64_chars[(c & 0x0003f000) >> 12];
|
||||
p[2] = base64_chars[(c & 0x00000fc0) >> 6];
|
||||
p[3] = base64_chars[(c & 0x0000003f) >> 0];
|
||||
if (i > size) {
|
||||
p[3] = '=';
|
||||
}
|
||||
if (i > size + 1) {
|
||||
p[2] = '=';
|
||||
}
|
||||
p += 4;
|
||||
}
|
||||
*p = 0;
|
||||
return strlen(buffer);
|
||||
}
|
||||
|
||||
#define DECODE_ERROR 0xffffffff
|
||||
|
||||
static uint32_t
|
||||
token_decode(uint8_t * token)
|
||||
{
|
||||
int i;
|
||||
uint32_t val = 0;
|
||||
int marker = 0;
|
||||
|
||||
if (strlen(token) < 4) {
|
||||
return DECODE_ERROR;
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
val *= 64;
|
||||
if (token[i] == '=') {
|
||||
marker++;
|
||||
} else if (marker > 0) {
|
||||
return DECODE_ERROR;
|
||||
} else {
|
||||
val += pos(token[i]);
|
||||
}
|
||||
}
|
||||
if (marker > 2) {
|
||||
return DECODE_ERROR;
|
||||
}
|
||||
return (marker << 24) | val;
|
||||
}
|
||||
|
||||
|
||||
uint8_t *
|
||||
base64_decode(uint8_t * str, void *data, int *datalen)
|
||||
{
|
||||
uint8_t *p, *q;
|
||||
uint32_t marker = 0;
|
||||
|
||||
q = data;
|
||||
for (p = str; *p; p += 4) {
|
||||
uint32_t val = token_decode(p);
|
||||
marker = (val >> 24) & 0xff;
|
||||
if (val == DECODE_ERROR) {
|
||||
return NULL;
|
||||
}
|
||||
*q++ = (val >> 16) & 0xff;
|
||||
if (marker < 2) {
|
||||
*q++ = (val >> 8) & 0xff;
|
||||
}
|
||||
if (marker < 1) {
|
||||
*q++ = val & 0xff;
|
||||
}
|
||||
}
|
||||
*datalen = (int)(q - (uint8_t *) data);
|
||||
|
||||
return p - marker + 1;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/* $NetBSD: base64.h,v 1.1 2011/10/23 21:15:02 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Wasabi Systems, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* size of result string including term. zero and "0b" prefix */
|
||||
#define base64_enclen(size) ((size) * 4 / 3 + 4 + 2)
|
||||
|
||||
/* encode "size" bytes of "data" into "buffer" returning length */
|
||||
int base64_encode(const void *, int, uint8_t *);
|
||||
/* decode "str" into "data" returning end of source string */
|
||||
uint8_t *base64_decode(uint8_t *, void *, int *);
|
|
@ -0,0 +1,19 @@
|
|||
# $NetBSD: files.iscsi,v 1.1 2011/10/23 21:15:02 agc Exp $
|
||||
#
|
||||
# Configuration file for iSCSI initiator
|
||||
|
||||
defpseudodev iscsi : scsi
|
||||
|
||||
defflag ISCSI_DEBUG
|
||||
defflag ISCSI_PERFTEST
|
||||
defflag ISCSI_TEST_MODE
|
||||
|
||||
file dev/iscsi/base64.c iscsi
|
||||
file dev/iscsi/iscsi_ioctl.c iscsi
|
||||
file dev/iscsi/iscsi_main.c iscsi
|
||||
file dev/iscsi/iscsi_profile.c iscsi
|
||||
file dev/iscsi/iscsi_rcv.c iscsi
|
||||
file dev/iscsi/iscsi_send.c iscsi
|
||||
file dev/iscsi/iscsi_test.c iscsi
|
||||
file dev/iscsi/iscsi_text.c iscsi
|
||||
file dev/iscsi/iscsi_utils.c
|
|
@ -0,0 +1,217 @@
|
|||
/* $NetBSD: iscsi.h,v 1.1 2011/10/23 21:15:02 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2004,2006,2011 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Wasabi Systems, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _ISCSI_H
|
||||
#define _ISCSI_H
|
||||
|
||||
#define ISCSI_DEV_MAJOR 202
|
||||
|
||||
#define ISCSI_STRING_LENGTH (223+1)
|
||||
#define ISCSI_ADDRESS_LENGTH (255+1)
|
||||
#define ISCSI_AUTH_OPTIONS 4
|
||||
|
||||
typedef enum {
|
||||
ISCSI_AUTH_None = 0,
|
||||
ISCSI_AUTH_CHAP = 1,
|
||||
ISCSI_AUTH_KRB5 = 2,
|
||||
ISCSI_AUTH_SRP = 3
|
||||
} iscsi_auth_types_t;
|
||||
/*
|
||||
ISCSI_AUTH_None
|
||||
Indicates that no authentication is necessary.
|
||||
ISCSI_AUTH_CHAP
|
||||
Indicates CHAP authentication should be used.
|
||||
ISCSI_AUTH_KRB5
|
||||
Indicates Kerberos 5 authentication (fur future use).
|
||||
ISCSI_AUTH_SRP
|
||||
Indicates SRP authentication (for future use).
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
int mutual_auth:1;
|
||||
int is_secure:1;
|
||||
int auth_number:4;
|
||||
iscsi_auth_types_t auth_type[ISCSI_AUTH_OPTIONS];
|
||||
} iscsi_auth_info_t;
|
||||
|
||||
/*
|
||||
mutual_auth
|
||||
Indicates that authentication should be mutual, i.e.
|
||||
the initiator should authenticate the target, and the target
|
||||
should authenticate the initiator. If not specified, the target
|
||||
will authenticate the initiator only.
|
||||
is_secure
|
||||
Indicates that the connection is secure.
|
||||
auth_number
|
||||
Indicates the number of elements in auth_type.
|
||||
When 0, no authentication will be used.
|
||||
auth_type
|
||||
Contains up to ISCSI_AUTH_OPTIONS enumerator values of type
|
||||
ISCSI_AUTH_TYPES that indicates the authentication method that
|
||||
should be used to establish a login connection (none, CHAP, KRB5,
|
||||
etc.), in order of priority. The first element is the most
|
||||
preferred method, the last element the least preferred.
|
||||
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
ISCSI_DIGEST_None = 0,
|
||||
ISCSI_DIGEST_CRC32C = 1
|
||||
} iscsi_digest_t;
|
||||
|
||||
/*
|
||||
ISCSI_DIGEST_None
|
||||
Indicates that no CRC is to be generated.
|
||||
ISCSI_DIGEST_CRC32C
|
||||
Indicates the CRC32C digest should be used.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
ISCSI_LOGINTYPE_DISCOVERY = 0,
|
||||
ISCSI_LOGINTYPE_NOMAP = 1,
|
||||
ISCSI_LOGINTYPE_MAP = 2
|
||||
} iscsi_login_session_type_t;
|
||||
|
||||
/*
|
||||
ISCSI_LOGINTYPE_DISCOVERY
|
||||
Indicates that the login session is for discovery only.
|
||||
Initiators use this type of session to send a SCSI SendTargets
|
||||
command to an iSCSI target to request assistance in
|
||||
discovering other targets accessible to the target that
|
||||
receives the SendTargets command.
|
||||
ISCSI_LOGINTYPE_NOMAP
|
||||
This establishes a normal (full featured) session, but does
|
||||
not report the target LUNs to the operating system as
|
||||
available drives. Communication with the target is limited
|
||||
to io-controls through the driver.
|
||||
ISCSI_LOGINTYPE_MAP
|
||||
Indicates that the login session is full featured, and reports
|
||||
all target LUNs to the operating system to map as logical drives.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint8_t address[ISCSI_ADDRESS_LENGTH];
|
||||
uint16_t port;
|
||||
uint16_t group_tag;
|
||||
} iscsi_portal_address_t;
|
||||
|
||||
/*
|
||||
address
|
||||
IP address of the target (V4 dotted quad or V6 hex).
|
||||
port
|
||||
IP port number.
|
||||
group_tag
|
||||
Target portal group tag (0 if unknown).
|
||||
*/
|
||||
|
||||
|
||||
/* ------------------------- Status Values -------------------------- */
|
||||
|
||||
#define ISCSI_STATUS_SUCCESS 0 /* Indicates success. */
|
||||
#define ISCSI_STATUS_LIST_EMPTY 1 /* The requested list is empty. */
|
||||
#define ISCSI_STATUS_DUPLICATE_NAME 2 /* The specified symbolic identifier is not unique. */
|
||||
#define ISCSI_STATUS_GENERAL_ERROR 3 /* A non-specific error occurred. */
|
||||
#define ISCSI_STATUS_LOGIN_FAILED 4 /* The login failed. */
|
||||
#define ISCSI_STATUS_CONNECTION_FAILED 5 /* The attempt to establish a connection failed. */
|
||||
#define ISCSI_STATUS_AUTHENTICATION_FAILED 6 /* Authentication negotiation failed. */
|
||||
#define ISCSI_STATUS_NO_RESOURCES 7 /* Could not allocate resources (e.g. memory). */
|
||||
#define ISCSI_STATUS_MAXED_CONNECTIONS 8 /* Maximum number of connections exceeded. */
|
||||
#define ISCSI_STATUS_INVALID_SESSION_ID 9 /* Session ID not found */
|
||||
#define ISCSI_STATUS_INVALID_CONNECTION_ID 10 /* Connection ID not found */
|
||||
#define ISCSI_STATUS_INVALID_SOCKET 11 /* Specified socket is invalid */
|
||||
#define ISCSI_STATUS_NOTIMPL 12 /* Feature not implemented */
|
||||
#define ISCSI_STATUS_CHECK_CONDITION 13 /* Target reported CHECK CONDITION */
|
||||
#define ISCSI_STATUS_TARGET_BUSY 14 /* Target reported BUSY */
|
||||
#define ISCSI_STATUS_TARGET_ERROR 15 /* Target reported other error */
|
||||
#define ISCSI_STATUS_TARGET_FAILURE 16 /* Command Response was Target Failure */
|
||||
#define ISCSI_STATUS_TARGET_DROP 17 /* Target dropped connection */
|
||||
#define ISCSI_STATUS_SOCKET_ERROR 18 /* Communication failure */
|
||||
#define ISCSI_STATUS_PARAMETER_MISSING 19 /* A required ioctl parameter is missing */
|
||||
#define ISCSI_STATUS_PARAMETER_INVALID 20 /* A parameter is malformed (string too long etc.) */
|
||||
#define ISCSI_STATUS_MAP_FAILED 21 /* Mapping the LUNs failed */
|
||||
#define ISCSI_STATUS_NO_INITIATOR_NAME 22 /* Initiator name was not set */
|
||||
#define ISCSI_STATUS_NEGOTIATION_ERROR 23 /* Negotiation failure (invalid key or value) */
|
||||
#define ISCSI_STATUS_TIMEOUT 24 /* Command timed out (at iSCSI level) */
|
||||
#define ISCSI_STATUS_PROTOCOL_ERROR 25 /* Internal Error (Protocol error reject) */
|
||||
#define ISCSI_STATUS_PDU_ERROR 26 /* Internal Error (Invalid PDU field reject) */
|
||||
#define ISCSI_STATUS_CMD_NOT_SUPPORTED 27 /* Target does not support iSCSI command */
|
||||
#define ISCSI_STATUS_DRIVER_UNLOAD 28 /* Driver is unloading */
|
||||
#define ISCSI_STATUS_LOGOUT 29 /* Session was logged out */
|
||||
#define ISCSI_STATUS_PDUS_LOST 30 /* Excessive PDU loss */
|
||||
#define ISCSI_STATUS_INVALID_EVENT_ID 31 /* Invalid Event ID */
|
||||
#define ISCSI_STATUS_EVENT_DEREGISTERED 32 /* Wait for event cancelled by deregistration */
|
||||
#define ISCSI_STATUS_EVENT_WAITING 33 /* Someone is already waiting for this event */
|
||||
#define ISCSI_STATUS_TASK_NOT_FOUND 34 /* Task Management: task not found */
|
||||
#define ISCSI_STATUS_LUN_NOT_FOUND 35 /* Task Management: LUN not found */
|
||||
#define ISCSI_STATUS_TASK_ALLEGIANT 36 /* Task Management: Task still allegiant */
|
||||
#define ISCSI_STATUS_CANT_REASSIGN 37 /* Task Management: Task reassignment not supported */
|
||||
#define ISCSI_STATUS_FUNCTION_UNSUPPORTED 38 /* Task Management: Function unsupported */
|
||||
#define ISCSI_STATUS_FUNCTION_NOT_AUTHORIZED 39 /* Task Management: Function not authorized */
|
||||
#define ISCSI_STATUS_FUNCTION_REJECTED 40 /* Task Management: Function rejected */
|
||||
#define ISCSI_STATUS_UNKNOWN_REASON 41 /* Task Management: Unknown reason code */
|
||||
#define ISCSI_STATUS_DUPLICATE_ID 42 /* Given ID is a duplicate */
|
||||
#define ISCSI_STATUS_INVALID_ID 43 /* Given ID was not found */
|
||||
#define ISCSI_STATUS_TARGET_LOGOUT 44 /* Target requested logout */
|
||||
#define ISCSI_STATUS_LOGOUT_CID_NOT_FOUND 45 /* Logout error: CID not found */
|
||||
#define ISCSI_STATUS_LOGOUT_RECOVERY_NS 46 /* Logout error: Recovery not supported */
|
||||
#define ISCSI_STATUS_LOGOUT_ERROR 47 /* Logout error: Unknown reason */
|
||||
|
||||
#define ISCSID_STATUS_SUCCESS 0 /* Indicates success. */
|
||||
#define ISCSID_STATUS_LIST_EMPTY 1001 /* The requested list is empty. */
|
||||
#define ISCSID_STATUS_DUPLICATE_NAME 1002 /* The specified name is not unique. */
|
||||
#define ISCSID_STATUS_GENERAL_ERROR 1003 /* A non-specific error occurred. */
|
||||
#define ISCSID_STATUS_CONNECT_ERROR 1005 /* Failed to connect to target */
|
||||
#define ISCSID_STATUS_NO_RESOURCES 1007 /* Could not allocate resources (e.g. memory). */
|
||||
#define ISCSID_STATUS_INVALID_SESSION_ID 1009 /* Session ID not found */
|
||||
#define ISCSID_STATUS_INVALID_CONNECTION_ID 1010 /* Connection ID not found */
|
||||
#define ISCSID_STATUS_NOTIMPL 1012 /* Feature not implemented */
|
||||
#define ISCSID_STATUS_SOCKET_ERROR 1018 /* Failed to create socket */
|
||||
#define ISCSID_STATUS_PARAMETER_MISSING 1019 /* A required parameter is missing */
|
||||
#define ISCSID_STATUS_PARAMETER_INVALID 1020 /* A parameter is malformed (string too long etc.) */
|
||||
#define ISCSID_STATUS_INVALID_PARAMETER 1020 /* Alternate spelling of above */
|
||||
#define ISCSID_STATUS_NO_INITIATOR_NAME 1022 /* Initiator name was not set */
|
||||
#define ISCSID_STATUS_TIMEOUT 1024 /* Request timed out */
|
||||
#define ISCSID_STATUS_DRIVER_NOT_LOADED 1028 /* Driver not loaded */
|
||||
#define ISCSID_STATUS_INVALID_REQUEST 1101 /* Unknown request code */
|
||||
#define ISCSID_STATUS_INVALID_PORTAL_ID 1102 /* Portal ID not found */
|
||||
#define ISCSID_STATUS_INVALID_TARGET_ID 1103 /* Target ID not found */
|
||||
#define ISCSID_STATUS_NOT_FOUND 1104 /* Search failed */
|
||||
#define ISCSID_STATUS_HOST_NOT_FOUND 1105 /* Target address not found */
|
||||
#define ISCSID_STATUS_HOST_TRY_AGAIN 1106 /* Target address retreival failed, try again later */
|
||||
#define ISCSID_STATUS_HOST_ERROR 1107 /* Target address invalid */
|
||||
#define ISCSID_STATUS_NO_TARGETS_FOUND 1108 /* No targets found during refresh */
|
||||
#define ISCSID_STATUS_INVALID_ISNS_ID 1111 /* iSNS ID not found */
|
||||
#define ISCSID_STATUS_ISNS_ERROR 1112 /* Problem connecting to iSNS */
|
||||
#define ISCSID_STATUS_ISNS_SERVER_ERROR 1113 /* iSNS server returned garbage */
|
||||
#define ISCSID_STATUS_DUPLICATE_ENTRY 1114 /* The specified entry already exists */
|
||||
#define ISCSID_STATUS_INVALID_INITIATOR_ID 1115 /* Initiator ID not found */
|
||||
#define ISCSID_STATUS_INITIATOR_BIND_ERROR 1116 /* Bind to initiator portal failed */
|
||||
|
||||
#endif /* !_ISCSI_H */
|
|
@ -0,0 +1,843 @@
|
|||
/* $NetBSD: iscsi_globals.h,v 1.1 2011/10/23 21:15:02 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Wasabi Systems, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _ISCSI_GLOBALS_H
|
||||
#define _ISCSI_GLOBALS_H
|
||||
|
||||
/*#include "opt_ddb.h" */
|
||||
#define DDB 1
|
||||
|
||||
/* Includes we need in all files */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/scsiio.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/kthread.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/rnd.h>
|
||||
#include <sys/device.h>
|
||||
|
||||
#include <dev/scsipi/scsi_all.h>
|
||||
#include <dev/scsipi/scsipi_all.h>
|
||||
#include <dev/scsipi/scsiconf.h>
|
||||
#include <dev/scsipi/scsipiconf.h>
|
||||
|
||||
#include "iscsi.h"
|
||||
#include "iscsi_pdu.h"
|
||||
#include "iscsi_ioctl.h"
|
||||
|
||||
/* ------------------------ Code selection constants ------------------------ */
|
||||
|
||||
/* #define ISCSI_DEBUG 1 */
|
||||
|
||||
#include "iscsi_perf.h"
|
||||
#include "iscsi_test.h"
|
||||
|
||||
/* ------------------------- Global Constants ----------------------------- */
|
||||
|
||||
/* Version information */
|
||||
|
||||
#define INTERFACE_VERSION 2
|
||||
#define VERSION_MAJOR 3
|
||||
#define VERSION_MINOR 1
|
||||
#define VERSION_STRING "NetBSD iSCSI Software Initiator 20110407"
|
||||
|
||||
/*
|
||||
Various checks are made that the expected cmd Serial Number is less than
|
||||
the actual command serial number. The extremely paranoid amongst us
|
||||
believe that a malicious iSCSI server could set this artificially low
|
||||
and effectively DoS a naive initiator. For this (possibly ludicrous)
|
||||
reason, I have added the two definitions below (agc, 2011/04/09). The
|
||||
throttling definition enables a check that the CmdSN is less than the
|
||||
ExpCmdSN in iscsi_send.c, and is enabled by default. The second definition
|
||||
effectively says "don't bother testing these values", and is used right
|
||||
now only in iscsi_send.c.
|
||||
*/
|
||||
#define ISCSI_TROTTLING_ENABLED 1
|
||||
#define ISCSI_SERVER_TRUSTED 1
|
||||
|
||||
/*
|
||||
NOTE: CCBS_PER_SESSION must not exceed 256 due to the way the ITT
|
||||
is constructed (it has the CCB index in its lower 8 bits). If it should ever
|
||||
be necessary to increase the number beyond that (which isn't expected),
|
||||
the corresponding ITT generation and extraction code must be rewritten.
|
||||
*/
|
||||
#define CCBS_PER_SESSION 64 /* ToDo: Reasonable number?? */
|
||||
/*
|
||||
NOTE: PDUS_PER_CONNECTION is a number that could potentially impact
|
||||
performance if set too low, as a single command may use up a lot of PDUs for
|
||||
high values of First/MaxBurstLength and small values of
|
||||
MaxRecvDataSegmentLength of the target.
|
||||
*/
|
||||
#define PDUS_PER_CONNECTION 64 /* ToDo: Reasonable number?? */
|
||||
|
||||
/* max outstanding serial nums before we give up on the connection */
|
||||
#define SERNUM_BUFFER_LENGTH (CCBS_PER_SESSION / 2) /* ToDo: Reasonable?? */
|
||||
|
||||
/* The RecvDataSegmentLength for Target->Initiator */
|
||||
#define DEFAULT_MaxRecvDataSegmentLength (64*1024)
|
||||
|
||||
/* Command timeout (reset on received PDU associated with the command's CCB) */
|
||||
#define COMMAND_TIMEOUT (7 * hz) /* ToDo: Reasonable? (7 seconds) */
|
||||
#define MAX_CCB_TIMEOUTS 3 /* Max number of tries to resend or SNACK */
|
||||
#define MAX_CCB_TRIES 9 /* Max number of total tries to recover */
|
||||
|
||||
/* Connectionn timeout (reset on every valid received PDU) */
|
||||
#define CONNECTION_TIMEOUT (2 * hz) /* ToDo: Reasonable? (2 seconds) */
|
||||
#define CONNECTION_IDLE_TIMEOUT (30 * hz) /* Adjusted to Time2Retain/2 later */
|
||||
#define MAX_CONN_TIMEOUTS 4 /* Max number of tries to ping a target */
|
||||
|
||||
/* Maximum attempts to recover connection */
|
||||
#define MAX_RECOVERY_ATTEMPTS 2 /* If two attempts don't work, something */
|
||||
/* probably is seriously broken */
|
||||
|
||||
/* PDU flags */
|
||||
|
||||
#define PDUF_BUSY 0x01 /* PDU is being sent, don't re-send */
|
||||
#define PDUF_INQUEUE 0x02 /* PDU is in send queue */
|
||||
#define PDUF_PRIORITY 0x04 /* Insert PDU at head of queue */
|
||||
#define PDUF_NOUPDATE 0x10 /* Do not update PDU header/digest (test mode) */
|
||||
|
||||
/* CCB Flags */
|
||||
|
||||
#define CCBF_COMPLETE 0x01 /* received status */
|
||||
#define CCBF_RESENT 0x02 /* ccb was resent */
|
||||
#define CCBF_SENDTARGET 0x04 /* SendTargets text request, not negotiation */
|
||||
#define CCBF_WAITING 0x08 /* CCB is waiting for MaxCmdSN, wake it up */
|
||||
#define CCBF_GOT_RSP 0x10 /* Got at least one response to this request */
|
||||
#define CCBF_REASSIGN 0x20 /* Command can be reassigned */
|
||||
#define CCBF_OTHERCONN 0x40 /* a logout for a different connection */
|
||||
|
||||
|
||||
/* --------------------------- Global Types ------------------------------- */
|
||||
|
||||
/* Connection state */
|
||||
|
||||
typedef enum {
|
||||
/* first three correspond to CSG/NSG coding */
|
||||
ST_SEC_NEG = 0, /* security negotiation phase */
|
||||
ST_OP_NEG = 1, /* operational negotiation phase */
|
||||
ST_FULL_FEATURE = 3, /* full feature phase */
|
||||
/* rest is internal */
|
||||
ST_WINDING_DOWN = 4, /* connection termination initiated, logging out */
|
||||
ST_LOGOUT_SENT = 5, /* logout has been sent */
|
||||
ST_SETTLING = 6, /* waiting for things to settle down */
|
||||
ST_IDLE = 7 /* connection is idle (ready to delete) */
|
||||
} conn_state_t;
|
||||
|
||||
|
||||
/* Logout state */
|
||||
|
||||
typedef enum {
|
||||
NOT_LOGGED_OUT, /* Not logged out */
|
||||
LOGOUT_SENT, /* Logout was sent */
|
||||
LOGOUT_SUCCESS, /* Logout succeeded */
|
||||
LOGOUT_FAILED /* Logout failed */
|
||||
} logout_state_t;
|
||||
|
||||
|
||||
/* CCB Disposition */
|
||||
|
||||
typedef enum {
|
||||
CCBDISP_UNUSED, /* 0 = In free pool */
|
||||
CCBDISP_BUSY, /* This CCB is busy, don't allow rx ops */
|
||||
CCBDISP_NOWAIT, /* Not waiting for anything */
|
||||
CCBDISP_FREE, /* Free this CCB when done */
|
||||
CCBDISP_WAIT, /* Calling thread is waiting for completion */
|
||||
CCBDISP_SCSIPI, /* Call scsipi_done when operation completes */
|
||||
CCBDISP_DEFER /* Defer waiting until all PDUs have been queued */
|
||||
} ccb_disp_t;
|
||||
|
||||
|
||||
/* PDU Disposition */
|
||||
|
||||
typedef enum {
|
||||
PDUDISP_UNUSED, /* 0 = In free pool */
|
||||
PDUDISP_SIGNAL, /* Free this PDU when done and wakeup(pdu) */
|
||||
PDUDISP_FREE, /* Free this PDU when done */
|
||||
PDUDISP_WAIT /* Waiting for acknowledge */
|
||||
} pdu_disp_t;
|
||||
|
||||
|
||||
typedef struct connection_s connection_t;
|
||||
typedef struct session_s session_t;
|
||||
typedef struct ccb_s ccb_t;
|
||||
typedef struct pdu_s pdu_t;
|
||||
|
||||
|
||||
#include "iscsi_testlocal.h"
|
||||
|
||||
|
||||
/* the serial number management structure (a circular buffer) */
|
||||
|
||||
typedef struct {
|
||||
uint32_t ExpSN; /* ExpxxSN (Data or Stat) sent to the target */
|
||||
uint32_t next_sn; /* next_sn (== ExpSN if no ack is pending) */
|
||||
int top; /* top of buffer (newest element) */
|
||||
int bottom; /* bottom of buffer (oldest element) */
|
||||
uint32_t sernum[SERNUM_BUFFER_LENGTH]; /* the serial numbers */
|
||||
int ack[SERNUM_BUFFER_LENGTH]; /* acknowledged? */
|
||||
} sernum_buffer_t;
|
||||
|
||||
|
||||
/*
|
||||
The per-PDU data structure.
|
||||
*/
|
||||
|
||||
struct pdu_s {
|
||||
TAILQ_ENTRY(pdu_s) chain; /* freelist or wait list (or no list) */
|
||||
TAILQ_ENTRY(pdu_s) send_chain;
|
||||
/* chaining PDUs waiting to be sent */
|
||||
pdu_disp_t disp; /* what to do with this pdu */
|
||||
uint32_t flags; /* various processing flags */
|
||||
pdu_header_t pdu; /* Buffer for PDU associated with cmd */
|
||||
void *temp_data; /* (free after use) */
|
||||
uint32_t temp_data_len; /* size of temp data */
|
||||
|
||||
struct uio uio; /* UIO structure */
|
||||
struct iovec io_vec[4];
|
||||
/* Header + data + data-digest + padding */
|
||||
|
||||
struct uio save_uio;
|
||||
/* UIO structure save for retransmits */
|
||||
struct iovec save_iovec[4];
|
||||
/* Header + data + data-digest + padding */
|
||||
uint32_t data_digest;
|
||||
/* holds data digest if enabled */
|
||||
ccb_t *owner;
|
||||
/* the ccb this PDU belongs to (if any) */
|
||||
connection_t *connection;
|
||||
/* the connection this PDU belongs to */
|
||||
|
||||
#ifdef ISCSI_TEST_MODE
|
||||
pdu_header_t mod_pdu;
|
||||
/* Buffer for modified PDU header (test mode) */
|
||||
#endif
|
||||
|
||||
#ifdef ISCSI_PERFTEST
|
||||
int perf_index;
|
||||
/* performance counter index */
|
||||
perfpoint_t perf_which; /* performance point */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/* the PDU list type */
|
||||
|
||||
TAILQ_HEAD(pdu_list_s, pdu_s);
|
||||
typedef struct pdu_list_s pdu_list_t;
|
||||
|
||||
/*
|
||||
The per-command data structure. Calling it ccb in correspondence
|
||||
to other HA drivers.
|
||||
*/
|
||||
|
||||
struct ccb_s {
|
||||
TAILQ_ENTRY(ccb_s) chain;
|
||||
/* either freelist or waiting list (or no list) */
|
||||
|
||||
uint32_t status; /* Status gets entered here */
|
||||
ccb_disp_t disp; /* what to do with this ccb */
|
||||
|
||||
struct callout timeout; /* To make sure it isn't lost */
|
||||
int num_timeouts;
|
||||
/* How often we've sent out SNACK without answer */
|
||||
int total_tries;
|
||||
/* How often we've tried to recover */
|
||||
|
||||
uint32_t ITT;
|
||||
/* task tag: ITT counter + sess id + CCB index */
|
||||
sernum_buffer_t DataSN_buf;
|
||||
/* Received Data Seq nums (read ops only) */
|
||||
|
||||
void *par;
|
||||
/* misc. parameter for this request */
|
||||
struct scsipi_xfer *xs;
|
||||
/* the scsipi_xfer for this cmd */
|
||||
|
||||
void *temp_data;
|
||||
/* to hold state (mainly during negotiation) */
|
||||
void *text_data;
|
||||
/* holds accumulated text for continued PDUs */
|
||||
uint32_t text_len;
|
||||
/* length of text data so far */
|
||||
|
||||
uint64_t lun; /* LUN */
|
||||
uint8_t *cmd; /* SCSI command block */
|
||||
uint16_t cmdlen; /* SCSI command block length */
|
||||
bool data_in; /* if this is a read request */
|
||||
uint8_t *data_ptr; /* data pointer for read/write */
|
||||
uint32_t data_len; /* total data length */
|
||||
uint32_t xfer_len; /* data transferred on read */
|
||||
uint32_t residual; /* residual data size */
|
||||
|
||||
void *sense_ptr; /* sense data pointer */
|
||||
int sense_len_req; /* requested sense data length */
|
||||
int sense_len_got; /* actual sense data length */
|
||||
|
||||
pdu_t *pdu_waiting; /* PDU waiting to be ack'ed */
|
||||
uint32_t CmdSN; /* CmdSN associated with waiting PDU */
|
||||
|
||||
int flags;
|
||||
connection_t *connection; /* connection for CCB */
|
||||
session_t *session; /* session for CCB */
|
||||
|
||||
#ifdef ISCSI_PERFTEST
|
||||
int perf_index; /* performance counter index */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/* the CCB list type */
|
||||
|
||||
TAILQ_HEAD(ccb_list_s, ccb_s);
|
||||
typedef struct ccb_list_s ccb_list_t;
|
||||
|
||||
|
||||
/*
|
||||
Per connection data: the connection structure
|
||||
*/
|
||||
#if (__NetBSD_Version__ >= 399000900)
|
||||
typedef struct lwp *PTHREADOBJ;
|
||||
#else
|
||||
typedef struct proc *PTHREADOBJ;
|
||||
#endif
|
||||
|
||||
|
||||
struct connection_s {
|
||||
TAILQ_ENTRY(connection_s) connections;
|
||||
|
||||
pdu_list_t pdu_pool; /* the free PDU pool */
|
||||
|
||||
ccb_list_t ccbs_waiting;
|
||||
/* CCBs waiting for completion */
|
||||
|
||||
pdu_list_t pdus_to_send;
|
||||
/* the PDUs waiting to be sent */
|
||||
|
||||
sernum_buffer_t StatSN_buf;
|
||||
/* to keep track of received StatSNs */
|
||||
|
||||
uint32_t max_transfer;
|
||||
/* min(MaxRecvDataSegmentLength, MaxBurstLength) */
|
||||
uint32_t max_firstimmed;
|
||||
/* 0 if InitialR2T=Yes, else
|
||||
min of (MaxRecvDataSegmentLength, FirstBurstLength) */
|
||||
uint32_t max_firstdata;
|
||||
/* 0 if ImmediateData=No, else min of */
|
||||
/* (MaxRecvDataSegmentLength, FirstBurstLength) */
|
||||
|
||||
uint32_t MaxRecvDataSegmentLength;
|
||||
/* Target's value */
|
||||
uint32_t Our_MaxRecvDataSegmentLength;
|
||||
/* Our own value */
|
||||
bool HeaderDigest; /* TRUE if doing CRC */
|
||||
bool DataDigest; /* TRUE if doing CRC */
|
||||
uint32_t Time2Wait;
|
||||
/* Negotiated default or logout value */
|
||||
uint32_t Time2Retain;
|
||||
/* Negotiated default or logout value */
|
||||
|
||||
uint16_t id;
|
||||
/* connection ID (unique within session) */
|
||||
|
||||
conn_state_t state; /* State of connection */
|
||||
|
||||
PTHREADOBJ threadobj;
|
||||
/* proc/thread pointer of socket owner */
|
||||
struct file *sock; /* the connection's socket */
|
||||
session_t *session;
|
||||
/* back pointer to the owning session */
|
||||
|
||||
struct lwp *rcvproc; /* receive thread */
|
||||
struct lwp *sendproc; /* send thread */
|
||||
|
||||
uint32_t terminating;
|
||||
/* if closing down: status */
|
||||
int recover; /* recovery count */
|
||||
/* (reset on first successful data transfer) */
|
||||
|
||||
bool destroy; /* conn will be destroyed */
|
||||
bool in_session;
|
||||
/* if it's linked into the session list */
|
||||
logout_state_t loggedout;
|
||||
/* status of logout (for recovery) */
|
||||
struct callout timeout;
|
||||
/* Timeout for checking if connection is dead */
|
||||
int num_timeouts;
|
||||
/* How often we've sent out a NOP without answer */
|
||||
uint32_t idle_timeout_val;
|
||||
/* Connection timeout value when idle */
|
||||
|
||||
iscsi_login_parameters_t *login_par;
|
||||
/* only valid during login */
|
||||
|
||||
pdu_t pdu[PDUS_PER_CONNECTION]; /* PDUs */
|
||||
|
||||
#ifdef ISCSI_TEST_MODE
|
||||
test_pars_t *test_pars;
|
||||
/* connection in test mode if non-NULL */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* the connection list type */
|
||||
|
||||
TAILQ_HEAD(connection_list_s, connection_s);
|
||||
typedef struct connection_list_s connection_list_t;
|
||||
|
||||
|
||||
/*
|
||||
Per session data: the session structure
|
||||
*/
|
||||
|
||||
struct session_s {
|
||||
/* Interface to child drivers.
|
||||
NOTE: sc_adapter MUST be the first field in this structure so we can
|
||||
easily get from adapter to session.
|
||||
*/
|
||||
struct scsipi_adapter sc_adapter;
|
||||
struct scsipi_channel sc_channel;
|
||||
|
||||
device_t child_dev;
|
||||
/* the child we're associated with - (NULL if not mapped) */
|
||||
|
||||
/* local stuff */
|
||||
TAILQ_ENTRY(session_s) sessions; /* the list of sessions */
|
||||
|
||||
ccb_list_t ccb_pool; /* The free CCB pool */
|
||||
ccb_list_t ccbs_throttled;
|
||||
/* CCBs waiting for MaxCmdSN to increase */
|
||||
|
||||
uint16_t id; /* session ID (unique within driver) */
|
||||
uint16_t TSIH; /* Target assigned session ID */
|
||||
|
||||
uint32_t CmdSN; /* Current CmdSN */
|
||||
uint32_t ExpCmdSN; /* Current max ExpCmdSN received */
|
||||
uint32_t MaxCmdSN; /* Current MaxCmdSN */
|
||||
|
||||
/* negotiated values */
|
||||
uint32_t ErrorRecoveryLevel;
|
||||
uint32_t FirstBurstLength;
|
||||
uint32_t MaxBurstLength;
|
||||
bool ImmediateData;
|
||||
bool InitialR2T;
|
||||
uint32_t MaxOutstandingR2T;
|
||||
uint32_t MaxConnections;
|
||||
uint32_t DefaultTime2Wait;
|
||||
uint32_t DefaultTime2Retain;
|
||||
|
||||
iscsi_login_session_type_t login_type; /* session type */
|
||||
|
||||
/* for send_targets requests */
|
||||
uint8_t *target_list;
|
||||
uint32_t target_list_len;
|
||||
|
||||
uint32_t conn_id; /* connection ID counter */
|
||||
|
||||
uint32_t terminating; /* if closing down: status */
|
||||
|
||||
uint32_t active_connections;
|
||||
/* currently active connections */
|
||||
uint32_t total_connections;
|
||||
/* connections associated with this session (active or winding down) */
|
||||
connection_list_t conn_list; /* the list of connections */
|
||||
connection_t *mru_connection;
|
||||
/* the most recently used connection */
|
||||
|
||||
uint8_t itt_id; /* counter for use in ITT */
|
||||
|
||||
ccb_t ccb[CCBS_PER_SESSION]; /* CCBs */
|
||||
|
||||
char tgtname[ISCSI_STRING_LENGTH + 1];
|
||||
/* iSCSI target name */
|
||||
};
|
||||
|
||||
/* the session list type */
|
||||
|
||||
TAILQ_HEAD(session_list_s, session_s);
|
||||
typedef struct session_list_s session_list_t;
|
||||
|
||||
|
||||
/*
|
||||
The softc structure. This driver doesn't really need one, because there's
|
||||
always just one instance, and for the time being it's only loaded as
|
||||
an LKM (which doesn't create a softc), but we need one to put into the
|
||||
scsipi interface structures, so here it is.
|
||||
*/
|
||||
|
||||
typedef struct iscsi_softc {
|
||||
device_t sc_dev;
|
||||
} iscsi_softc_t;
|
||||
|
||||
|
||||
/*
|
||||
Event notification structures
|
||||
*/
|
||||
|
||||
typedef struct event_s {
|
||||
TAILQ_ENTRY(event_s) link; /* next event in queue */
|
||||
iscsi_event_t event_kind; /* which event */
|
||||
uint32_t session_id; /* affected session ID */
|
||||
uint32_t connection_id; /* affected connection ID */
|
||||
uint32_t reason; /* event reason */
|
||||
} event_t;
|
||||
|
||||
/* the event list entry type */
|
||||
|
||||
TAILQ_HEAD(event_list_s, event_s);
|
||||
typedef struct event_list_s event_list_t;
|
||||
|
||||
|
||||
typedef struct event_handler_s {
|
||||
TAILQ_ENTRY(event_handler_s) link; /* next handler */
|
||||
uint32_t id; /* unique ID */
|
||||
event_list_t events; /* list of events pending */
|
||||
iscsi_wait_event_parameters_t *waiter; /* waiting parameter */
|
||||
/* following to detect dead handlers */
|
||||
event_t *first_in_list;
|
||||
} event_handler_t;
|
||||
|
||||
/* the event list entry type */
|
||||
|
||||
TAILQ_HEAD(event_handler_list_s, event_handler_s);
|
||||
typedef struct event_handler_list_s event_handler_list_t;
|
||||
|
||||
|
||||
/* ------------------------- Global Variables ----------------------------- */
|
||||
|
||||
/* In iscsi_main.c */
|
||||
|
||||
struct cfattach iscsi_ca; /* the device attach structure */
|
||||
struct cdevsw iscsi_cdevsw; /* the character device descriptor */
|
||||
|
||||
iscsi_softc_t *sc; /* our device pointer */
|
||||
session_list_t sessions; /* the list of sessions */
|
||||
|
||||
connection_list_t cleanup_list; /* connections to clean up */
|
||||
bool detaching; /* signal to cleanup thread it should exit */
|
||||
struct lwp *cleanproc; /* pointer to cleanup proc */
|
||||
|
||||
uint32_t num_send_threads; /* the number of active send threads */
|
||||
|
||||
uint8_t InitiatorName[ISCSI_STRING_LENGTH];
|
||||
uint8_t InitiatorAlias[ISCSI_STRING_LENGTH];
|
||||
login_isid_t InitiatorISID;
|
||||
|
||||
|
||||
/* ------------------------- Global Functions ----------------------------- */
|
||||
|
||||
#ifdef __NetBSD__
|
||||
#define GEN_RAND(buffer, len) rnd_extract_data (buffer, len, RND_EXTRACT_ANY)
|
||||
#else
|
||||
#define GEN_RAND(buffer, len) get_random_bytes (buffer, len)
|
||||
#endif
|
||||
|
||||
static __inline uint8_t
|
||||
randb(void)
|
||||
{
|
||||
uint8_t buf;
|
||||
|
||||
GEN_RAND(&buf, 1);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/* Debugging and profiling stuff */
|
||||
|
||||
#include "iscsi_profile.h"
|
||||
|
||||
#ifndef DDB
|
||||
#define Debugger() panic("should call debugger here (iscsi.c)")
|
||||
#endif /* ! DDB */
|
||||
|
||||
#if defined(ISCSI_PERFTEST)
|
||||
|
||||
int perf_level; /* How much info to display */
|
||||
|
||||
#define PDEBOUT(x) printf x
|
||||
#define PDEB(lev,x) { if (perf_level >= lev) printf x ;}
|
||||
#define PDEBC(conn,lev,x) { { if (perf_level >= lev) printf("S%dC%d: ", \
|
||||
conn->session->id, conn->id); printf x ;}}
|
||||
#else
|
||||
#define PDEBOUT(x)
|
||||
#define PDEB(lev,x)
|
||||
#define PDEBC(conn,lev,x)
|
||||
#endif
|
||||
|
||||
#ifdef ISCSI_DEBUG
|
||||
|
||||
int debug_level; /* How much debug info to display */
|
||||
|
||||
#define DEBOUT(x) printf x
|
||||
#define DEB(lev,x) { if (debug_level >= lev) printf x ;}
|
||||
#define DEBC(conn,lev,x) { if (debug_level >= lev) { printf("S%dC%d: ", \
|
||||
conn->session->id, conn->id); printf x ;}}
|
||||
void dump(void *buf, int len);
|
||||
|
||||
#define STATIC static
|
||||
|
||||
#else
|
||||
|
||||
#define DEBOUT(x)
|
||||
#define DEB(lev,x)
|
||||
#define DEBC(conn,lev,x)
|
||||
#define dump(a,b)
|
||||
|
||||
#define STATIC static
|
||||
|
||||
#endif
|
||||
|
||||
/* Critical section macros */
|
||||
|
||||
#define CS_BEGIN { int s = splbio ();
|
||||
#define CS_END splx (s); }
|
||||
|
||||
/* misc stuff */
|
||||
#define min(a, b) ((a) < (b)) ? (a) : (b)
|
||||
#define max(a, b) ((a) < (b)) ? (b) : (a)
|
||||
|
||||
|
||||
/*
|
||||
Convert unsigned int to 3-byte value (for DataSegmentLength field in PDU)
|
||||
*/
|
||||
|
||||
static __inline void
|
||||
hton3(uint32_t val, uint8_t *bytes)
|
||||
{
|
||||
bytes[0] = (uint8_t) (val >> 16);
|
||||
bytes[1] = (uint8_t) (val >> 8);
|
||||
bytes[2] = (uint8_t) val;
|
||||
}
|
||||
|
||||
/*
|
||||
Convert 3-byte value to unsigned int (for DataSegmentLength field in PDU)
|
||||
*/
|
||||
|
||||
static __inline uint32_t
|
||||
ntoh3(uint8_t *bytes)
|
||||
{
|
||||
return (bytes[0] << 16) | (bytes[1] << 8) | bytes[2];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert uint64 to network byte order (for LUN field in PDU)
|
||||
*/
|
||||
static __inline uint64_t
|
||||
htonq(uint64_t x)
|
||||
{
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
uint8_t *s = (uint8_t *) & x;
|
||||
return (uint64_t) ((uint64_t) s[0] << 56 | (uint64_t) s[1] << 48 |
|
||||
(uint64_t) s[2] << 40 | (uint64_t) s[3] << 32 |
|
||||
(uint64_t) s[4] << 24 | (uint64_t) s[5] << 16 |
|
||||
(uint64_t) s[6] << 8 | (uint64_t) s[7]);
|
||||
#else
|
||||
return x;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define ntohq(x) htonq(x)
|
||||
|
||||
/*
|
||||
* Serial number buffer empty?
|
||||
*/
|
||||
|
||||
static __inline bool
|
||||
sn_empty(sernum_buffer_t *buf)
|
||||
{
|
||||
return buf->top == buf->bottom;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Serial number compare
|
||||
*/
|
||||
|
||||
static __inline bool
|
||||
sn_a_lt_b(uint32_t a, uint32_t b)
|
||||
{
|
||||
return (a < b && !((b - a) & 0x80000000)) ||
|
||||
(a > b && ((a - b) & 0x80000000));
|
||||
}
|
||||
|
||||
static __inline bool
|
||||
sn_a_le_b(uint32_t a, uint32_t b)
|
||||
{
|
||||
return (a <= b && !((b - a) & 0x80000000)) ||
|
||||
(a >= b && ((a - b) & 0x80000000));
|
||||
}
|
||||
|
||||
|
||||
/* Version dependencies */
|
||||
|
||||
|
||||
#if (__NetBSD_Version__ >= 399000900)
|
||||
#define PROCP(obj) (obj->l_proc)
|
||||
#else
|
||||
#define PROCP(obj) obj
|
||||
#define UIO_SETUP_SYSSPACE(uio) (uio)->uio_segflg = UIO_SYSSPACE
|
||||
#endif
|
||||
|
||||
#if (__NetBSD_Version__ >= 106000000)
|
||||
# ifdef ISCSI_TEST_MODE
|
||||
#define SET_CCB_TIMEOUT(conn, ccb, tout) do { \
|
||||
if (test_ccb_timeout (conn)) { \
|
||||
callout_schedule(&ccb->timeout, tout); \
|
||||
} \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
# else
|
||||
#define SET_CCB_TIMEOUT(conn, ccb, tout) callout_schedule(&ccb->timeout, tout)
|
||||
# endif
|
||||
#else
|
||||
/* no test mode for 1.5 */
|
||||
#define SET_CCB_TIMEOUT(conn, ccb, tout) \
|
||||
callout_reset(&ccb->timeout, tout, ccb_timeout, ccb)
|
||||
#endif
|
||||
|
||||
#if (__NetBSD_Version__ >= 106000000)
|
||||
# ifdef ISCSI_TEST_MODE
|
||||
#define SET_CONN_TIMEOUT(conn, tout) do { \
|
||||
if (test_conn_timeout (conn)) { \
|
||||
callout_schedule(&conn->timeout, tout); \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
# else
|
||||
#define SET_CONN_TIMEOUT(conn, tout) callout_schedule(&conn->timeout, tout)
|
||||
# endif
|
||||
#else
|
||||
/* no test mode for 1.5 */
|
||||
#define SET_CONN_TIMEOUT(conn, tout) \
|
||||
callout_reset(&conn->timeout, tout, connection_timeout, conn)
|
||||
#endif
|
||||
|
||||
/* in iscsi_ioctl.c */
|
||||
|
||||
/* Parameter for logout is reason code in logout PDU, -1 for don't send logout */
|
||||
#define NO_LOGOUT -1
|
||||
#define LOGOUT_SESSION 0
|
||||
#define LOGOUT_CONNECTION 1
|
||||
#define RECOVER_CONNECTION 2
|
||||
|
||||
void add_event(iscsi_event_t, uint32_t, uint32_t, uint32_t);
|
||||
|
||||
void kill_connection(connection_t *, uint32_t, int, bool);
|
||||
void kill_session(session_t *, uint32_t, int, bool);
|
||||
void kill_all_sessions(void);
|
||||
void handle_connection_error(connection_t *, uint32_t, int);
|
||||
void iscsi_cleanup_thread(void *);
|
||||
|
||||
#ifndef ISCSI_MINIMAL
|
||||
uint32_t map_databuf(struct proc *, void **, uint32_t);
|
||||
void unmap_databuf(struct proc *, void *, uint32_t);
|
||||
#endif
|
||||
int iscsiioctl(dev_t, u_long, void *, int, PTHREADOBJ);
|
||||
|
||||
session_t *find_session(uint32_t);
|
||||
connection_t *find_connection(session_t *, uint32_t);
|
||||
|
||||
|
||||
/* in iscsi_main.c */
|
||||
|
||||
/*void iscsiattach(void *); */
|
||||
int iscsidetach(device_t, int);
|
||||
|
||||
void iscsi_done(ccb_t *);
|
||||
int map_session(session_t *);
|
||||
void unmap_session(session_t *);
|
||||
|
||||
/* in iscsi_send.c */
|
||||
|
||||
void iscsi_send_thread(void *);
|
||||
|
||||
connection_t *assign_connection(session_t *session, bool waitok);
|
||||
void resend_pdu(ccb_t *);
|
||||
int send_login(connection_t *);
|
||||
int send_logout(connection_t *, connection_t *, int, bool);
|
||||
int send_data_out(connection_t *, pdu_t *, ccb_t *, ccb_disp_t, bool);
|
||||
void send_run_xfer(session_t *, struct scsipi_xfer *);
|
||||
int send_send_targets(session_t *, uint8_t *);
|
||||
int send_task_management(connection_t *, ccb_t *, struct scsipi_xfer *, int);
|
||||
|
||||
void negotiate_login(connection_t *, pdu_t *, ccb_t *);
|
||||
void acknowledge_text(connection_t *, pdu_t *, ccb_t *);
|
||||
void start_text_negotiation(connection_t *);
|
||||
void negotiate_text(connection_t *, pdu_t *, ccb_t *);
|
||||
int send_nop_out(connection_t *, pdu_t *);
|
||||
void snack_missing(connection_t *, ccb_t *, uint8_t, uint32_t, uint32_t);
|
||||
void send_snack(connection_t *, pdu_t *, ccb_t *, uint8_t);
|
||||
int send_send_targets(session_t *, uint8_t *);
|
||||
|
||||
void send_command(ccb_t *, ccb_disp_t, bool, bool);
|
||||
#ifndef ISCSI_MINIMAL
|
||||
int send_io_command(session_t *, uint64_t, scsireq_t *, bool, uint32_t);
|
||||
#endif
|
||||
|
||||
void connection_timeout(void *);
|
||||
void ccb_timeout(void *);
|
||||
|
||||
/* in iscsi_rcv.c */
|
||||
|
||||
void iscsi_rcv_thread(void *);
|
||||
|
||||
/* in iscsi_utils.c */
|
||||
|
||||
uint32_t gen_digest(void *, int);
|
||||
uint32_t gen_digest_2(void *, int, void *, int);
|
||||
|
||||
void create_ccbs(session_t *);
|
||||
ccb_t *get_ccb(connection_t *, bool);
|
||||
void free_ccb(ccb_t *);
|
||||
void wake_ccb(ccb_t *);
|
||||
void complete_ccb(ccb_t *);
|
||||
|
||||
void create_pdus(connection_t *);
|
||||
pdu_t *get_pdu(connection_t *);
|
||||
pdu_t *get_pdu_c(connection_t *, bool);
|
||||
void free_pdu(pdu_t *);
|
||||
|
||||
void init_sernum(sernum_buffer_t *);
|
||||
int add_sernum(sernum_buffer_t *, uint32_t);
|
||||
uint32_t ack_sernum(sernum_buffer_t *, uint32_t);
|
||||
|
||||
/* in iscsi_text.c */
|
||||
|
||||
int assemble_login_parameters(connection_t *, ccb_t *, pdu_t *);
|
||||
int assemble_security_parameters(connection_t *, ccb_t *, pdu_t *, pdu_t *);
|
||||
int assemble_negotiation_parameters(connection_t *, ccb_t *, pdu_t *, pdu_t *);
|
||||
int init_text_parameters(connection_t *, ccb_t *);
|
||||
int assemble_send_targets(pdu_t *, uint8_t *);
|
||||
void set_negotiated_parameters(ccb_t *);
|
||||
|
||||
#endif /* !_ISCSI_GLOBALS_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,439 @@
|
|||
/* $NetBSD: iscsi_ioctl.h,v 1.1 2011/10/23 21:15:02 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Wasabi Systems, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _ISCSI_IOCTL_H
|
||||
#define _ISCSI_IOCTL_H
|
||||
|
||||
#include <dev/iscsi/iscsi.h>
|
||||
|
||||
/* ================== Interface Structures ======================== */
|
||||
|
||||
/* ===== Login, add_connection, and restore_connection ===== */
|
||||
|
||||
typedef struct {
|
||||
uint32_t status;
|
||||
int socket;
|
||||
struct {
|
||||
int HeaderDigest:1;
|
||||
int DataDigest:1;
|
||||
int MaxConnections:1;
|
||||
int DefaultTime2Wait:1;
|
||||
int DefaultTime2Retain:1;
|
||||
int MaxRecvDataSegmentLength:1;
|
||||
int auth_info:1;
|
||||
int user_name:1;
|
||||
int password:1;
|
||||
int target_password:1;
|
||||
int TargetName:1;
|
||||
int TargetAlias:1;
|
||||
int ErrorRecoveryLevel:1;
|
||||
} is_present;
|
||||
iscsi_auth_info_t auth_info;
|
||||
iscsi_login_session_type_t login_type;
|
||||
iscsi_digest_t HeaderDigest;
|
||||
iscsi_digest_t DataDigest;
|
||||
uint32_t session_id;
|
||||
uint32_t connection_id;
|
||||
uint32_t MaxRecvDataSegmentLength;
|
||||
uint16_t MaxConnections;
|
||||
uint16_t DefaultTime2Wait;
|
||||
uint16_t DefaultTime2Retain;
|
||||
uint16_t ErrorRecoveryLevel;
|
||||
void *user_name;
|
||||
void *password;
|
||||
void *target_password;
|
||||
void *TargetName;
|
||||
void *TargetAlias;
|
||||
} iscsi_login_parameters_t;
|
||||
|
||||
/*
|
||||
status
|
||||
Contains, on return, the result of the command.
|
||||
socket
|
||||
A handle to the open TCP connection to the target portal.
|
||||
is_present
|
||||
Contains a bitfield that indicates which members of the
|
||||
iscsi_login_parameters structure contain valid data.
|
||||
auth_info
|
||||
Is a bitfield of parameters for authorization.
|
||||
The members are
|
||||
mutual_auth Indicates that authentication should be mutual, i.e.
|
||||
the initiator should authenticate the target, and the target
|
||||
should authenticate the initiator. If not specified, the target
|
||||
will authenticate the initiator only.
|
||||
is_secure Indicates that the connection is secure.
|
||||
auth_number Indicates the number of elements in auth_type.
|
||||
When 0, no authentication will be used.
|
||||
auth_type
|
||||
Contains up to ISCSI_AUTH_OPTIONS enumerator values of type
|
||||
iscsi_auth_types that indicates the authentication method that should
|
||||
be used to establish a login connection (none, CHAP, KRB5, etc.), in
|
||||
order of priority. The first element is the most preferred method, the
|
||||
last element the least preferred.
|
||||
login_type
|
||||
Contains an enumerator value of type login_session_type that indicates
|
||||
the type of logon session (discovery, informational, or full featured).
|
||||
HeaderDigest
|
||||
Indicates which digest (if any) to use for the PDU header.
|
||||
DataDigest
|
||||
Indicates which digest (if any) to use for the PDU data.
|
||||
session_id
|
||||
Login: OUT: Receives an integer that identifies the session.
|
||||
Add_connection, Restore_connection: IN: Session ID.
|
||||
connection_id
|
||||
Login, Add_connection: OUT: Receives an integer that identifies the
|
||||
connection.
|
||||
Restore_connection: IN: Connection ID.
|
||||
MaxRecvDataSegmentLength
|
||||
Allows limiting or extending the maximum receive data segment length.
|
||||
Must contain a value between 512 and 2**24-1 if specified.
|
||||
MaxConnections
|
||||
Contains a value between 1 and 65535 that specifies the maximum number
|
||||
of connections to target devices that can be associated with a single
|
||||
logon session. A value of 0 indicates that there no limit to the
|
||||
number of connections.
|
||||
DefaultTime2Wait
|
||||
Specifies the minimum time to wait, in seconds, before attempting to
|
||||
reconnect or reassign a connection that has been dropped.
|
||||
The default is 2.
|
||||
DefaultTime2Retain
|
||||
Specifies the maximum time, in seconds, allowed to reassign a
|
||||
connection after the initial wait indicated in DefaultTime2Retain has
|
||||
elapsed. The default is 20.
|
||||
ErrorRecoveryLevel
|
||||
Specifies the desired error recovery level for the session.
|
||||
The default and maximum is 2.
|
||||
user_name
|
||||
Sets the user (or CHAP) name to use during login authentication of the
|
||||
initiator (zero terminated UTF-8 string). Default is initiator name.
|
||||
password
|
||||
Contains the password to use during login authentication of the
|
||||
initiator (zero terminated UTF-8 string). Required if authentication
|
||||
is requested.
|
||||
target_password
|
||||
Contains the password to use during login authentication of the target
|
||||
(zero terminated UTF-8 string). Required if mutual authentication is
|
||||
requested.
|
||||
TargetName
|
||||
Indicates the name of the target with which to establish the logon
|
||||
session (zero terminated UTF-8 string).
|
||||
TargetAlias
|
||||
Receives the target alias as a zero terminated UTF-8 string. When
|
||||
present, the buffer must be of size ISCSI_STRING_LENGTH.
|
||||
*/
|
||||
|
||||
|
||||
/* ===== Logout ===== */
|
||||
|
||||
typedef struct {
|
||||
uint32_t status;
|
||||
uint32_t session_id;
|
||||
} iscsi_logout_parameters_t;
|
||||
|
||||
/*
|
||||
status
|
||||
Contains, on return, the result of the command.
|
||||
session_id
|
||||
Contains an integer that identifies the session.
|
||||
*/
|
||||
|
||||
/* ===== remove_connection ===== */
|
||||
|
||||
typedef struct {
|
||||
uint32_t status;
|
||||
uint32_t session_id;
|
||||
uint32_t connection_id;
|
||||
} iscsi_remove_parameters_t;
|
||||
|
||||
/*
|
||||
status
|
||||
Contains, on return, the result of the command.
|
||||
session_id
|
||||
Contains an integer that identifies the session.
|
||||
connection_id
|
||||
Contains an integer that identifies the connection.
|
||||
*/
|
||||
|
||||
/* ===== connection status ===== */
|
||||
|
||||
typedef struct {
|
||||
uint32_t status;
|
||||
uint32_t session_id;
|
||||
uint32_t connection_id;
|
||||
} iscsi_conn_status_parameters_t;
|
||||
|
||||
/*
|
||||
status
|
||||
Contains, on return, the result of the command.
|
||||
session_id
|
||||
Contains an integer that identifies the session.
|
||||
connection_id
|
||||
Contains an integer that identifies the connection.
|
||||
*/
|
||||
|
||||
/* ===== io_command ===== */
|
||||
|
||||
typedef struct {
|
||||
uint32_t status;
|
||||
uint32_t session_id;
|
||||
uint32_t connection_id;
|
||||
struct {
|
||||
int immediate:1;
|
||||
} options;
|
||||
uint64_t lun;
|
||||
scsireq_t req;
|
||||
} iscsi_iocommand_parameters_t;
|
||||
|
||||
/*
|
||||
status
|
||||
Contains, on return, the result of the command (an ISCSI_STATUS code).
|
||||
lun
|
||||
Indicates which of the target's logical units should provide the data.
|
||||
session_id
|
||||
Contains an integer that identifies the session.
|
||||
connection_id
|
||||
Contains an integer that identifies the connection.
|
||||
This parameter is optional and should only be used for test purposes.
|
||||
options
|
||||
A bitfield indicating options for the command.
|
||||
The members are
|
||||
immediate Indicates that the command should be sent
|
||||
immediately, ahead of any queued requests.
|
||||
|
||||
req
|
||||
Contains the parameters for the request as defined in sys/scsiio.h
|
||||
typedef struct scsireq {
|
||||
u_long flags;
|
||||
u_long timeout;
|
||||
uint8_t cmd[16];
|
||||
uint8_t cmdlen;
|
||||
void * databuf;
|
||||
u_long datalen;
|
||||
u_long datalen_used;
|
||||
uint8_t sense[SENSEBUFLEN];
|
||||
uint8_t senselen;
|
||||
uint8_t senselen_used;
|
||||
uint8_t status;
|
||||
uint8_t retsts;
|
||||
int error;
|
||||
} scsireq_t;
|
||||
|
||||
flags
|
||||
Indicates request status and type.
|
||||
timeout
|
||||
Indicates a timeout value (reserved).
|
||||
cmd
|
||||
SCSI command buffer.
|
||||
cmdlen
|
||||
Length of SCSI command in cmd.
|
||||
databuf
|
||||
Pointer to user-space buffer that holds the data
|
||||
read or written by the SCSI command.
|
||||
datalen
|
||||
Indicates the size in bytes of the buffer at databuf.
|
||||
datalen_used
|
||||
Returns the number of bytes actually read or written.
|
||||
sense
|
||||
Sense data buffer.
|
||||
senselen
|
||||
Indicates the requested size of sense data. Must not exceed
|
||||
SENSEBUFLEN (48).
|
||||
senselen_used
|
||||
Contains, on return, the number of bytes written to sense.
|
||||
status
|
||||
Contains, on return, the original SCSI status (reserved).
|
||||
retsts
|
||||
Contains, on return, the status of the command as defined in scsiio.h.
|
||||
error
|
||||
Contains, on return, the original SCSI error bits (reserved).
|
||||
*/
|
||||
|
||||
|
||||
/* ===== send_targets ===== */
|
||||
|
||||
typedef struct {
|
||||
uint32_t status;
|
||||
uint32_t session_id;
|
||||
void *response_buffer;
|
||||
uint32_t response_size;
|
||||
uint32_t response_used;
|
||||
uint32_t response_total;
|
||||
uint8_t key[ISCSI_STRING_LENGTH];
|
||||
} iscsi_send_targets_parameters_t;
|
||||
|
||||
/*
|
||||
status
|
||||
Contains, on return, the result of the command.
|
||||
session_id
|
||||
Contains an integer that identifies the session.
|
||||
response_buffer
|
||||
User mode address of buffer to hold the response data retrieved by
|
||||
the iSCSI send targets command.
|
||||
response_size
|
||||
Contains, on input, the size in bytes of the buffer at
|
||||
response_buffer. If this is 0, the command will execute the
|
||||
SendTargets request, and return (in response_total) the number of
|
||||
bytes required.
|
||||
response_used
|
||||
Contains, on return, the number of bytes actually retrieved to
|
||||
response_buffer.
|
||||
response_total
|
||||
Contains, on return, the total number of bytes required to hold the
|
||||
complete list of targets. This may be larger than response_size.
|
||||
key
|
||||
Specifies the SendTargets key value ("All", <target name>, or empty).
|
||||
*/
|
||||
|
||||
/* ===== set_node_name ===== */
|
||||
|
||||
typedef struct {
|
||||
uint32_t status;
|
||||
uint8_t InitiatorName[ISCSI_STRING_LENGTH];
|
||||
uint8_t InitiatorAlias[ISCSI_STRING_LENGTH];
|
||||
uint8_t ISID[6];
|
||||
} iscsi_set_node_name_parameters_t;
|
||||
|
||||
/*
|
||||
status
|
||||
Contains, on return, the result of the command.
|
||||
InitiatorName
|
||||
Specifies the InitiatorName used during login. Required.
|
||||
InitiatorAlias
|
||||
Specifies the InitiatorAlias for use during login. May be empty.
|
||||
ISID
|
||||
Specifies the ISID (a 6 byte binary value) for use during login.
|
||||
May be zero (all bytes) for the initiator to use a default value.
|
||||
*/
|
||||
|
||||
/* ===== register_event and deregister_event ===== */
|
||||
|
||||
typedef struct {
|
||||
uint32_t status;
|
||||
uint32_t event_id;
|
||||
} iscsi_register_event_parameters_t;
|
||||
|
||||
/*
|
||||
status
|
||||
Contains, on return, the result of the command.
|
||||
event_id
|
||||
Returns driver-assigned event ID to be used in
|
||||
subsequent calls to wait_event and deregister_event.
|
||||
*/
|
||||
|
||||
/* ===== wait_event ===== */
|
||||
|
||||
typedef enum {
|
||||
ISCSI_SESSION_TERMINATED = 1,
|
||||
ISCSI_CONNECTION_TERMINATED,
|
||||
ISCSI_RECOVER_CONNECTION,
|
||||
ISCSI_DRIVER_TERMINATING
|
||||
} iscsi_event_t;
|
||||
|
||||
/*
|
||||
Driver Events
|
||||
|
||||
ISCSI_SESSION_TERMINATED
|
||||
The specified session (including all of its associated connections)
|
||||
has been terminated.
|
||||
ISCSI_CONNECTION_TERMINATED
|
||||
The specified connection has been terminated.
|
||||
ISCSI_RECOVER_CONNECTION
|
||||
The application should attempt to recover the given connection.
|
||||
ISCSI_DRIVER_TERMINATING
|
||||
The driver is unloading.
|
||||
The application MUST call ISCSI_DEREGISTER_EVENT as soon as possible
|
||||
after receiving this event. After performing the deregister IOCTL,
|
||||
the application must no longer attempt to access the driver.
|
||||
*/
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t status;
|
||||
uint32_t event_id;
|
||||
iscsi_event_t event_kind;
|
||||
uint32_t session_id;
|
||||
uint32_t connection_id;
|
||||
uint32_t reason;
|
||||
} iscsi_wait_event_parameters_t;
|
||||
|
||||
/*
|
||||
status
|
||||
Contains, on return, the result of the command.
|
||||
event_id
|
||||
Driver assigned event ID.
|
||||
event_kind
|
||||
Identifies the event.
|
||||
session_id
|
||||
Identifies the affected session (0 for DRIVER_TERMINATING).
|
||||
connection_id
|
||||
Identifies the affected connection (0 for DRIVER_TERMINATING).
|
||||
reason
|
||||
Identifies the termination reason (ISCSI status code).
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint32_t status;
|
||||
uint16_t interface_version;
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
uint8_t version_string[ISCSI_STRING_LENGTH];
|
||||
} iscsi_get_version_parameters_t;
|
||||
|
||||
/*
|
||||
status
|
||||
Contains, on return, the result of the command.
|
||||
interface_version
|
||||
Updated when interface changes. Current Version is 2.
|
||||
major
|
||||
Major version number.
|
||||
minor
|
||||
Minor version number.
|
||||
version_string
|
||||
Displayable version string (zero terminated).
|
||||
*/
|
||||
|
||||
/* ========================= IOCTL Codes =========================== */
|
||||
|
||||
#define ISCSI_GET_VERSION _IOWR(0, 1, iscsi_get_version_parameters_t)
|
||||
#define ISCSI_LOGIN _IOWR(0, 2, iscsi_login_parameters_t)
|
||||
#define ISCSI_LOGOUT _IOWR(0, 3, iscsi_logout_parameters_t)
|
||||
#define ISCSI_ADD_CONNECTION _IOWR(0, 4, iscsi_login_parameters_t)
|
||||
#define ISCSI_RESTORE_CONNECTION _IOWR(0, 5, iscsi_login_parameters_t)
|
||||
#define ISCSI_REMOVE_CONNECTION _IOWR(0, 6, iscsi_remove_parameters_t)
|
||||
#define ISCSI_CONNECTION_STATUS _IOWR(0, 7, iscsi_conn_status_parameters_t)
|
||||
#define ISCSI_SEND_TARGETS _IOWR(0, 8, iscsi_send_targets_parameters_t)
|
||||
#define ISCSI_SET_NODE_NAME _IOWR(0, 9, iscsi_set_node_name_parameters_t)
|
||||
#define ISCSI_IO_COMMAND _IOWR(0, 10, iscsi_iocommand_parameters_t)
|
||||
#define ISCSI_REGISTER_EVENT _IOWR(0, 11, iscsi_register_event_parameters_t)
|
||||
#define ISCSI_DEREGISTER_EVENT _IOWR(0, 12, iscsi_register_event_parameters_t)
|
||||
#define ISCSI_WAIT_EVENT _IOWR(0, 13, iscsi_wait_event_parameters_t)
|
||||
#define ISCSI_POLL_EVENT _IOWR(0, 14, iscsi_wait_event_parameters_t)
|
||||
|
||||
#endif /* !_ISCSI_IOCTL_H */
|
|
@ -0,0 +1,580 @@
|
|||
/* $netBSD: iscsi_main.c,v 1.1.1.1 2011/05/02 07:01:11 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Wasabi Systems, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "iscsi_globals.h"
|
||||
|
||||
#include <sys/systm.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/kmem.h>
|
||||
#include <sys/socketvar.h>
|
||||
|
||||
|
||||
/*------------------------- Global Variables ------------------------*/
|
||||
|
||||
extern struct cfdriver iscsi_cd;
|
||||
|
||||
#if defined(ISCSI_DEBUG)
|
||||
int debug_level = ISCSI_DEBUG;
|
||||
#endif
|
||||
|
||||
#if defined(ISCSI_PERFTEST)
|
||||
int perf_level = 0;
|
||||
#endif
|
||||
|
||||
/* Device Structure */
|
||||
iscsi_softc_t *sc = NULL;
|
||||
|
||||
/* the list of sessions */
|
||||
session_list_t sessions = TAILQ_HEAD_INITIALIZER(sessions);
|
||||
|
||||
/* connections to clean up */
|
||||
connection_list_t cleanup_list = TAILQ_HEAD_INITIALIZER(cleanup_list);
|
||||
bool detaching = FALSE;
|
||||
struct lwp *cleanproc = NULL;
|
||||
|
||||
/* the number of active send threads (for cleanup thread) */
|
||||
uint32_t num_send_threads = 0;
|
||||
|
||||
/* Our node name, alias, and ISID */
|
||||
uint8_t InitiatorName[ISCSI_STRING_LENGTH] = "";
|
||||
uint8_t InitiatorAlias[ISCSI_STRING_LENGTH] = "";
|
||||
login_isid_t InitiatorISID;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/*
|
||||
System interface: autoconf and device structures
|
||||
*/
|
||||
|
||||
void iscsiattach(int);
|
||||
void iscsi_attach(device_t parent, device_t self, void *aux);
|
||||
int iscsi_match(device_t, cfdata_t, void *);
|
||||
int iscsi_detach(device_t, int);
|
||||
|
||||
|
||||
CFATTACH_DECL_NEW(iscsi, sizeof(struct iscsi_softc), iscsi_match, iscsi_attach,
|
||||
iscsi_detach, NULL);
|
||||
|
||||
|
||||
int iscsiopen(dev_t, int, int, PTHREADOBJ);
|
||||
int iscsiclose(dev_t, int, int, PTHREADOBJ);
|
||||
|
||||
struct cdevsw iscsi_cdevsw = {
|
||||
iscsiopen, iscsiclose,
|
||||
noread, nowrite,
|
||||
iscsiioctl, nostop, notty, nopoll, nommap, nokqfilter, D_OTHER
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
STATIC void iscsi_scsipi_request(struct scsipi_channel *,
|
||||
scsipi_adapter_req_t, void *);
|
||||
STATIC void iscsi_minphys(struct buf *);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* Open and Close device interfaces. We don't really need them, because we don't
|
||||
* have to keep track of device opens and closes from userland. But apps can't
|
||||
* call ioctl without a handle to the device, and the kernel doesn't hand out
|
||||
* handles without an open routine in the driver. So here they are in all their
|
||||
* glory...
|
||||
*******************************************************************************/
|
||||
|
||||
int
|
||||
iscsiopen(dev_t dev, int flag, int mode, PTHREADOBJ p)
|
||||
{
|
||||
|
||||
DEB(99, ("ISCSI Open\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
iscsiclose(dev_t dev, int flag, int mode, PTHREADOBJ p)
|
||||
{
|
||||
|
||||
DEB(99, ("ISCSI Close\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/*
|
||||
* The config Match routine.
|
||||
* Not much to do here, either - this is a pseudo-device.
|
||||
*/
|
||||
|
||||
int
|
||||
iscsi_match(device_t self, cfdata_t cfdata, void *arg)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* iscsiattach:
|
||||
* Only called when statically configured into a kernel
|
||||
*/
|
||||
void
|
||||
iscsiattach(int n)
|
||||
{
|
||||
int err;
|
||||
cfdata_t cf;
|
||||
|
||||
err = config_cfattach_attach(iscsi_cd.cd_name, &iscsi_ca);
|
||||
if (err) {
|
||||
aprint_error("%s: couldn't register cfattach: %d\n",
|
||||
iscsi_cd.cd_name, err);
|
||||
config_cfdriver_detach(&iscsi_cd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (n > 1)
|
||||
aprint_error("%s: only one device supported\n",
|
||||
iscsi_cd.cd_name);
|
||||
|
||||
cf = kmem_alloc(sizeof(struct cfdata), KM_NOSLEEP);
|
||||
if (cf == NULL) {
|
||||
aprint_error("%s: couldn't allocate cfdata\n",
|
||||
iscsi_cd.cd_name);
|
||||
return;
|
||||
}
|
||||
cf->cf_name = iscsi_cd.cd_name;
|
||||
cf->cf_atname = iscsi_cd.cd_name;
|
||||
cf->cf_unit = 0;
|
||||
cf->cf_fstate = FSTATE_NOTFOUND;
|
||||
|
||||
(void)config_attach_pseudo(cf);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* iscsi_attach:
|
||||
* One-time inits go here. Not much for now, probably even less later.
|
||||
*/
|
||||
void
|
||||
iscsi_attach(device_t parent, device_t self, void *aux)
|
||||
{
|
||||
|
||||
DEBOUT(("ISCSI: iscsi_attach, parent=%p, self=%p, aux=%p\n", parent,
|
||||
self, aux));
|
||||
sc = (iscsi_softc_t *) device_private(self);
|
||||
sc->sc_dev = self;
|
||||
if (kthread_create(PRI_NONE, 0, NULL, iscsi_cleanup_thread,
|
||||
NULL, &cleanproc, "Cleanup") != 0) {
|
||||
panic("Can't create cleanup thread!");
|
||||
}
|
||||
aprint_normal("%s: attached. major = %d\n", iscsi_cd.cd_name,
|
||||
cdevsw_lookup_major(&iscsi_cdevsw));
|
||||
}
|
||||
|
||||
/*
|
||||
* iscsi_detach:
|
||||
* Cleanup.
|
||||
*/
|
||||
int
|
||||
iscsi_detach(device_t self, int flags)
|
||||
{
|
||||
|
||||
DEBOUT(("ISCSI: detach\n"));
|
||||
kill_all_sessions();
|
||||
detaching = TRUE;
|
||||
while (cleanproc != NULL) {
|
||||
wakeup(&cleanup_list);
|
||||
tsleep(&cleanup_list, PWAIT, "detach_wait", 20);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef struct quirktab_t {
|
||||
const char *tgt;
|
||||
size_t tgtlen;
|
||||
const char *iqn;
|
||||
size_t iqnlen;
|
||||
uint32_t quirks;
|
||||
} quirktab_t;
|
||||
|
||||
static const quirktab_t quirktab[] = {
|
||||
{ "StarWind", 8,
|
||||
"iqn.2008-08.com.starwindsoftware", 32,
|
||||
PQUIRK_ONLYBIG },
|
||||
{ "UNH", 3,
|
||||
"iqn.2002-10.edu.unh.", 20,
|
||||
PQUIRK_NOBIGMODESENSE |
|
||||
PQUIRK_NOMODESENSE |
|
||||
PQUIRK_NOSYNCCACHE },
|
||||
{ "NetBSD", 6,
|
||||
"iqn.1994-04.org.netbsd.", 23,
|
||||
0 },
|
||||
{ "Unknown", 7,
|
||||
"unknown", 7,
|
||||
0 },
|
||||
{ NULL, 0, NULL, 0, 0 }
|
||||
};
|
||||
|
||||
/* loop through the quirktab looking for a match on target name */
|
||||
static const quirktab_t *
|
||||
getquirks(const char *iqn)
|
||||
{
|
||||
const quirktab_t *qp;
|
||||
|
||||
if (iqn == NULL) {
|
||||
iqn = "unknown";
|
||||
}
|
||||
for (qp = quirktab ; qp->iqn ; qp++) {
|
||||
if (strncmp(qp->iqn, iqn, qp->iqnlen) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return qp;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/*
|
||||
* map_session
|
||||
* This (indirectly) maps the existing LUNs for a target to SCSI devices
|
||||
* by going through config_found to tell any child drivers that there's
|
||||
* a new adapter.
|
||||
* Note that each session is equivalent to a SCSI adapter.
|
||||
*
|
||||
* Parameter: the session pointer
|
||||
*
|
||||
* Returns: 1 on success, 0 on failure
|
||||
*
|
||||
* ToDo: Figuring out how to handle more than one LUN. It appears that
|
||||
* the NetBSD SCSI LUN discovery doesn't use "report LUNs", and instead
|
||||
* goes through the LUNs sequentially, stopping somewhere on the way if it
|
||||
* gets an error. We may have to do some LUN mapping in here if this is
|
||||
* really how things work.
|
||||
*/
|
||||
|
||||
int
|
||||
map_session(session_t *session)
|
||||
{
|
||||
struct scsipi_adapter *adapt = &session->sc_adapter;
|
||||
struct scsipi_channel *chan = &session->sc_channel;
|
||||
const quirktab_t *tgt;
|
||||
|
||||
if (sc == NULL) {
|
||||
/* we haven't gone through the config process */
|
||||
/* (shouldn't happen) */
|
||||
DEBOUT(("Map: No device pointer!\n"));
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Fill in the scsipi_adapter.
|
||||
*/
|
||||
adapt->adapt_dev = sc->sc_dev;
|
||||
adapt->adapt_nchannels = 1;
|
||||
adapt->adapt_request = iscsi_scsipi_request;
|
||||
adapt->adapt_minphys = iscsi_minphys;
|
||||
adapt->adapt_openings = CCBS_PER_SESSION;
|
||||
adapt->adapt_max_periph = CCBS_PER_SESSION;
|
||||
|
||||
/*
|
||||
* Fill in the scsipi_channel.
|
||||
*/
|
||||
if ((tgt = getquirks(chan->chan_name)) == NULL) {
|
||||
tgt = getquirks("unknown");
|
||||
}
|
||||
chan->chan_name = tgt->tgt;
|
||||
chan->chan_defquirks = tgt->quirks;
|
||||
chan->chan_adapter = adapt;
|
||||
chan->chan_bustype = &scsi_bustype;
|
||||
chan->chan_channel = 0;
|
||||
chan->chan_flags = SCSIPI_CHAN_NOSETTLE;
|
||||
chan->chan_ntargets = 1;
|
||||
chan->chan_nluns = 16; /* ToDo: ??? */
|
||||
chan->chan_id = session->id;
|
||||
|
||||
session->child_dev = config_found(sc->sc_dev, chan, scsiprint);
|
||||
|
||||
return session->child_dev != NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* unmap_session
|
||||
* This (indirectly) unmaps the existing all LUNs for a target by
|
||||
* telling the config system that the adapter has detached.
|
||||
*
|
||||
* Parameter: the session pointer
|
||||
*/
|
||||
|
||||
void
|
||||
unmap_session(session_t *session)
|
||||
{
|
||||
device_t dev;
|
||||
|
||||
if ((dev = session->child_dev) != NULL) {
|
||||
session->child_dev = NULL;
|
||||
config_detach(dev, DETACH_FORCE);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* SCSI interface routines
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* iscsi_scsipi_request:
|
||||
* Perform a request for the SCSIPI layer.
|
||||
*/
|
||||
|
||||
void
|
||||
iscsi_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req,
|
||||
void *arg)
|
||||
{
|
||||
struct scsipi_adapter *adapt = chan->chan_adapter;
|
||||
struct scsipi_xfer *xs;
|
||||
session_t *session;
|
||||
int flags;
|
||||
|
||||
session = (session_t *) adapt; /* adapter is first field in session */
|
||||
|
||||
switch (req) {
|
||||
case ADAPTER_REQ_RUN_XFER:
|
||||
DEB(9, ("ISCSI: scsipi_request RUN_XFER\n"));
|
||||
xs = arg;
|
||||
flags = xs->xs_control;
|
||||
|
||||
if ((flags & XS_CTL_POLL) != 0) {
|
||||
xs->error = XS_DRIVER_STUFFUP;
|
||||
DEBOUT(("Run Xfer request with polling\n"));
|
||||
scsipi_done(xs);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* NOTE: It appears that XS_CTL_DATA_UIO is not actually used anywhere.
|
||||
* Since it really would complicate matters to handle offsets
|
||||
* into scatter-gather lists, and a number of other drivers don't
|
||||
* handle uio-based data as well, XS_CTL_DATA_UIO isn't
|
||||
* implemented in this driver (at least for now).
|
||||
*/
|
||||
if (flags & XS_CTL_DATA_UIO) {
|
||||
xs->error = XS_DRIVER_STUFFUP;
|
||||
DEBOUT(("Run Xfer with data in UIO\n"));
|
||||
scsipi_done(xs);
|
||||
return;
|
||||
}
|
||||
|
||||
send_run_xfer(session, xs);
|
||||
DEB(9, ("scsipi_req returns\n"));
|
||||
return;
|
||||
|
||||
case ADAPTER_REQ_GROW_RESOURCES:
|
||||
DEBOUT(("ISCSI: scsipi_request GROW_RESOURCES\n"));
|
||||
return;
|
||||
|
||||
case ADAPTER_REQ_SET_XFER_MODE:
|
||||
DEB(5, ("ISCSI: scsipi_request SET_XFER_MODE\n"));
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
DEBOUT(("ISCSI: scsipi_request with invalid REQ code %d\n", req));
|
||||
}
|
||||
|
||||
/* cap the transfer at 64K */
|
||||
#define ISCSI_MAX_XFER 65536
|
||||
|
||||
/*
|
||||
* iscsi_minphys:
|
||||
* Limit a transfer to our maximum transfer size.
|
||||
*/
|
||||
|
||||
void
|
||||
iscsi_minphys(struct buf *bp)
|
||||
{
|
||||
if (bp->b_bcount > ISCSI_MAX_XFER) {
|
||||
bp->b_bcount = ISCSI_MAX_XFER;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* SCSI job execution helper routines
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* iscsi_done:
|
||||
*
|
||||
* A CCB has completed execution. Pass the status back to the
|
||||
* upper layer.
|
||||
*/
|
||||
void
|
||||
iscsi_done(ccb_t *ccb)
|
||||
{
|
||||
struct scsipi_xfer *xs = ccb->xs;
|
||||
/*DEBOUT (("iscsi_done\n")); */
|
||||
|
||||
if (xs != NULL) {
|
||||
xs->resid = ccb->residual;
|
||||
|
||||
switch (ccb->status) {
|
||||
case ISCSI_STATUS_SUCCESS:
|
||||
xs->error = 0;
|
||||
break;
|
||||
|
||||
case ISCSI_STATUS_CHECK_CONDITION:
|
||||
xs->error = XS_SENSE;
|
||||
xs->error = XS_SENSE;
|
||||
#ifdef ISCSI_DEBUG
|
||||
{
|
||||
uint8_t *s = (uint8_t *) (&xs->sense);
|
||||
DEB(5, ("Scsipi_done, error=XS_SENSE, sense data=%02x "
|
||||
"%02x %02x %02x...\n",
|
||||
s[0], s[1], s[2], s[3]));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case ISCSI_STATUS_TARGET_BUSY:
|
||||
xs->error = XS_BUSY;
|
||||
break;
|
||||
|
||||
case ISCSI_STATUS_SOCKET_ERROR:
|
||||
case ISCSI_STATUS_TIMEOUT:
|
||||
xs->error = XS_SELTIMEOUT;
|
||||
break;
|
||||
|
||||
default:
|
||||
xs->error = XS_DRIVER_STUFFUP;
|
||||
break;
|
||||
}
|
||||
|
||||
DEB(99, ("Calling scsipi_done (%p), err = %d\n", xs, xs->error));
|
||||
scsipi_done(xs);
|
||||
DEB(99, ("scsipi_done returned\n"));
|
||||
}
|
||||
|
||||
free_ccb(ccb);
|
||||
}
|
||||
|
||||
/* Kernel Module support */
|
||||
#ifdef _MODULE
|
||||
|
||||
#include <sys/module.h>
|
||||
|
||||
MODULE(MODULE_CLASS_DRIVER, iscsi, NULL);
|
||||
static const struct cfiattrdata ibescsi_info = { "scsi", 1,
|
||||
{{"channel", "-1", -1},}
|
||||
};
|
||||
static const struct cfiattrdata *const iscsi_attrs[] = { &ibescsi_info, NULL };
|
||||
|
||||
CFDRIVER_DECL(iscsi, DV_DULL, iscsi_attrs);
|
||||
|
||||
static struct cfdata iscsi_cfdata[] = {
|
||||
{
|
||||
.cf_name = "iscsi",
|
||||
.cf_atname = "iscsi",
|
||||
.cf_unit = 0, /* Only unit 0 is ever used */
|
||||
.cf_fstate = FSTATE_NOTFOUND,
|
||||
.cf_loc = NULL,
|
||||
.cf_flags = 0,
|
||||
.cf_pspec = NULL,
|
||||
},
|
||||
{ NULL, NULL, 0, 0, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
static int
|
||||
iscsi_modcmd(modcmd_t cmd, void *arg)
|
||||
{
|
||||
devmajor_t cmajor = NODEVMAJOR, bmajor = NODEVMAJOR;
|
||||
int error;
|
||||
|
||||
switch (cmd) {
|
||||
case MODULE_CMD_INIT:
|
||||
error = config_cfdriver_attach(&iscsi_cd);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error = config_cfattach_attach(iscsi_cd.cd_name, &iscsi_ca);
|
||||
if (error) {
|
||||
config_cfdriver_detach(&iscsi_cd);
|
||||
aprint_error("%s: unable to register cfattach\n",
|
||||
iscsi_cd.cd_name);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = config_cfdata_attach(iscsi_cfdata, 1);
|
||||
if (error) {
|
||||
aprint_error("%s: unable to attach cfdata\n",
|
||||
iscsi_cd.cd_name);
|
||||
config_cfattach_detach(iscsi_cd.cd_name, &iscsi_ca);
|
||||
config_cfdriver_detach(&iscsi_cd);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = devsw_attach(iscsi_cd.cd_name, NULL, &bmajor,
|
||||
&iscsi_cdevsw, &cmajor);
|
||||
if (error) {
|
||||
aprint_error("%s: unable to register devsw\n",
|
||||
iscsi_cd.cd_name);
|
||||
config_cfdata_detach(iscsi_cfdata);
|
||||
config_cfattach_detach(iscsi_cd.cd_name, &iscsi_ca);
|
||||
config_cfdriver_detach(&iscsi_cd);
|
||||
return error;
|
||||
}
|
||||
|
||||
if (config_attach_pseudo(iscsi_cfdata) == NULL) {
|
||||
aprint_error("%s: config_attach_pseudo failed\n",
|
||||
iscsi_cd.cd_name);
|
||||
config_cfattach_detach(iscsi_cd.cd_name, &iscsi_ca);
|
||||
config_cfdriver_detach(&iscsi_cd);
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case MODULE_CMD_FINI:
|
||||
error = config_cfdata_detach(iscsi_cfdata);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
config_cfattach_detach(iscsi_cd.cd_name, &iscsi_ca);
|
||||
config_cfdriver_detach(&iscsi_cd);
|
||||
devsw_detach(NULL, &iscsi_cdevsw);
|
||||
|
||||
return 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
return ENOTTY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* _MODULE */
|
|
@ -0,0 +1,442 @@
|
|||
/* $NetBSD: iscsi_pdu.h,v 1.1 2011/10/23 21:15:02 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Wasabi Systems, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _ISCSI_PDU_H
|
||||
#define _ISCSI_PDU_H
|
||||
|
||||
#define BHS_SIZE 48 /* Basic Header Segment (without digest) */
|
||||
#define PDU_HEADER_SIZE 52 /* PDU Header with Digest */
|
||||
|
||||
#define OP_IMMEDIATE 0x40 /* Bit 1 in Opcode field: immediate delivery */
|
||||
#define OPCODE_MASK 0x3f /* Mask for opcode */
|
||||
|
||||
/* PDU Flags field */
|
||||
|
||||
#define FLAG_FINAL 0x80 /* Bit 0: Final PDU in sequence */
|
||||
#define FLAG_TRANSIT 0x80 /* Bit 0: Transit to next login phase */
|
||||
#define FLAG_CONTINUE 0x40 /* Bit 1: Continue PDU */
|
||||
#define FLAG_ACK 0x40 /* Bit 1: Acknowledge */
|
||||
#define FLAG_READ 0x40 /* Bit 1: Read Data */
|
||||
#define FLAG_WRITE 0x20 /* Bit 2: Write Data */
|
||||
#define FLAG_BIDI_OFLO 0x10 /* Bit 3: Bidirectional Read Residual Oflow */
|
||||
#define FLAG_BIDI_UFLOW 0x08 /* Bit 4: Bidirectional Read Residual Uflow */
|
||||
#define FLAG_OVERFLOW 0x04 /* Bit 5: Residual Overflow */
|
||||
#define FLAG_UNDERFLOW 0x02 /* Bit 6: Residual Underflow */
|
||||
#define FLAG_STATUS 0x01 /* Bit 7: Command Status is valid */
|
||||
|
||||
/* CSG/NSG flag field codes */
|
||||
|
||||
#define SG_SECURITY_NEGOTIATION 0
|
||||
#define SG_LOGIN_OPERATIONAL_NEGOTIATION 1
|
||||
#define SG_FULL_FEATURE_PHASE 3
|
||||
|
||||
#define CSG_SHIFT 2 /* shift factor for CSG field */
|
||||
#define SG_MASK 3 /* mask for CSG (after shift) and NSG */
|
||||
|
||||
#define NEXT_PHASE(ph) ((!ph) ? 1 : 3) /* no phase 2 */
|
||||
|
||||
/* Task Management Function Codes (in Flags byte) */
|
||||
|
||||
#define ABORT_TASK 1
|
||||
#define ABORT_TASK_SET 2
|
||||
#define CLEAR_ACA 3
|
||||
#define CLEAR_TASK_SET 4
|
||||
#define LOGICAL_UNIT_RESET 5
|
||||
#define TARGET_WARM_RESET 6
|
||||
#define TARGET_COLD_RESET 7
|
||||
#define TASK_REASSIGN 8
|
||||
|
||||
/* ISID T-Field (first byte) */
|
||||
|
||||
#define T_FORMAT_OUI 0x00
|
||||
#define T_FORMAT_EN 0x40
|
||||
#define T_FORMAT_RANDOM 0x80
|
||||
|
||||
|
||||
/* Task Attributes */
|
||||
|
||||
#define ATTR_UNTAGGED 0
|
||||
#define ATTR_SIMPLE 1
|
||||
#define ATTR_ORDERED 2
|
||||
#define ATTR_HEAD_OF_QUEUE 3
|
||||
#define ATTR_ACA 4
|
||||
|
||||
/* Initiator Opcodes */
|
||||
|
||||
#define IOP_NOP_Out 0x00
|
||||
#define IOP_SCSI_Command 0x01
|
||||
#define IOP_SCSI_Task_Management 0x02
|
||||
#define IOP_Login_Request 0x03
|
||||
#define IOP_Text_Request 0x04
|
||||
#define IOP_SCSI_Data_out 0x05
|
||||
#define IOP_Logout_Request 0x06
|
||||
#define IOP_SNACK_Request 0x10
|
||||
|
||||
/* Target Opcodes */
|
||||
|
||||
#define TOP_NOP_In 0x20
|
||||
#define TOP_SCSI_Response 0x21
|
||||
#define TOP_SCSI_Task_Management 0x22
|
||||
#define TOP_Login_Response 0x23
|
||||
#define TOP_Text_Response 0x24
|
||||
#define TOP_SCSI_Data_in 0x25
|
||||
#define TOP_Logout_Response 0x26
|
||||
#define TOP_R2T 0x31
|
||||
#define TOP_Asynchronous_Message 0x32
|
||||
#define TOP_Reject 0x3f
|
||||
|
||||
/*
|
||||
* The Opcode-dependent fields of the BHS, defined per PDU
|
||||
*/
|
||||
|
||||
/* Command + Response */
|
||||
|
||||
struct scsi_command_pdu_s
|
||||
{
|
||||
uint32_t ExpectedDataTransferLength;
|
||||
uint32_t CmdSN;
|
||||
uint32_t ExpStatSN;
|
||||
uint8_t SCSI_CDB[16];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct scsi_command_pdu_s scsi_command_pdu_t;
|
||||
|
||||
struct scsi_response_pdu_s
|
||||
{
|
||||
uint32_t SNACKTag;
|
||||
uint32_t StatSN;
|
||||
uint32_t ExpCmdSN;
|
||||
uint32_t MaxCmdSN;
|
||||
uint32_t ExpStatSN;
|
||||
uint32_t ReadResidualCount;
|
||||
uint32_t ResidualCount;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct scsi_response_pdu_s scsi_response_pdu_t;
|
||||
|
||||
|
||||
/* Task Management */
|
||||
|
||||
struct task_management_req_pdu_s
|
||||
{
|
||||
uint32_t ReferencedTaskTag;
|
||||
uint32_t CmdSN;
|
||||
uint32_t ExpStatSN;
|
||||
uint32_t RefCmdSN;
|
||||
uint32_t ExpDataSN;
|
||||
uint8_t reserved[8];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct task_management_req_pdu_s task_management_req_pdu_t;
|
||||
|
||||
|
||||
struct task_management_rsp_pdu_s
|
||||
{
|
||||
uint32_t reserved1;
|
||||
uint32_t StatSN;
|
||||
uint32_t ExpCmdSN;
|
||||
uint32_t MaxCmdSN;
|
||||
uint8_t reserved2[12];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct task_management_rsp_pdu_s task_management_rsp_pdu_t;
|
||||
|
||||
|
||||
/* Data Out & In, R2T */
|
||||
|
||||
struct data_out_pdu_s
|
||||
{
|
||||
uint32_t TargetTransferTag;
|
||||
uint32_t reserved1;
|
||||
uint32_t ExpStatSN;
|
||||
uint32_t reserved2;
|
||||
uint32_t DataSN;
|
||||
uint32_t BufferOffset;
|
||||
uint32_t reserved3;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct data_out_pdu_s data_out_pdu_t;
|
||||
|
||||
|
||||
struct data_in_pdu_s
|
||||
{
|
||||
uint32_t TargetTransferTag;
|
||||
uint32_t StatSN;
|
||||
uint32_t ExpCmdSN;
|
||||
uint32_t MaxCmdSN;
|
||||
uint32_t DataSN;
|
||||
uint32_t BufferOffset;
|
||||
uint32_t ResidualCount;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct data_in_pdu_s data_in_pdu_t;
|
||||
|
||||
|
||||
struct r2t_pdu_s
|
||||
{
|
||||
uint32_t TargetTransferTag;
|
||||
uint32_t StatSN;
|
||||
uint32_t ExpCmdSN;
|
||||
uint32_t MaxCmdSN;
|
||||
uint32_t R2TSN;
|
||||
uint32_t BufferOffset;
|
||||
uint32_t DesiredDataTransferLength;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct r2t_pdu_s r2t_pdu_t;
|
||||
|
||||
|
||||
/* Asynch message */
|
||||
|
||||
struct asynch_pdu_s
|
||||
{
|
||||
uint32_t reserved1;
|
||||
uint32_t StatSN;
|
||||
uint32_t ExpCmdSN;
|
||||
uint32_t MaxCmdSN;
|
||||
uint8_t AsyncEvent;
|
||||
uint8_t AsyncVCode;
|
||||
uint16_t Parameter1;
|
||||
uint16_t Parameter2;
|
||||
uint16_t Parameter3;
|
||||
uint32_t reserved2;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct asynch_pdu_s asynch_pdu_t;
|
||||
|
||||
|
||||
/* Text request / response */
|
||||
|
||||
struct text_req_pdu_s
|
||||
{
|
||||
uint32_t TargetTransferTag;
|
||||
uint32_t CmdSN;
|
||||
uint32_t ExpStatSN;
|
||||
uint8_t reserved[16];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct text_req_pdu_s text_req_pdu_t;
|
||||
|
||||
|
||||
struct text_rsp_pdu_s
|
||||
{
|
||||
uint32_t TargetTransferTag;
|
||||
uint32_t StatSN;
|
||||
uint32_t ExpCmdSN;
|
||||
uint32_t MaxCmdSN;
|
||||
uint8_t reserved[12];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct text_rsp_pdu_s text_rsp_pdu_t;
|
||||
|
||||
|
||||
/* Login request / response */
|
||||
|
||||
struct login_req_pdu_s
|
||||
{
|
||||
uint16_t CID;
|
||||
uint16_t reserved1;
|
||||
uint32_t CmdSN;
|
||||
uint32_t ExpStatSN;
|
||||
uint8_t reserved2[16];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct login_req_pdu_s login_req_pdu_t;
|
||||
|
||||
/* Overlays LUN field in login request and response */
|
||||
struct login_isid_s
|
||||
{
|
||||
uint8_t ISID_A;
|
||||
uint16_t ISID_B;
|
||||
uint8_t ISID_C;
|
||||
uint16_t ISID_D;
|
||||
uint16_t TSIH;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct login_isid_s login_isid_t;
|
||||
|
||||
struct login_rsp_pdu_s
|
||||
{
|
||||
uint32_t reserved1;
|
||||
uint32_t StatSN;
|
||||
uint32_t ExpCmdSN;
|
||||
uint32_t MaxCmdSN;
|
||||
uint8_t StatusClass;
|
||||
uint8_t StatusDetail;
|
||||
uint8_t reserved2[10];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct login_rsp_pdu_s login_rsp_pdu_t;
|
||||
|
||||
|
||||
/* Logout request / response */
|
||||
|
||||
struct logout_req_pdu_s
|
||||
{
|
||||
uint16_t CID;
|
||||
uint16_t reserved2;
|
||||
uint32_t CmdSN;
|
||||
uint32_t ExpStatSN;
|
||||
uint8_t reserved3[16];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct logout_req_pdu_s logout_req_pdu_t;
|
||||
|
||||
|
||||
struct logout_rsp_pdu_s
|
||||
{
|
||||
uint32_t reserved2;
|
||||
uint32_t StatSN;
|
||||
uint32_t ExpCmdSN;
|
||||
uint32_t MaxCmdSN;
|
||||
uint32_t reserved3;
|
||||
uint16_t Time2Wait;
|
||||
uint16_t Time2Retain;
|
||||
uint32_t reserved4;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct logout_rsp_pdu_s logout_rsp_pdu_t;
|
||||
|
||||
|
||||
/* SNACK request */
|
||||
|
||||
/* SNACK Types (in Flags field) */
|
||||
|
||||
#define SNACK_DATA_NAK 0
|
||||
#define SNACK_STATUS_NAK 1
|
||||
#define SNACK_DATA_ACK 2
|
||||
#define SNACK_RDATA_NAK 3
|
||||
|
||||
struct snack_req_pdu_s
|
||||
{
|
||||
uint32_t TargetTransferTag;
|
||||
uint32_t reserved1;
|
||||
uint32_t ExpStatSN;
|
||||
uint8_t reserved2[8];
|
||||
uint32_t BegRun;
|
||||
uint32_t RunLength;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct snack_req_pdu_s snack_req_pdu_t;
|
||||
|
||||
|
||||
/* Reject */
|
||||
|
||||
#define REJECT_DIGEST_ERROR 2
|
||||
#define REJECT_SNACK 3
|
||||
#define REJECT_PROTOCOL_ERROR 4
|
||||
#define REJECT_CMD_NOT_SUPPORTED 5
|
||||
#define REJECT_IMMED_COMMAND 6
|
||||
#define REJECT_TASK_IN_PROGRESS 7
|
||||
#define REJECT_INVALID_DATA_ACK 8
|
||||
#define REJECT_INVALID_PDU_FIELD 9
|
||||
#define REJECT_LONG_OPERATION 10
|
||||
#define REJECT_NEGOTIATION_RESET 11
|
||||
#define REJECT_WAITING_FOR_LOGOUT 12
|
||||
|
||||
|
||||
struct reject_pdu_s
|
||||
{
|
||||
uint32_t reserved2;
|
||||
uint32_t StatSN;
|
||||
uint32_t ExpCmdSN;
|
||||
uint32_t MaxCmdSN;
|
||||
uint8_t DataSN;
|
||||
uint8_t reserved[8];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct reject_pdu_s reject_pdu_t;
|
||||
|
||||
|
||||
/* NOP Out & In */
|
||||
|
||||
struct nop_out_pdu_s
|
||||
{
|
||||
uint32_t TargetTransferTag;
|
||||
uint32_t CmdSN;
|
||||
uint32_t ExpStatSN;
|
||||
uint8_t reserved[16];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct nop_out_pdu_s nop_out_pdu_t;
|
||||
|
||||
|
||||
struct nop_in_pdu_s
|
||||
{
|
||||
uint32_t TargetTransferTag;
|
||||
uint32_t StatSN;
|
||||
uint32_t ExpCmdSN;
|
||||
uint32_t MaxCmdSN;
|
||||
uint8_t reserved3[12];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct nop_in_pdu_s nop_in_pdu_t;
|
||||
|
||||
|
||||
/*
|
||||
* The complete PDU Header.
|
||||
*/
|
||||
|
||||
struct pdu_header_s
|
||||
{
|
||||
uint8_t Opcode;
|
||||
uint8_t Flags;
|
||||
uint8_t OpcodeSpecific[2];
|
||||
uint8_t TotalAHSLength;
|
||||
uint8_t DataSegmentLength[3];
|
||||
uint64_t LUN;
|
||||
uint32_t InitiatorTaskTag;
|
||||
union
|
||||
{
|
||||
scsi_command_pdu_t command;
|
||||
scsi_response_pdu_t response;
|
||||
task_management_req_pdu_t task_req;
|
||||
task_management_rsp_pdu_t task_rsp;
|
||||
data_out_pdu_t data_out;
|
||||
data_in_pdu_t data_in;
|
||||
r2t_pdu_t r2t;
|
||||
asynch_pdu_t asynch;
|
||||
text_req_pdu_t text_req;
|
||||
text_rsp_pdu_t text_rsp;
|
||||
login_req_pdu_t login_req;
|
||||
login_rsp_pdu_t login_rsp;
|
||||
logout_req_pdu_t logout_req;
|
||||
logout_rsp_pdu_t logout_rsp;
|
||||
snack_req_pdu_t snack;
|
||||
reject_pdu_t reject;
|
||||
nop_out_pdu_t nop_out;
|
||||
nop_in_pdu_t nop_in;
|
||||
} p;
|
||||
uint32_t HeaderDigest;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef struct pdu_header_s pdu_header_t;
|
||||
|
||||
#endif /* !_ISCSI_PDU_H */
|
|
@ -0,0 +1,116 @@
|
|||
/* $NetBSD: iscsi_perf.h,v 1.1 2011/10/23 21:15:02 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Wasabi Systems, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PERF_BEGIN_COMMAND, /* start of command */
|
||||
PERF_END_COMMAND, /* end of command */
|
||||
PERF_BEGIN_PDUWRITECMD, /* start of write of command PDU */
|
||||
PERF_END_PDUWRITECMD, /* end of write of command PDU */
|
||||
PERF_BEGIN_PDUWRITEDATA, /* start of first data PDU write (write only) */
|
||||
PERF_END_PDUWRITEDATA, /* end of last data PDU write */
|
||||
PERF_BEGIN_PDURCVDATA, /* start of first data PDU receive (read only) */
|
||||
PERF_END_PDURCVDATA, /* end of last data PDU receive */
|
||||
PERF_PDURCVSTS, /* receive of status PDU */
|
||||
PERF_NUM_PERFPOINTS
|
||||
} perfpoint_t;
|
||||
|
||||
|
||||
#define PERF_FLG_READ 0x10000000 /* this is a read command */
|
||||
#define PERF_FLG_NOWAIT 0x20000000 /* this command was non-waiting */
|
||||
#define PERF_FLG_COMPLETE 0x80000000 /* command completed */
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint64_t pctr[PERF_NUM_PERFPOINTS];
|
||||
uint32_t datalen; /* data transfer size */
|
||||
uint32_t status; /* Result of command (lower 16 bits) + flags */
|
||||
} command_perf_t;
|
||||
|
||||
|
||||
/*
|
||||
Perfdata_Start:
|
||||
Allocates data buffer in driver with given number of command_perf
|
||||
elements. If a buffer of larger or equal size already exists, it is
|
||||
not reallocated.
|
||||
Resets indices and clears the buffer.
|
||||
|
||||
Perfdata_Stop:
|
||||
Stops data collection, waits (up to 5 seconds) for completion.
|
||||
Returns the number of data points collected.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int num_elements; /* start: IN number of elements to allocate */
|
||||
/* stop: OUT number of elements used */
|
||||
uint32_t status; /* out: status */
|
||||
} iscsi_perf_startstop_parameters_t;
|
||||
|
||||
|
||||
#define ISCSI_PERFDATA_START _IOWR (0, 90, iscsi_perf_startstop_parameters_t)
|
||||
#define ISCSI_PERFDATA_STOP _IOWR (0, 91, iscsi_perf_startstop_parameters_t)
|
||||
|
||||
|
||||
/*
|
||||
Perfdata_Get:
|
||||
Retrieves the current data. Note that this may be called while data
|
||||
collection is still active, it does not automatically stop collection.
|
||||
It will not reset collection or release any buffers.
|
||||
|
||||
To determine the required buffer size, call with buffersize set to zero.
|
||||
In that case, no data is transferred, the buffersize field is set to the
|
||||
required size in bytes, and num_elements is set to the corresponding
|
||||
number of data points.
|
||||
|
||||
If buffersize is nonzero, the number of data points that will fit into
|
||||
the buffer, or the number of data points collected so far, will be
|
||||
copied into the buffer, whichever is smallest. num_elements is set to
|
||||
the number of elements copied.
|
||||
|
||||
ticks_per_100ms is the approximate conversion base to convert the CPU
|
||||
cycle counter values collected into time units. This value is determined
|
||||
by measuring the cycles for a delay(100) five times and taking the
|
||||
average.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *buffer; /* in: buffer pointer */
|
||||
uint32_t buffersize; /* in: size of buffer in bytes (0 to query size) */
|
||||
uint32_t status; /* out: status */
|
||||
int num_elements; /* out: number of elements written */
|
||||
uint64_t ticks_per_100us; /* out: ticks per 100 usec */
|
||||
} iscsi_perf_get_parameters_t;
|
||||
|
||||
|
||||
#define ISCSI_PERFDATA_GET _IOWR (0, 92, iscsi_perf_get_parameters_t)
|
|
@ -0,0 +1,251 @@
|
|||
/* $NetBSD: iscsi_profile.c,v 1.1 2011/10/23 21:15:02 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Wasabi Systems, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "iscsi_globals.h"
|
||||
|
||||
#ifdef ISCSI_PERFTEST
|
||||
|
||||
command_perf_t *perfdata = NULL;
|
||||
int perf_active = 0;
|
||||
|
||||
static int perfcount = 0;
|
||||
static int perfindex = 0;
|
||||
static uint64_t ticks_per_100us = 0;
|
||||
|
||||
/*
|
||||
* perf_begin_command:
|
||||
* Start command profiling.
|
||||
* Allocates space for a command entry, sets the data length and
|
||||
* flags, and gets the begin cycle count.
|
||||
* If no room is left in the data buffer, nothing is set.
|
||||
*
|
||||
* Note: The perf_index set in the CCB is the index + 1, so that 0 is
|
||||
* reserved as profiling not active (this is the default state
|
||||
* for CCB fields).
|
||||
*
|
||||
* This function must only be called if perf_active is nonzero.
|
||||
* The wrapper macro checks for this condition.
|
||||
*
|
||||
* Parameter:
|
||||
* ccb The associated CCB.
|
||||
* nowait Nonzero if this is a no-wait command.
|
||||
*/
|
||||
|
||||
void
|
||||
perf_begin_command(ccb_t *ccb, int nowait)
|
||||
{
|
||||
int idx;
|
||||
|
||||
/* Only trace commands that actually transfer data so we don't skew results */
|
||||
if (ccb->data_len < 512) {
|
||||
return;
|
||||
}
|
||||
idx = perfindex++;
|
||||
if (idx >= perfcount) {
|
||||
--perfindex;
|
||||
return;
|
||||
}
|
||||
perfdata[idx].datalen = ccb->data_len;
|
||||
if (ccb->data_in) {
|
||||
perfdata[idx].status |= PERF_FLG_READ;
|
||||
}
|
||||
if (nowait) {
|
||||
perfdata[idx].status |= PERF_FLG_NOWAIT;
|
||||
}
|
||||
ccb->perf_index = ++idx;
|
||||
perf_snap(idx, PERF_BEGIN_COMMAND);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* perf_end_command:
|
||||
* Ends command profiling.
|
||||
* Gets the end cycle count, and sets the complete flag.
|
||||
*
|
||||
* Parameter:
|
||||
* ccb The associated CCB.
|
||||
*/
|
||||
|
||||
void
|
||||
perf_end_command(ccb_t *ccb)
|
||||
{
|
||||
int idx = ccb->perf_index;
|
||||
|
||||
perf_snap(idx, PERF_END_COMMAND);
|
||||
perfdata[idx - 1].status |=
|
||||
(ccb->status & 0xffffff) | PERF_FLG_COMPLETE;
|
||||
ccb->perf_index = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* perf_do_stop:
|
||||
* Stops performance data collection (internal function).
|
||||
* Clears perf_active, and waits until all commands have completed.
|
||||
* The wait is limited to 5 seconds.
|
||||
*/
|
||||
|
||||
STATIC void
|
||||
perf_do_stop(void)
|
||||
{
|
||||
int i, n = 0;
|
||||
|
||||
perf_active = 0;
|
||||
do {
|
||||
for (i = 0; i < perfindex; i++) {
|
||||
if (!(perfdata[i].status & PERF_FLG_COMPLETE)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < perfindex) {
|
||||
tsleep(&perfindex, PWAIT, "wait_perf", 1 * hz);
|
||||
}
|
||||
} while (n++ < 10 && i < perfindex);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* perf_start:
|
||||
* Starts performance data collection.
|
||||
* If collection is already running, it is stopped.
|
||||
* Allocates a buffer if necessary, clears the buffer, resets indices.
|
||||
* Measures tick timing.
|
||||
*
|
||||
* Parameter:
|
||||
* par The ioctl parameter specifying the number of elements.
|
||||
*/
|
||||
|
||||
void
|
||||
perf_start(iscsi_perf_startstop_parameters_t *par)
|
||||
{
|
||||
uint64_t rv, rv1, rv2;
|
||||
int i, s;
|
||||
|
||||
if (par->num_elements <= 0) {
|
||||
par->status = ISCSI_STATUS_PARAMETER_INVALID;
|
||||
return;
|
||||
}
|
||||
if (perf_active)
|
||||
perf_do_stop();
|
||||
|
||||
if (perfdata == NULL || perfcount < par->num_elements) {
|
||||
if (perfdata != NULL) {
|
||||
free(perfdata, M_DEVBUF);
|
||||
}
|
||||
perfdata = malloc(par->num_elements * sizeof(*perfdata),
|
||||
M_DEVBUF, M_WAITOK);
|
||||
if (perfdata == NULL) {
|
||||
perfcount = 0;
|
||||
par->status = ISCSI_STATUS_NO_RESOURCES;
|
||||
return;
|
||||
}
|
||||
perfcount = par->num_elements;
|
||||
}
|
||||
|
||||
(void) memset(perfdata, 0x0, perfcount * sizeof(*perfdata));
|
||||
perfindex = 0;
|
||||
|
||||
rv = 0;
|
||||
for (i = 0; i < 5; i++) {
|
||||
s = splhigh();
|
||||
|
||||
__asm __volatile("rdtsc":"=A"(rv1));
|
||||
delay(100);
|
||||
__asm __volatile("rdtsc":"=A"(rv2));
|
||||
|
||||
splx(s);
|
||||
rv += rv2 - rv1;
|
||||
}
|
||||
|
||||
ticks_per_100us = rv / 5;
|
||||
par->status = ISCSI_STATUS_SUCCESS;
|
||||
|
||||
perf_active = 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* perf_start:
|
||||
* Stops performance data collection (external interface).
|
||||
*
|
||||
* Parameter:
|
||||
* par The ioctl parameter receiving the number of
|
||||
* elements collected.
|
||||
*/
|
||||
|
||||
void
|
||||
perf_stop(iscsi_perf_startstop_parameters_t *par)
|
||||
{
|
||||
if (perfdata == NULL || perfcount <= 0 || !perf_active) {
|
||||
par->status = ISCSI_STATUS_GENERAL_ERROR;
|
||||
return;
|
||||
}
|
||||
perf_do_stop();
|
||||
par->num_elements = perfindex;
|
||||
par->status = ISCSI_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* perf_get:
|
||||
* Retrieves performance data.
|
||||
*
|
||||
* Parameter:
|
||||
* par The ioctl parameter.
|
||||
*/
|
||||
|
||||
void
|
||||
perf_get(iscsi_perf_get_parameters_t *par)
|
||||
{
|
||||
int nelem;
|
||||
|
||||
if (perfdata == NULL || perfcount <= 0) {
|
||||
par->status = ISCSI_STATUS_GENERAL_ERROR;
|
||||
return;
|
||||
}
|
||||
par->status = ISCSI_STATUS_SUCCESS;
|
||||
|
||||
if (!par->buffersize) {
|
||||
par->buffersize = perfindex * sizeof(command_perf_t);
|
||||
par->num_elements = perfindex;
|
||||
return;
|
||||
}
|
||||
nelem = par->buffersize / sizeof(command_perf_t);
|
||||
if (!nelem) {
|
||||
par->status = ISCSI_STATUS_PARAMETER_INVALID;
|
||||
return;
|
||||
}
|
||||
nelem = min(nelem, perfindex);
|
||||
copyout(perfdata, par->buffer, nelem * sizeof(command_perf_t));
|
||||
par->num_elements = nelem;
|
||||
par->ticks_per_100us = ticks_per_100us;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,89 @@
|
|||
/* $NetBSD: iscsi_profile.h,v 1.1 2011/10/23 21:15:02 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Wasabi Systems, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifdef ISCSI_PERFTEST
|
||||
|
||||
command_perf_t *perfdata;
|
||||
int perf_active;
|
||||
|
||||
void perf_begin_command(ccb_t *, int);
|
||||
void perf_end_command(ccb_t *);
|
||||
void perf_start(iscsi_perf_startstop_parameters_t *);
|
||||
void perf_stop(iscsi_perf_startstop_parameters_t *);
|
||||
void perf_get(iscsi_perf_get_parameters_t *);
|
||||
|
||||
|
||||
static __inline void
|
||||
perf_snap(int index, perfpoint_t which)
|
||||
{
|
||||
uint64_t rv;
|
||||
|
||||
__asm __volatile("rdtsc":"=A"(rv));
|
||||
|
||||
perfdata[index - 1].pctr[which] = rv;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
perf_snapcond(int index, perfpoint_t which)
|
||||
{
|
||||
uint64_t *pdst = &perfdata[index - 1].pctr[which];
|
||||
uint64_t rv;
|
||||
|
||||
if (!*pdst) {
|
||||
__asm __volatile("rdtsc":"=A"(rv));
|
||||
|
||||
*pdst = rv;
|
||||
}
|
||||
}
|
||||
|
||||
#define PERF_BEGIN(ccb, nowait) if (perf_active) perf_begin_command(ccb, nowait)
|
||||
#define PERF_END(ccb) if (ccb->perf_index) perf_end_command(ccb)
|
||||
#define PERF_SNAP(ccb,which) if (ccb->perf_index) \
|
||||
perf_snap(ccb->perf_index,which)
|
||||
#define PERF_SNAPC(ccb,which) if (ccb->perf_index) \
|
||||
perf_snapcond(ccb->perf_index,which)
|
||||
#define PERF_PDUSNAPB(pdu) if (pdu->perf_index) \
|
||||
perf_snapcond(pdu->perf_index,pdu->perf_which)
|
||||
#define PERF_PDUSNAPE(pdu) if (pdu->perf_index) \
|
||||
perf_snap(pdu->perf_index,pdu->perf_which+1)
|
||||
#define PERF_PDUSET(pdu,ccb,which) {pdu->perf_index = ccb->perf_index; \
|
||||
pdu->perf_which = which;}
|
||||
|
||||
#else
|
||||
|
||||
#define PERF_BEGIN(ccb, nowait)
|
||||
#define PERF_END(ccb)
|
||||
#define PERF_SNAP(ccb,which)
|
||||
#define PERF_SNAPC(ccb,which)
|
||||
#define PERF_PDUSNAPB(pdu)
|
||||
#define PERF_PDUSNAPE(pdu)
|
||||
#define PERF_PDUSET(pdu,ccb,which)
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,264 @@
|
|||
/* $NetBSD: iscsi_test.h,v 1.1 2011/10/23 21:15:02 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006,2011 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Wasabi Systems, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _ISCSI_TEST_H
|
||||
#define _ISCSI_TEST_H
|
||||
|
||||
#ifdef ISCSI_TEST_MODE
|
||||
|
||||
/* Status codes returned in test mode only */
|
||||
|
||||
#define ISCSI_STATUS_TEST_INACTIVE 5001 /* Test not assigned to connection */
|
||||
#define ISCSI_STATUS_TEST_CANCELED 5002 /* Test was cancelled */
|
||||
#define ISCSI_STATUS_TEST_CONNECTION_CLOSED 5003 /* Connection closed */
|
||||
#define ISCSI_STATUS_TEST_MODIFICATION_SKIPPED 5004 /* Modification skipped due to bad offset */
|
||||
#define ISCSI_STATUS_TEST_HEADER_CRC_ERROR 5005 /* Received PDU had bad header CRC */
|
||||
#define ISCSI_STATUS_TEST_DATA_CRC_ERROR 5006 /* Received PDU had bad data CRC */
|
||||
#define ISCSI_STATUS_TEST_DATA_READ_ERROR 5007 /* Error while receiving PDU */
|
||||
#define ISCSI_STATUS_TEST_ALREADY_ASSIGNED 5008 /* Different test already assigned */
|
||||
|
||||
/*
|
||||
PDU modification descriptor.
|
||||
*/
|
||||
|
||||
#define ISCSITEST_MOD_FLAG_ADD_VAL 0x01 /* Add value to field */
|
||||
/* (default is replace) */
|
||||
#define ISCSITEST_MOD_FLAG_REORDER 0x02 /* Put bytes in network order */
|
||||
|
||||
/* Special values for offset field */
|
||||
|
||||
#define ISCSITEST_OFFSET_HEADERDIGEST (-1) /* offset is header digest */
|
||||
#define ISCSITEST_OFFSET_DATA (-2) /* offset is start of data */
|
||||
#define ISCSITEST_OFFSET_DATADIGEST (-3) /* offset is data digest */
|
||||
#define ISCSITEST_OFFSET_DRV_CMDSN (-4) /* offset is driver's CmdSN */
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t flags; /* flags */
|
||||
uint16_t size; /* size of field in bytes (1..8) */
|
||||
int32_t offset; /* offset into PDU */
|
||||
uint8_t value[8]; /* value to use */
|
||||
} iscsi_pdu_mod_t;
|
||||
|
||||
/* PDU kinds */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ANY_PDU, /* don't care */
|
||||
COMMAND_PDU,
|
||||
RESPONSE_PDU,
|
||||
TASK_REQ_PDU,
|
||||
TASK_RSP_PDU,
|
||||
DATA_OUT_PDU,
|
||||
DATA_IN_PDU,
|
||||
R2T_PDU,
|
||||
ASYNCH_PDU,
|
||||
TEXT_REQ_PDU,
|
||||
TEXT_RSP_PDU,
|
||||
LOGIN_REQ_PDU,
|
||||
LOGIN_RSP_PDU,
|
||||
LOGOUT_REQ_PDU,
|
||||
LOGOUT_RSP_PDU,
|
||||
SNACK_PDU,
|
||||
REJECT_PDU,
|
||||
NOP_OUT_PDU,
|
||||
NOP_IN_PDU,
|
||||
INVALID_PDU
|
||||
} iscsi_pdu_kind_t;
|
||||
|
||||
/* types of offsets supported for determining PDU offset */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ABSOLUTE_ANY, /* absolute to beginning of connection, any kind */
|
||||
RELATIVE_ANY, /* relative to last modified PDU, any kind */
|
||||
ABSOLUTE_PDUKIND, /* absolute to beginning of connection, same kind */
|
||||
RELATIVE_PDUKIND, /* relative to last modified PDU, same kind */
|
||||
ABSOLUTE_TX, /* absolute to beginning of connection, send only */
|
||||
RELATIVE_TX, /* relative to last modified PDU, send only */
|
||||
ABSOLUTE_RX, /* absolute to beginning of connection, receive only */
|
||||
RELATIVE_RX /* relative to last modified PDU, receive only */
|
||||
} iscsi_pdu_offset_t;
|
||||
|
||||
|
||||
/*
|
||||
Negotiation parameters
|
||||
*/
|
||||
|
||||
/* Negotiation states */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NEG_SECURITY, /* First security negotiation PDU (method) */
|
||||
NEG_CHAP_ALG, /* CHAP: Algorithm specification */
|
||||
NEG_CHAP_NAME_RESPONSE, /* CHAP: Name and Response */
|
||||
NEG_OP_NEG /* in Operational negotiation stage */
|
||||
} iscsi_neg_state_t;
|
||||
|
||||
#define ISCSITEST_NEGOPT_REPLACE 0x01 /* Replace existing parameters */
|
||||
/* (default is append) */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
iscsi_neg_state_t state; /* which negotiation stage */
|
||||
uint16_t flags; /* flags */
|
||||
uint16_t size; /* size of value in bytes */
|
||||
uint8_t value[0]; /* value to use */
|
||||
} iscsi_test_negotiation_descriptor_t;
|
||||
|
||||
|
||||
/*
|
||||
Define and add test parameters
|
||||
The calling application defines the test ID. Duplicate IDs are rejected.
|
||||
*/
|
||||
|
||||
/* Options for define_parameters only */
|
||||
|
||||
#define ISCSITEST_NEGOTIATE_R2T 0x00000100 /* Negotiate MaxOutstandingR2T */
|
||||
#define ISCSITEST_NEGOTIATE_MAXBURST 0x00000200 /* Negotiate MaxBurstLength */
|
||||
#define ISCSITEST_NEGOTIATE_FIRSTBURST 0x00000400 /* Negotiate FirstBurstLength */
|
||||
#define ISCSITEST_OVERRIDE_INITIALR2T 0x00001000 /* Override default InitialR2T (set to TRUE) */
|
||||
#define ISCSITEST_OVERRIDE_IMMDATA 0x00002000 /* Override default ImmediateData (set to FALSE) */
|
||||
|
||||
/* options for both define and add_modification parameters */
|
||||
|
||||
#define ISCSITEST_OPT_DISABLE_CCB_TIMEOUT 0x00020000 /* Disable CCB timeout */
|
||||
#define ISCSITEST_OPT_ENABLE_CCB_TIMEOUT 0x00040000 /* Enable CCB timeout */
|
||||
#define ISCSITEST_OPT_DISABLE_CONN_TIMEOUT 0x00080000 /* Disable connection timeout */
|
||||
#define ISCSITEST_OPT_ENABLE_CONN_TIMEOUT 0x00100000 /* Enable connection timeout */
|
||||
#define ISCSITEST_OPT_USE_RANDOM_TX 0x00200000 /* Use random tx loss parameter */
|
||||
#define ISCSITEST_OPT_USE_RANDOM_RX 0x00400000 /* Use random rx loss parameter */
|
||||
|
||||
/* options for add_modification parameters only */
|
||||
|
||||
#define ISCSITEST_OPT_WAIT_FOR_COMPLETION 0x00000001 /* Wait until processing done */
|
||||
|
||||
#define ISCSITEST_OPT_MOD_PERMANENT 0x20000000 /* PDU header mods are permanent */
|
||||
#define ISCSITEST_OPT_NO_RESPONSE_PDU 0x40000000 /* Do not expect response to this PDU */
|
||||
#define ISCSITEST_OPT_DISCARD_PDU 0x80000000 /* Don't send PDU/process PDU in driver */
|
||||
|
||||
/* options for add_modification and send_pdu */
|
||||
|
||||
#define ISCSITEST_KILL_CONNECTION 0x08000000 /* Kill connection when done */
|
||||
|
||||
#define ISCSITEST_SFLAG_NO_HEADER_DIGEST 0x00000020 /* Do not update header digest */
|
||||
#define ISCSITEST_SFLAG_NO_DATA_DIGEST 0x00000040 /* Do not update data digest */
|
||||
|
||||
/* options for send_pdu only */
|
||||
|
||||
#define ISCSITEST_SFLAG_UPDATE_FIELDS 0x00000010 /* Update fields in PDU */
|
||||
#define ISCSITEST_SFLAG_NO_PADDING 0x00000080 /* Do not add padding */
|
||||
|
||||
/* The parameter for TEST_DEFINE ioctl */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t test_id; /* Test ID */
|
||||
uint32_t options; /* Test options */
|
||||
uint32_t session_id; /* Session to attach to (may be 0) */
|
||||
uint32_t connection_id; /* Connection to attach to (may be 0) */
|
||||
uint8_t lose_random_tx; /* 0 disables, else mod value */
|
||||
uint8_t lose_random_rx; /* 0 disables, else mod value */
|
||||
uint32_t r2t_val; /* Used only if NEGOTIATE_R2T */
|
||||
uint32_t maxburst_val; /* Used only if NEGOTIATE_MAXBURST */
|
||||
uint32_t firstburst_val; /* Used only if NEGOTIATE_FIRSTBURST */
|
||||
uint32_t neg_descriptor_size; /* Size of negotiation descriptor (may be 0) */
|
||||
void *neg_descriptor_ptr; /* pointer to negotiation descriptor */
|
||||
uint32_t status; /* Out: Status */
|
||||
} iscsi_test_define_parameters_t;
|
||||
|
||||
|
||||
/* The parameter for TEST_ADD_MODIFICATION ioctl */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t test_id; /* Test ID */
|
||||
uint32_t options; /* Test options */
|
||||
uint8_t lose_random_tx; /* 0 disables, else mod value */
|
||||
uint8_t lose_random_rx; /* 0 disables, else mod value */
|
||||
iscsi_pdu_kind_t which_pdu; /* Which kind of PDU to act on */
|
||||
iscsi_pdu_offset_t which_offset; /* Which offset to use */
|
||||
uint32_t pdu_offset; /* Offset of PDU to act on (0 means next) */
|
||||
uint32_t num_pdu_mods; /* How many PDU modifications */
|
||||
iscsi_pdu_mod_t *mod_ptr; /* pointer to modifications */
|
||||
uint32_t pdu_size; /* size of PDU buffer for get */
|
||||
void *pdu_ptr; /* pointer to PDU buffer */
|
||||
uint32_t pdu_actual_size; /* Out: actual size of PDU */
|
||||
uint32_t status; /* Out: Status */
|
||||
} iscsi_test_add_modification_parameters_t;
|
||||
|
||||
|
||||
/* The parameter for TEST_ADD_NEGOTIATION ioctl */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t test_id; /* Test ID */
|
||||
uint32_t neg_descriptor_size; /* Size of negotiation descriptor (may be 0) */
|
||||
void *neg_descriptor_ptr; /* pointer to negotiation descriptor */
|
||||
uint32_t status; /* Out: Status */
|
||||
} iscsi_test_add_negotiation_parameters_t;
|
||||
|
||||
|
||||
/*
|
||||
Cancel test parameters
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t test_id; /* Test ID */
|
||||
uint32_t status; /* Out: Status */
|
||||
} iscsi_test_cancel_parameters_t;
|
||||
|
||||
/*
|
||||
Send PDU parameters
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t test_id; /* Test ID */
|
||||
uint32_t options; /* Test options */
|
||||
uint32_t pdu_size; /* size of PDU */
|
||||
void *pdu_ptr; /* pointer to PDU */
|
||||
uint32_t status; /* Out: Status */
|
||||
} iscsi_test_send_pdu_parameters_t;
|
||||
|
||||
|
||||
/* IOCTL codes */
|
||||
|
||||
#define ISCSI_TEST_DEFINE _IOWR(0, 100, iscsi_test_define_parameters_t)
|
||||
#define ISCSI_TEST_ADD_NEGOTIATION _IOWR(0, 101, iscsi_test_add_negotiation_parameters_t)
|
||||
#define ISCSI_TEST_ADD_MODIFICATION _IOWR(0, 102, iscsi_test_add_modification_parameters_t)
|
||||
#define ISCSI_TEST_SEND_PDU _IOWR(0, 103, iscsi_test_send_pdu_parameters_t)
|
||||
#define ISCSI_TEST_CANCEL _IOWR(0, 109, iscsi_test_cancel_parameters_t)
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,105 @@
|
|||
/* $wasabi: iscsi_testlocal.h,v 1.5 2006/05/30 23:22:20 twagner Exp $ */
|
||||
/* $NetBSD: iscsi_testlocal.h,v 1.1 2011/10/23 21:15:02 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006,2011 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Wasabi Systems, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _ISCSI_TESTLOCAL_H
|
||||
#define _ISCSI_TESTLOCAL_H
|
||||
|
||||
#ifdef ISCSI_TEST_MODE
|
||||
|
||||
typedef struct mod_desc_s
|
||||
{
|
||||
TAILQ_ENTRY(mod_desc_s) link;
|
||||
void *pdu_ptr; /* get only */
|
||||
iscsi_test_add_modification_parameters_t pars;
|
||||
iscsi_pdu_mod_t mods[0];
|
||||
} mod_desc_t;
|
||||
|
||||
|
||||
typedef struct neg_desc_s
|
||||
{
|
||||
TAILQ_ENTRY(neg_desc_s) link;
|
||||
iscsi_test_negotiation_descriptor_t entry;
|
||||
} neg_desc_t;
|
||||
|
||||
|
||||
TAILQ_HEAD(mod_list_s, mod_desc_s);
|
||||
typedef struct mod_list_s mod_list_t;
|
||||
|
||||
TAILQ_HEAD(neg_list_s, neg_desc_s);
|
||||
typedef struct neg_list_s neg_list_t;
|
||||
|
||||
#define CNT_TX 0
|
||||
#define CNT_RX 1
|
||||
|
||||
typedef struct test_pars_s
|
||||
{
|
||||
TAILQ_ENTRY(test_pars_s) link; /* links tests to be assigned */
|
||||
uint32_t test_id; /* Test ID */
|
||||
connection_t *connection; /* Attached Connection */
|
||||
uint16_t options; /* Test options */
|
||||
uint8_t lose_random[2]; /* 0 disables, else mod value */
|
||||
uint32_t r2t_val; /* Used only if NEGOTIATE_R2T */
|
||||
uint32_t maxburst_val; /* Used only if NEGOTIATE_MAXBURST */
|
||||
uint32_t firstburst_val; /* Used only if NEGOTIATE_FIRSTBURST */
|
||||
neg_list_t negs; /* list of negotiation descriptors */
|
||||
mod_list_t mods; /* list of modification decriptors */
|
||||
uint32_t pdu_count[INVALID_PDU + 1][2]; /* PDU counter */
|
||||
uint32_t pdu_last[INVALID_PDU + 1][2]; /* last PDU counter */
|
||||
} test_pars_t;
|
||||
|
||||
|
||||
TAILQ_HEAD(test_pars_list_s, test_pars_s);
|
||||
typedef struct test_pars_list_s test_pars_list_t;
|
||||
|
||||
void test_assign_connection(connection_t *);
|
||||
void test_remove_connection(connection_t *);
|
||||
|
||||
#define TEST_INVALID_HEADER_CRC -99
|
||||
#define TEST_READ_ERROR 1
|
||||
#define TEST_INVALID_DATA_CRC -1
|
||||
|
||||
int test_mode_rx(connection_t *, pdu_t *, int);
|
||||
int test_mode_tx(connection_t *, pdu_t *);
|
||||
|
||||
void test_define(iscsi_test_define_parameters_t *);
|
||||
void test_add_neg(iscsi_test_add_negotiation_parameters_t *);
|
||||
void test_add_mod(struct proc *, iscsi_test_add_modification_parameters_t *);
|
||||
void test_send_pdu(struct proc *, iscsi_test_send_pdu_parameters_t *);
|
||||
void test_cancel(iscsi_test_cancel_parameters_t *);
|
||||
|
||||
#define test_ccb_timeout(conn) ((conn->test_pars == NULL) ? 1 \
|
||||
: !(conn->test_pars->options & ISCSITEST_OPT_DISABLE_CCB_TIMEOUT))
|
||||
|
||||
#define test_conn_timeout(conn) ((conn->test_pars == NULL) ? 1 \
|
||||
: !(conn->test_pars->options & ISCSITEST_OPT_DISABLE_CONN_TIMEOUT))
|
||||
|
||||
#endif /* TEST_MODE */
|
||||
#endif /* TESTLOCAL_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,706 @@
|
|||
/* $NetBSD: iscsi_utils.c,v 1.1 2011/10/23 21:15:02 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2004,2005,2006,2008 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Wasabi Systems, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "iscsi_globals.h"
|
||||
|
||||
#include <sys/systm.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/socketvar.h>
|
||||
|
||||
|
||||
#ifdef ISCSI_DEBUG
|
||||
|
||||
/* debug helper routine */
|
||||
void
|
||||
dump(void *buff, int len)
|
||||
{
|
||||
uint8_t *bp = (uint8_t *) buff;
|
||||
int i;
|
||||
|
||||
while (len > 0) {
|
||||
for (i = min(16, len); i > 0; i--)
|
||||
printf("%02x ", *bp++);
|
||||
printf("\n");
|
||||
len -= 16;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
* Digest functions
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************
|
||||
*
|
||||
* CRC LOOKUP TABLE
|
||||
* ================
|
||||
* The following CRC lookup table was generated automagically
|
||||
* by the Rocksoft^tm Model CRC Algorithm Table Generation
|
||||
* Program V1.0 using the following model parameters:
|
||||
*
|
||||
* Width : 4 bytes.
|
||||
* Poly : 0x1EDC6F41L
|
||||
* Reverse : TRUE.
|
||||
*
|
||||
* For more information on the Rocksoft^tm Model CRC Algorithm,
|
||||
* see the document titled "A Painless Guide to CRC Error
|
||||
* Detection Algorithms" by Ross Williams
|
||||
* (ross@guest.adelaide.edu.au.). This document is likely to be
|
||||
* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft".
|
||||
*
|
||||
*****************************************************************/
|
||||
|
||||
STATIC uint32_t crc_table[256] = {
|
||||
0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
|
||||
0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
|
||||
0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
|
||||
0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
|
||||
0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
|
||||
0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
|
||||
0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
|
||||
0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
|
||||
0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
|
||||
0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
|
||||
0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
|
||||
0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
|
||||
0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
|
||||
0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
|
||||
0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
|
||||
0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
|
||||
0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
|
||||
0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
|
||||
0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
|
||||
0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
|
||||
0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
|
||||
0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
|
||||
0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
|
||||
0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
|
||||
0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
|
||||
0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
|
||||
0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
|
||||
0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
|
||||
0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
|
||||
0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
|
||||
0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
|
||||
0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
|
||||
0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
|
||||
0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
|
||||
0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
|
||||
0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
|
||||
0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
|
||||
0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
|
||||
0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
|
||||
0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
|
||||
0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
|
||||
0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
|
||||
0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
|
||||
0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
|
||||
0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
|
||||
0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
|
||||
0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
|
||||
0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
|
||||
0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
|
||||
0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
|
||||
0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
|
||||
0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
|
||||
0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
|
||||
0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
|
||||
0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
|
||||
0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
|
||||
0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
|
||||
0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
|
||||
0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
|
||||
0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
|
||||
0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
|
||||
0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
|
||||
0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
|
||||
0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* gen_digest:
|
||||
* Generate an iSCSI CRC32C digest over the given data.
|
||||
*
|
||||
* Parameters:
|
||||
* buff The data
|
||||
* len The length of the data in bytes
|
||||
*
|
||||
* Returns: The digest in network byte order
|
||||
*/
|
||||
|
||||
uint32_t
|
||||
gen_digest(void *buff, int len)
|
||||
{
|
||||
uint8_t *bp = (uint8_t *) buff;
|
||||
uint32_t crc = 0xffffffff;
|
||||
|
||||
while (len--) {
|
||||
crc = ((crc >> 8) & 0x00ffffff) ^ crc_table[(crc ^ *bp++) & 0xff];
|
||||
}
|
||||
return crc ^ 0xffffffff;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* gen_digest_2:
|
||||
* Generate an iSCSI CRC32C digest over the given data, which is split over
|
||||
* two buffers.
|
||||
*
|
||||
* Parameters:
|
||||
* buf1, buf2 The data
|
||||
* len1, len2 The length of the data in bytes
|
||||
*
|
||||
* Returns: The digest in network byte order
|
||||
*/
|
||||
|
||||
uint32_t
|
||||
gen_digest_2(void *buf1, int len1, void *buf2, int len2)
|
||||
{
|
||||
uint8_t *bp = (uint8_t *) buf1;
|
||||
uint32_t crc = 0xffffffff;
|
||||
|
||||
while (len1--) {
|
||||
crc = ((crc >> 8) & 0x00ffffff) ^ crc_table[(crc ^ *bp++) & 0xff];
|
||||
}
|
||||
bp = (uint8_t *) buf2;
|
||||
while (len2--) {
|
||||
crc = ((crc >> 8) & 0x00ffffff) ^ crc_table[(crc ^ *bp++) & 0xff];
|
||||
}
|
||||
return crc ^ 0xffffffff;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* CCB management functions
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* get_ccb:
|
||||
* Get a CCB for the SCSI operation, waiting if none is available.
|
||||
*
|
||||
* Parameter:
|
||||
* sess The session containing this CCB
|
||||
* waitok Whether waiting for a CCB is OK
|
||||
*
|
||||
* Returns: The CCB.
|
||||
*/
|
||||
|
||||
ccb_t *
|
||||
get_ccb(connection_t *conn, bool waitok)
|
||||
{
|
||||
ccb_t *ccb;
|
||||
session_t *sess = conn->session;
|
||||
|
||||
do {
|
||||
CS_BEGIN;
|
||||
ccb = TAILQ_FIRST(&sess->ccb_pool);
|
||||
if (ccb != NULL) {
|
||||
TAILQ_REMOVE(&sess->ccb_pool, ccb, chain);
|
||||
}
|
||||
CS_END;
|
||||
DEB(100, ("get_ccb: ccb = %p, waitok = %d\n", ccb, waitok));
|
||||
if (ccb == NULL) {
|
||||
if (!waitok || conn->terminating) {
|
||||
return NULL;
|
||||
}
|
||||
PDEBOUT(("Waiting for CCB!\n"));
|
||||
tsleep(&sess->ccb_pool, PWAIT, "get_ccb", 0);
|
||||
}
|
||||
} while (ccb == NULL);
|
||||
|
||||
ccb->flags = 0;
|
||||
ccb->xs = NULL;
|
||||
ccb->temp_data = NULL;
|
||||
ccb->text_data = NULL;
|
||||
ccb->status = ISCSI_STATUS_SUCCESS;
|
||||
ccb->ITT = (ccb->ITT & 0xffffff) | (++sess->itt_id << 24);
|
||||
ccb->disp = CCBDISP_NOWAIT;
|
||||
ccb->connection = conn;
|
||||
|
||||
return ccb;
|
||||
}
|
||||
|
||||
/*
|
||||
* free_ccb:
|
||||
* Put a CCB back onto the free list.
|
||||
*
|
||||
* Parameter: The CCB.
|
||||
*/
|
||||
|
||||
void
|
||||
free_ccb(ccb_t *ccb)
|
||||
{
|
||||
session_t *sess = ccb->session;
|
||||
pdu_t *pdu;
|
||||
|
||||
ccb->disp = CCBDISP_UNUSED;
|
||||
|
||||
/* free temporary data */
|
||||
if (ccb->temp_data != NULL) {
|
||||
free(ccb->temp_data, M_TEMP);
|
||||
}
|
||||
if (ccb->text_data != NULL) {
|
||||
free(ccb->text_data, M_TEMP);
|
||||
}
|
||||
/* free PDU waiting for ACK */
|
||||
if ((pdu = ccb->pdu_waiting) != NULL) {
|
||||
ccb->pdu_waiting = NULL;
|
||||
free_pdu(pdu);
|
||||
}
|
||||
|
||||
CS_BEGIN;
|
||||
TAILQ_INSERT_TAIL(&sess->ccb_pool, ccb, chain);
|
||||
CS_END;
|
||||
wakeup(&sess->ccb_pool);
|
||||
}
|
||||
|
||||
/*
|
||||
* create_ccbs
|
||||
* "Create" the pool of CCBs. This doesn't actually create the CCBs
|
||||
* (they are allocated with the session structure), but it links them
|
||||
* into the free-list.
|
||||
*
|
||||
* Parameter: The session owning the CCBs.
|
||||
*/
|
||||
|
||||
void
|
||||
create_ccbs(session_t *sess)
|
||||
{
|
||||
int i;
|
||||
ccb_t *ccb;
|
||||
int sid = sess->id << 8;
|
||||
|
||||
/* Note: CCBs are initialized to 0 with connection structure */
|
||||
|
||||
for (i = 0, ccb = sess->ccb; i < CCBS_PER_SESSION; i++, ccb++) {
|
||||
ccb->ITT = i | sid;
|
||||
ccb->session = sess;
|
||||
|
||||
callout_init(&ccb->timeout, 0);
|
||||
#if (__NetBSD_Version__ >= 106000000)
|
||||
callout_setfunc(&ccb->timeout, ccb_timeout, ccb);
|
||||
#endif
|
||||
|
||||
/*DEB (9, ("Create_ccbs: ccb %x itt %x\n", ccb, ccb->ITT)); */
|
||||
TAILQ_INSERT_HEAD(&sess->ccb_pool, ccb, chain);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* wake_ccb:
|
||||
* Wake up (or dispose of) a CCB. Depending on the CCB's disposition,
|
||||
* either wake up the requesting thread, signal SCSIPI that we're done,
|
||||
* or just free the CCB for CCBDISP_FREE.
|
||||
*
|
||||
* Parameter: The CCB to handle.
|
||||
*/
|
||||
|
||||
void
|
||||
wake_ccb(ccb_t *ccb)
|
||||
{
|
||||
ccb_disp_t disp;
|
||||
connection_t *conn;
|
||||
int s;
|
||||
#ifdef ISCSI_DEBUG
|
||||
static ccb_t *lastccb = NULL;
|
||||
static int lastdisp = -1;
|
||||
#endif
|
||||
|
||||
/* Just in case */
|
||||
if (ccb == NULL)
|
||||
return;
|
||||
|
||||
conn = ccb->connection;
|
||||
|
||||
#ifdef ISCSI_DEBUG
|
||||
if (ccb != lastccb || ccb->disp != lastdisp) {
|
||||
DEBC(conn, 9, ("Wake CCB, ccb = %p, disp = %d\n",
|
||||
ccb, (ccb) ? ccb->disp : 0));
|
||||
lastccb = ccb;
|
||||
lastdisp = (ccb) ? ccb->disp : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
callout_stop(&ccb->timeout);
|
||||
|
||||
s = splbio();
|
||||
disp = ccb->disp;
|
||||
if (disp <= CCBDISP_NOWAIT ||
|
||||
(disp == CCBDISP_DEFER && conn->state <= ST_WINDING_DOWN)) {
|
||||
splx(s);
|
||||
return;
|
||||
}
|
||||
|
||||
TAILQ_REMOVE(&conn->ccbs_waiting, ccb, chain);
|
||||
|
||||
/* change the disposition so nobody tries this again */
|
||||
ccb->disp = CCBDISP_BUSY;
|
||||
splx(s);
|
||||
|
||||
PERF_END(ccb);
|
||||
|
||||
switch (disp) {
|
||||
case CCBDISP_WAIT:
|
||||
wakeup(ccb);
|
||||
break;
|
||||
|
||||
case CCBDISP_SCSIPI:
|
||||
iscsi_done(ccb);
|
||||
break;
|
||||
|
||||
case CCBDISP_DEFER:
|
||||
break;
|
||||
|
||||
default:
|
||||
free_ccb(ccb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* complete_ccb:
|
||||
* Same as wake_ccb, but the CCB is not assumed to be in the waiting list.
|
||||
*
|
||||
* Parameter: The CCB to handle.
|
||||
*/
|
||||
|
||||
void
|
||||
complete_ccb(ccb_t *ccb)
|
||||
{
|
||||
ccb_disp_t disp;
|
||||
int s;
|
||||
|
||||
/* Just in case */
|
||||
if (ccb == NULL)
|
||||
return;
|
||||
|
||||
callout_stop(&ccb->timeout);
|
||||
|
||||
s = splbio();
|
||||
disp = ccb->disp;
|
||||
if (disp <= CCBDISP_NOWAIT || disp == CCBDISP_DEFER) {
|
||||
splx(s);
|
||||
return;
|
||||
}
|
||||
/* change the disposition so nobody tries this again */
|
||||
ccb->disp = CCBDISP_BUSY;
|
||||
splx(s);
|
||||
|
||||
PERF_END(ccb);
|
||||
|
||||
switch (disp) {
|
||||
case CCBDISP_WAIT:
|
||||
wakeup(ccb);
|
||||
break;
|
||||
|
||||
case CCBDISP_SCSIPI:
|
||||
iscsi_done(ccb);
|
||||
break;
|
||||
|
||||
default:
|
||||
free_ccb(ccb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* PDU management functions
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* get_pdu_c:
|
||||
* Get a PDU for the SCSI operation.
|
||||
*
|
||||
* Parameter:
|
||||
* conn The connection this PDU should be associated with
|
||||
* waitok OK to wait for PDU if TRUE
|
||||
*
|
||||
* Returns: The PDU or NULL if none is available and waitok is FALSE.
|
||||
*/
|
||||
|
||||
pdu_t *
|
||||
get_pdu_c(connection_t *conn, bool waitok)
|
||||
{
|
||||
pdu_t *pdu;
|
||||
|
||||
do {
|
||||
CS_BEGIN;
|
||||
pdu = TAILQ_FIRST(&conn->pdu_pool);
|
||||
if (pdu != NULL) {
|
||||
TAILQ_REMOVE(&conn->pdu_pool, pdu, chain);
|
||||
}
|
||||
CS_END;
|
||||
DEB(100, ("get_pdu_c: pdu = %p, waitok = %d\n", pdu, waitok));
|
||||
if (pdu == NULL) {
|
||||
if (!waitok || conn->terminating)
|
||||
return NULL;
|
||||
PDEBOUT(("Waiting for PDU!\n"));
|
||||
tsleep(&conn->pdu_pool, PWAIT, "get_pdu_c", 0);
|
||||
}
|
||||
} while (pdu == NULL);
|
||||
|
||||
memset(pdu, 0, sizeof(pdu_t));
|
||||
pdu->connection = conn;
|
||||
pdu->disp = PDUDISP_FREE;
|
||||
|
||||
return pdu;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_pdu:
|
||||
* Get a PDU for the SCSI operation, waits if none is available.
|
||||
* Same as get_pdu_c, but with wait always OK.
|
||||
* Duplicated code because this is the more common case.
|
||||
*
|
||||
* Parameter: The connection this PDU should be associated with.
|
||||
*
|
||||
* Returns: The PDU.
|
||||
*/
|
||||
|
||||
pdu_t *
|
||||
get_pdu(connection_t *conn)
|
||||
{
|
||||
pdu_t *pdu;
|
||||
|
||||
do {
|
||||
CS_BEGIN;
|
||||
pdu = TAILQ_FIRST(&conn->pdu_pool);
|
||||
if (pdu != NULL) {
|
||||
TAILQ_REMOVE(&conn->pdu_pool, pdu, chain);
|
||||
}
|
||||
CS_END;
|
||||
DEB(100, ("get_pdu: pdu = %p\n", pdu));
|
||||
if (pdu == NULL) {
|
||||
if (conn->terminating)
|
||||
return NULL;
|
||||
|
||||
PDEBOUT(("Waiting for PDU!\n"));
|
||||
tsleep(&conn->pdu_pool, PWAIT, "get_pdu", 0);
|
||||
}
|
||||
} while (pdu == NULL);
|
||||
|
||||
memset(pdu, 0, sizeof(pdu_t));
|
||||
pdu->connection = conn;
|
||||
pdu->disp = PDUDISP_FREE;
|
||||
|
||||
return pdu;
|
||||
}
|
||||
|
||||
/*
|
||||
* free_pdu:
|
||||
* Put a PDU back onto the free list.
|
||||
*
|
||||
* Parameter: The PDU.
|
||||
*/
|
||||
|
||||
void
|
||||
free_pdu(pdu_t *pdu)
|
||||
{
|
||||
connection_t *conn = pdu->connection;
|
||||
pdu_disp_t pdisp;
|
||||
|
||||
if (PDUDISP_UNUSED == (pdisp = pdu->disp))
|
||||
return;
|
||||
pdu->disp = PDUDISP_UNUSED;
|
||||
|
||||
if (pdu->flags & PDUF_INQUEUE) {
|
||||
TAILQ_REMOVE(&conn->pdus_to_send, pdu, send_chain);
|
||||
pdu->flags &= ~PDUF_INQUEUE;
|
||||
}
|
||||
|
||||
if (pdisp == PDUDISP_SIGNAL)
|
||||
wakeup(pdu);
|
||||
|
||||
/* free temporary data in this PDU */
|
||||
if (pdu->temp_data)
|
||||
free(pdu->temp_data, M_TEMP);
|
||||
|
||||
CS_BEGIN;
|
||||
TAILQ_INSERT_TAIL(&conn->pdu_pool, pdu, chain);
|
||||
CS_END;
|
||||
wakeup(&conn->pdu_pool);
|
||||
}
|
||||
|
||||
/*
|
||||
* create_pdus
|
||||
* "Create" the pool of PDUs. This doesn't actually create the PDUs
|
||||
* (they are allocated with the connection structure), but it links them
|
||||
* into the free-list.
|
||||
*
|
||||
* Parameter: The connection owning the PDUs.
|
||||
*/
|
||||
|
||||
void
|
||||
create_pdus(connection_t *conn)
|
||||
{
|
||||
int i;
|
||||
pdu_t *pdu;
|
||||
|
||||
/* Note: PDUs are initialized to 0 with connection structure */
|
||||
|
||||
for (i = 0, pdu = conn->pdu; i < PDUS_PER_CONNECTION; i++, pdu++) {
|
||||
TAILQ_INSERT_HEAD(&conn->pdu_pool, pdu, chain);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Serial Number management functions
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* init_sernum:
|
||||
* Initialize serial number buffer variables.
|
||||
*
|
||||
* Parameter:
|
||||
* buff The serial number buffer.
|
||||
*/
|
||||
|
||||
void
|
||||
init_sernum(sernum_buffer_t *buff)
|
||||
{
|
||||
|
||||
buff->bottom = 0;
|
||||
buff->top = 0;
|
||||
buff->next_sn = 0;
|
||||
buff->ExpSN = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* add_sernum:
|
||||
* Add a received serial number to the buffer.
|
||||
* If the serial number is smaller than the expected one, it is ignored.
|
||||
* If it is larger, all missing serial numbers are added as well.
|
||||
*
|
||||
* Parameter:
|
||||
* buff The serial number buffer.
|
||||
* num The received serial number
|
||||
*
|
||||
* Returns:
|
||||
* 0 if the received block is a duplicate
|
||||
* 1 if the number is the expected one
|
||||
* >1 if the numer is > the expected value, in this case the
|
||||
* return value is the number of unacknowledged blocks
|
||||
* <0 if the buffer is full (i.e. an excessive number of blocks
|
||||
* is unacknowledged)
|
||||
*/
|
||||
|
||||
int
|
||||
add_sernum(sernum_buffer_t *buff, uint32_t num)
|
||||
{
|
||||
int i, t, b, n, diff;
|
||||
|
||||
/*
|
||||
* next_sn is the next expected SN, so normally diff should be 1.
|
||||
*/
|
||||
n = buff->next_sn;
|
||||
diff = (num - n) + 1;
|
||||
|
||||
if (diff <= 0) {
|
||||
PDEB(1, ("Rx Duplicate Block: SN %d < Next SN %d\n", num, n));
|
||||
return 0; /* ignore if SN is smaller than expected (dup or retransmit) */
|
||||
}
|
||||
|
||||
buff->next_sn = num + 1;
|
||||
t = buff->top;
|
||||
b = buff->bottom;
|
||||
|
||||
for (i = 0; i < diff; i++) {
|
||||
buff->sernum[t] = n++;
|
||||
buff->ack[t] = 0;
|
||||
t = (t + 1) % SERNUM_BUFFER_LENGTH;
|
||||
if (t == b) {
|
||||
DEB(1, ("AddSernum: Buffer Full! num %d, diff %d\n", num, diff));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
buff->top = t;
|
||||
DEB(10, ("AddSernum bottom %d [%d], top %d, num %d, diff %d\n",
|
||||
b, buff->sernum[b], buff->top, num, diff));
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ack_sernum:
|
||||
* Mark a received serial number as acknowledged. This does not necessarily
|
||||
* change the associated ExpSN if there are lower serial numbers in the
|
||||
* buffer.
|
||||
*
|
||||
* Parameter:
|
||||
* buff The serial number buffer.
|
||||
* num The serial number to acknowledge.
|
||||
*
|
||||
* Returns: The value of ExpSN.
|
||||
*/
|
||||
|
||||
uint32_t
|
||||
ack_sernum(sernum_buffer_t *buff, uint32_t num)
|
||||
{
|
||||
int b = buff->bottom;
|
||||
int t = buff->top;
|
||||
|
||||
/* shortcut for most likely case */
|
||||
if (t == (b + 1) && num == buff->sernum[b]) {
|
||||
/* buffer is now empty, reset top */
|
||||
buff->top = b;
|
||||
} else if (b != t) {
|
||||
for (; b != t; b = (b + 1) % SERNUM_BUFFER_LENGTH) {
|
||||
if (!sn_a_lt_b(buff->sernum[b], num))
|
||||
break;
|
||||
}
|
||||
if (num == buff->sernum[b]) {
|
||||
if (b == buff->bottom)
|
||||
buff->bottom = (b + 1) % SERNUM_BUFFER_LENGTH;
|
||||
else
|
||||
buff->ack[b] = 1;
|
||||
}
|
||||
|
||||
for (b = buff->bottom, num = buff->sernum[b] - 1;
|
||||
b != t && buff->ack[b]; b = (b + 1) % SERNUM_BUFFER_LENGTH) {
|
||||
num = buff->sernum[b];
|
||||
}
|
||||
}
|
||||
|
||||
if (!sn_a_lt_b(num, buff->ExpSN))
|
||||
buff->ExpSN = num + 1;
|
||||
|
||||
DEB(10, ("AckSernum bottom %d, top %d, num %d ExpSN %d\n",
|
||||
buff->bottom, buff->top, num, buff->ExpSN));
|
||||
|
||||
return buff->ExpSN;
|
||||
}
|
Loading…
Reference in New Issue