From patchwork Fri Dec 3 11:09:51 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ronnie sahlberg X-Patchwork-Id: 74128 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id E4A201007D8 for ; Fri, 3 Dec 2010 23:00:57 +1100 (EST) Received: from localhost ([127.0.0.1]:41975 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1POTea-0003B1-DF for incoming@patchwork.ozlabs.org; Fri, 03 Dec 2010 06:18:16 -0500 Received: from [140.186.70.92] (port=59500 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1POTYd-0001yd-3n for qemu-devel@nongnu.org; Fri, 03 Dec 2010 06:12:11 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1POTYa-0002sF-0P for qemu-devel@nongnu.org; Fri, 03 Dec 2010 06:12:06 -0500 Received: from mail-gw0-f45.google.com ([74.125.83.45]:39803) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1POTYZ-0002sA-Qg for qemu-devel@nongnu.org; Fri, 03 Dec 2010 06:12:03 -0500 Received: by gwj23 with SMTP id 23so2889485gwj.4 for ; Fri, 03 Dec 2010 03:12:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:received:from:to:cc:subject :date:message-id:x-mailer:in-reply-to:references; bh=sUtvCdaU9CSDC4luwH3WwKKm5RmY6l1ceMW+9DPbNzQ=; b=uLgKuVAmwXUVBkYyXAcueZKaUl33XsueJG+BZYPcuBnnETsA8HajC0yhdpoW2iRV/r Sd9wCyVphhz4wNJCflmsQFtRj0ej7uTTBYBp1xr6giYmdnE8O/+U6DRyyFK8FV9vLKvi xWcPnO52/UKF5qpulapvceAkzV/K+S24aC6NA= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; b=SXjtXSPnI4aGGiNdSoBMquo6OS4NClG13N4gnXUEiq33Ck6+Q2dTNs0zupx2feAAgB EDnKU5wSda4dx5hAHFqdePr7dNJVpXreoN1M6OKtVeIIWWn2c1Fq5OUf2m0jidXnSSl4 wL+c5epPSkB+L1xiGzvCygEP2JRWBg+MUNdGI= Received: by 10.151.147.17 with SMTP id z17mr3541160ybn.116.1291374723380; Fri, 03 Dec 2010 03:12:03 -0800 (PST) Received: from ronniesahlberg@gmail.com (CPE-121-216-183-74.lnse2.ken.bigpond.net.au [121.216.183.74]) by mx.google.com with ESMTPS id f73sm1004496yhc.4.2010.12.03.03.11.59 (version=TLSv1/SSLv3 cipher=RC4-MD5); Fri, 03 Dec 2010 03:12:03 -0800 (PST) Received: by ronniesahlberg@gmail.com (sSMTP sendmail emulation); Fri, 03 Dec 2010 22:11:34 +1100 From: ronniesahlberg@gmail.com To: qemu-devel@nongnu.org Date: Fri, 3 Dec 2010 22:09:51 +1100 Message-Id: <1291374593-17448-13-git-send-email-ronniesahlberg@gmail.com> X-Mailer: git-send-email 1.7.3.1 In-Reply-To: <1291374593-17448-1-git-send-email-ronniesahlberg@gmail.com> References: <1291374593-17448-1-git-send-email-ronniesahlberg@gmail.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) Cc: Ronnie Sahlberg Subject: [Qemu-devel] [PATCH 12/14] ./block/iscsi/*.h X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Ronnie Sahlberg iscsi client library : *.h These files contain the heade declaraions, typedefs and useful macros used by the iscsi client library. ... ./block/iscsi/ contains a copy of a general purpose iscsi client library which is aimed at providing a clientside api for iscsi for both qemu/kvm as well as otther scsi related utilities. As such, there is need to make merging across various consumers, qemu/kvm being one of many here, as easy as possible when features are added to the library. As such, no consumer/qemu specific code is used in this library as well as coding guidelined might not be adhered to 100% It is the intention that this library will be useful for many and that iscsi use spawned from this will flourish. Signed-off-by: Ronnie Sahlberg --- block/iscsi/iscsi-private.h | 172 +++++++++++++++++ block/iscsi/iscsi.h | 433 +++++++++++++++++++++++++++++++++++++++++++ block/iscsi/scsi-lowlevel.h | 369 ++++++++++++++++++++++++++++++++++++ block/iscsi/slist.h | 51 +++++ 4 files changed, 1025 insertions(+), 0 deletions(-) create mode 100644 block/iscsi/iscsi-private.h create mode 100644 block/iscsi/iscsi.h create mode 100644 block/iscsi/scsi-lowlevel.h create mode 100644 block/iscsi/slist.h diff --git a/block/iscsi/iscsi-private.h b/block/iscsi/iscsi-private.h new file mode 100644 index 0000000..ef1d02f --- /dev/null +++ b/block/iscsi/iscsi-private.h @@ -0,0 +1,172 @@ +/* + Copyright (C) 2010 by Ronnie Sahlberg + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include + +#ifndef discard_const +#define discard_const(ptr) ((void *)((intptr_t)(ptr))) +#endif + +struct iscsi_context { + const char *initiator_name; + const char *target_name; + const char *alias; + enum iscsi_session_type session_type; + unsigned char isid[6]; + uint32_t itt; + uint32_t cmdsn; + uint32_t statsn; + enum iscsi_header_digest want_header_digest; + enum iscsi_header_digest header_digest; + + char *error_string; + + int fd; + int is_connected; + int is_loggedin; + + iscsi_command_cb connect_cb; + void *connect_data; + + struct iscsi_pdu *outqueue; + struct iscsi_pdu *waitpdu; + + int insize; + int inpos; + unsigned char *inbuf; +}; + +#define ISCSI_RAW_HEADER_SIZE 48 + +#define ISCSI_HEADER_SIZE (ISCSI_RAW_HEADER_SIZE \ + + (iscsi->header_digest == ISCSI_HEADER_DIGEST_NONE?0:4)) + +#define ISCSI_PDU_IMMEDIATE 0x40 + +#define ISCSI_PDU_TEXT_FINAL 0x80 +#define ISCSI_PDU_TEXT_CONTINUE 0x40 + +#define ISCSI_PDU_LOGIN_TRANSIT 0x80 +#define ISCSI_PDU_LOGIN_CONTINUE 0x40 +#define ISCSI_PDU_LOGIN_CSG_SECNEG 0x00 +#define ISCSI_PDU_LOGIN_CSG_OPNEG 0x04 +#define ISCSI_PDU_LOGIN_CSG_FF 0x0c +#define ISCSI_PDU_LOGIN_NSG_SECNEG 0x00 +#define ISCSI_PDU_LOGIN_NSG_OPNEG 0x01 +#define ISCSI_PDU_LOGIN_NSG_FF 0x03 + +#define ISCSI_PDU_SCSI_FINAL 0x80 +#define ISCSI_PDU_SCSI_READ 0x40 +#define ISCSI_PDU_SCSI_WRITE 0x20 +#define ISCSI_PDU_SCSI_ATTR_UNTAGGED 0x00 +#define ISCSI_PDU_SCSI_ATTR_SIMPLE 0x01 +#define ISCSI_PDU_SCSI_ATTR_ORDERED 0x02 +#define ISCSI_PDU_SCSI_ATTR_HEADOFQUEUE 0x03 +#define ISCSI_PDU_SCSI_ATTR_ACA 0x04 + +#define ISCSI_PDU_DATA_FINAL 0x80 +#define ISCSI_PDU_DATA_ACK_REQUESTED 0x40 +#define ISCSI_PDU_DATA_BIDIR_OVERFLOW 0x10 +#define ISCSI_PDU_DATA_BIDIR_UNDERFLOW 0x08 +#define ISCSI_PDU_DATA_RESIDUAL_OVERFLOW 0x04 +#define ISCSI_PDU_DATA_RESIDUAL_UNDERFLOW 0x02 +#define ISCSI_PDU_DATA_CONTAINS_STATUS 0x01 + +enum iscsi_opcode { + ISCSI_PDU_NOP_OUT = 0x00, + ISCSI_PDU_SCSI_REQUEST = 0x01, + ISCSI_PDU_LOGIN_REQUEST = 0x03, + ISCSI_PDU_TEXT_REQUEST = 0x04, + ISCSI_PDU_LOGOUT_REQUEST = 0x06, + ISCSI_PDU_NOP_IN = 0x20, + ISCSI_PDU_SCSI_RESPONSE = 0x21, + ISCSI_PDU_LOGIN_RESPONSE = 0x23, + ISCSI_PDU_TEXT_RESPONSE = 0x24, + ISCSI_PDU_DATA_IN = 0x25, + ISCSI_PDU_LOGOUT_RESPONSE = 0x26 +}; + +struct iscsi_pdu { + struct iscsi_pdu *next; + + uint32_t itt; + uint32_t cmdsn; + enum iscsi_opcode response_opcode; + + iscsi_command_cb callback; + void *private_data; + + int written; + struct iscsi_data outdata; + struct iscsi_data indata; + + struct iscsi_scsi_cbdata *scsi_cbdata; +}; + +void iscsi_free_scsi_cbdata(struct iscsi_scsi_cbdata *scsi_cbdata); + +struct iscsi_pdu *iscsi_allocate_pdu(struct iscsi_context *iscsi, + enum iscsi_opcode opcode, + enum iscsi_opcode response_opcode); +void iscsi_free_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); +void iscsi_pdu_set_pduflags(struct iscsi_pdu *pdu, unsigned char flags); +void iscsi_pdu_set_immediate(struct iscsi_pdu *pdu); +void iscsi_pdu_set_ttt(struct iscsi_pdu *pdu, uint32_t ttt); +void iscsi_pdu_set_cmdsn(struct iscsi_pdu *pdu, uint32_t cmdsn); +void iscsi_pdu_set_lun(struct iscsi_pdu *pdu, uint32_t lun); +void iscsi_pdu_set_expstatsn(struct iscsi_pdu *pdu, uint32_t expstatsnsn); +void iscsi_pdu_set_expxferlen(struct iscsi_pdu *pdu, uint32_t expxferlen); +int iscsi_pdu_add_data(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, + unsigned char *dptr, int dsize); +int iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); +int iscsi_add_data(struct iscsi_context *iscsi, struct iscsi_data *data, + unsigned char *dptr, int dsize, int pdualignment); +int iscsi_set_random_isid(struct iscsi_context *iscsi); + +struct scsi_task; +void iscsi_pdu_set_cdb(struct iscsi_pdu *pdu, struct scsi_task *task); + +int iscsi_get_pdu_size(struct iscsi_context *iscsi, const unsigned char *hdr); +int iscsi_process_pdu(struct iscsi_context *iscsi, const unsigned char *hdr, + int size); + +int iscsi_process_login_reply(struct iscsi_context *iscsi, + struct iscsi_pdu *pdu, + const unsigned char *hdr, int size); +int iscsi_process_text_reply(struct iscsi_context *iscsi, + struct iscsi_pdu *pdu, + const unsigned char *hdr, int size); +int iscsi_process_logout_reply(struct iscsi_context *iscsi, + struct iscsi_pdu *pdu, + const unsigned char *hdr, int size); +int iscsi_process_scsi_reply(struct iscsi_context *iscsi, + struct iscsi_pdu *pdu, + const unsigned char *hdr, int size); +int iscsi_process_scsi_data_in(struct iscsi_context *iscsi, + struct iscsi_pdu *pdu, + const unsigned char *hdr, int size, + int *is_finished); +int iscsi_process_nop_out_reply(struct iscsi_context *iscsi, + struct iscsi_pdu *pdu, + const unsigned char *hdr, int size); + +void iscsi_set_error(struct iscsi_context *iscsi, const char *error_string, + ...); + +unsigned long crc32c(char *buf, int len); + +void iscsi_cbdata_steal_scsi_task(struct scsi_task *task); diff --git a/block/iscsi/iscsi.h b/block/iscsi/iscsi.h new file mode 100644 index 0000000..5e4c2cc --- /dev/null +++ b/block/iscsi/iscsi.h @@ -0,0 +1,433 @@ +/* + Copyright (C) 2010 by Ronnie Sahlberg + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +struct iscsi_context; +struct sockaddr; + + +char *iscsi_get_error(struct iscsi_context *iscsi); + +/* + * Returns the file descriptor that libiscsi uses. + */ +int iscsi_get_fd(struct iscsi_context *iscsi); + +/* + * Returns which events that we need to poll for for the iscsi file descriptor. + */ +int iscsi_which_events(struct iscsi_context *iscsi); + +/* + * Called to process the events when events become available for the iscsi + * file descriptor. + */ +int iscsi_service(struct iscsi_context *iscsi, int revents); + + + +/* + * Create a context for an ISCSI session. + * Initiator_name is the iqn name we want to identify to the target as. + * + * Returns: + * 0: success + * <0: error + */ +struct iscsi_context *iscsi_create_context(const char *initiator_name); + +/* + * Destroy an existing ISCSI context and tear down any existing connection. + * Callbacks for any command in flight will be invoked with + * ISCSI_STATUS_CANCELLED. + * + * Returns: + * 0: success + * <0: error + */ +int iscsi_destroy_context(struct iscsi_context *iscsi); + +/* + * Set an optional alias name to identify with when connecting to the target + * + * Returns: + * 0: success + * <0: error + */ +int iscsi_set_alias(struct iscsi_context *iscsi, const char *alias); + +/* + * Set the iqn name of the taqget to login to. + * The target name must be set before a normal-login can be initiated. + * Only discovery-logins are possible without setting the target iqn name. + * + * Returns: + * 0: success + * <0: error + */ +int iscsi_set_targetname(struct iscsi_context *iscsi, const char *targetname); + + +/* Types of icsi sessions. Discovery sessions are used to query for what + * targets exist behin the portal connected to. Normal sessions are used to + * log in and do I/O to the SCSI LUNs + */ +enum iscsi_session_type { + ISCSI_SESSION_DISCOVERY = 1, + ISCSI_SESSION_NORMAL = 2 +}; + +/* + * Set the session type for a scsi context. + * Session type can only be set/changed while the iscsi context is not + * logged in to a target. + * + * Returns: + * 0: success + * <0: error + */ +int iscsi_set_session_type(struct iscsi_context *iscsi, + enum iscsi_session_type session_type); + + +/* + * Types of header digest we support. Default is NONE + */ +enum iscsi_header_digest { + ISCSI_HEADER_DIGEST_NONE = 0, + ISCSI_HEADER_DIGEST_NONE_CRC32C = 1, + ISCSI_HEADER_DIGEST_CRC32C_NONE = 2, + ISCSI_HEADER_DIGEST_CRC32C = 3 +}; + +/* + * Set the desired header digest for a scsi context. + * Header digest can only be set/changed while the iscsi context is not + * logged in to a target. + * + * Returns: + * 0: success + * <0: error + */ +int iscsi_set_header_digest(struct iscsi_context *iscsi, + enum iscsi_header_digest header_digest); + + +/* + * check if the context is logged in or not + */ +int iscsi_is_logged_in(struct iscsi_context *iscsi); + + +enum scsi_status { + SCSI_STATUS_GOOD = 0, + SCSI_STATUS_CHECK_CONDITION = 2, + SCSI_STATUS_CANCELLED = 0x0f000000, + SCSI_STATUS_ERROR = 0x0f000001 +}; + + +/* + * Generic callback for completion of iscsi_*_async(). + * command_data depends on status. + */ +typedef void (*iscsi_command_cb)(struct iscsi_context *iscsi, int status, + void *command_data, void *private_data); + + + +/* + * Asynchronous call to connect a TCP connection to the target-host/port + * + * Returns: + * 0 if the call was initiated and a connection will be attempted. Result of + * the connection will be reported through the callback function. + * <0 if there was an error. The callback function will not be invoked. + * + * This command is unique in that the callback can be invoked twice. + * + * Callback parameters : + * status can be either of : + * ISCSI_STATUS_GOOD : Connection was successful. Command_data is NULL. + * In this case the callback will be invoked a + * second time once the connection is torn down. + * + * ISCSI_STATUS_ERROR : Either failed to establish the connection, or + * an already established connection has failed + * with an error. + * + * The callback will NOT be invoked if the session is explicitely torn down + * through a call to iscsi_disconnect() or iscsi_destroy_context(). + */ +int iscsi_connect_async(struct iscsi_context *iscsi, const char *portal, + iscsi_command_cb cb, void *private_data); + +/* + * Synchronous call to connect a TCP connection to the target-host/port + * + * Returns: + * 0 if connected successfully. + * <0 if there was an error. + * + */ +int iscsi_connect_sync(struct iscsi_context *iscsi, const char *portal); + + +/* + * Asynchronous call to connect a lun + * This function will connect to the portal, login, and verify that the lun + * is available. + * + * Returns: + * 0 if the call was initiated and a connection will be attempted. Result + * of the connection will be reported through the callback function. + * <0 if there was an error. The callback function will not be invoked. + * + * This command is unique in that the callback can be invoked twice. + * + * Callback parameters : + * status can be either of : + * ISCSI_STATUS_GOOD : Connection was successful. Command_data is NULL. + * In this case the callback will be invoked a + * second time once the connection is torn down. + * + * ISCSI_STATUS_ERROR : Either failed to establish the connection, or + * an already established connection has failed + * with an error. + * + * The callback will NOT be invoked if the session is explicitely torn down + * through a call to iscsi_disconnect() or iscsi_destroy_context(). + */ +int iscsi_full_connect_async(struct iscsi_context *iscsi, const char *portal, + int lun, iscsi_command_cb cb, void *private_data); + +/* + * Synchronous call to connect a lun + * This function will connect to the portal, login, and verify that the lun + * is available. + * + * Returns: + * 0 if the cconnect was successful. + * <0 if there was an error. + */ +int iscsi_full_connect_sync(struct iscsi_context *iscsi, const char *portal, + int lun); + +/* + * Disconnect a connection to a target. + * You can not disconnect while being logged in to a target. + * + * Returns: + * 0 disconnect was successful + * <0 error + */ +int iscsi_disconnect(struct iscsi_context *iscsi); + +/* + * Asynchronous call to perform an ISCSI login. + * + * Returns: + * 0 if the call was initiated and a login will be attempted. Result of the + * login will be reported through the callback function. + * <0 if there was an error. The callback function will not be invoked. + * + * Callback parameters : + * status can be either of : + * ISCSI_STATUS_GOOD : login was successful. Command_data is always + * NULL. + * ISCSI_STATUS_CANCELLED: login was aborted. Command_data is NULL. + * ISCSI_STATUS_ERROR : login failed. Command_data is NULL. + */ +int iscsi_login_async(struct iscsi_context *iscsi, iscsi_command_cb cb, + void *private_data); + +/* + * Synchronous call to perform an ISCSI login. + * + * Returns: + * 0 if the login was successful + * <0 if there was an error. + */ +int iscsi_login_sync(struct iscsi_context *iscsi); + + +/* + * Asynchronous call to perform an ISCSI logout. + * + * Returns: + * 0 if the call was initiated and a logout will be attempted. Result of the + * logout will be reported through the callback function. + * <0 if there was an error. The callback function will not be invoked. + * + * Callback parameters : + * status can be either of : + * ISCSI_STATUS_GOOD : logout was successful. Command_data is always + * NULL. + * ISCSI_STATUS_CANCELLED: logout was aborted. Command_data is NULL. + */ +int iscsi_logout_async(struct iscsi_context *iscsi, iscsi_command_cb cb, + void *private_data); + +/* + * Synchronous call to perform an ISCSI logout. + * + * Returns: + * 0 if the logout was successful + * <0 if there was an error. + */ +int iscsi_logout_sync(struct iscsi_context *iscsi); + + +/* + * Asynchronous call to perform an ISCSI discovery. + * + * discoveries can only be done on connected and logged in discovery sessions. + * + * Returns: + * 0 if the call was initiated and a discovery will be attempted. Result + * of the logout will be reported through the callback function. + * <0 if there was an error. The callback function will not be invoked. + * + * Callback parameters : + * status can be either of : + * ISCSI_STATUS_GOOD : Discovery was successful. Command_data is a + * pointer to a iscsi_discovery_address list of + * structures. + * This list of structures is only valid for the + * duration of the callback and all data will be + * freed once the callback returns. + * ISCSI_STATUS_CANCELLED: Discovery was aborted. Command_data is NULL. + */ +int iscsi_discovery_async(struct iscsi_context *iscsi, iscsi_command_cb cb, + void *private_data); + +struct iscsi_discovery_address { + struct iscsi_discovery_address *next; + const char *target_name; + const char *target_address; +}; + +/* + * Asynchronous call to perform an ISCSI NOP-OUT call + * + * Returns: + * 0 if the call was initiated and a nop-out will be attempted. Result will + * be reported through the callback function. + * <0 if there was an error. The callback function will not be invoked. + * + * Callback parameters : + * status can be either of : + * ISCSI_STATUS_GOOD : NOP-OUT was successful and the server responded + * with a NOP-IN callback_data is a iscsi_data + * structure containing the data returned from + * the server. + * ISCSI_STATUS_CANCELLED: Discovery was aborted. Command_data is NULL. + */ +int iscsi_nop_out_async(struct iscsi_context *iscsi, iscsi_command_cb cb, + unsigned char *data, int len, void *private_data); + + +/* These are the possible status values for the callbacks for scsi commands. + * The content of command_data depends on the status type. + * + * status : + * ISCSI_STATUS_GOOD the scsi command completed successfullt on the target. + * If this scsi command returns DATA-IN, that data is stored in an scsi_task + * structure returned in the command_data parameter. This buffer will be + * automatically freed once the callback returns. + * + * ISCSI_STATUS_CHECK_CONDITION the scsi command failed with a scsi sense. + * Command_data contains a struct scsi_task. When the callback returns, + * this buffer will automatically become freed. + * + * ISCSI_STATUS_CANCELLED the scsi command was aborted. Command_data is + * NULL. + * + * ISCSI_STATUS_ERROR the command failed. Command_data is NULL. + */ + + + +struct iscsi_data { + int size; + unsigned char *data; +}; + + +/* + * Async commands for SCSI + */ +struct scsi_task; +int iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, + struct scsi_task *task, iscsi_command_cb cb, + struct iscsi_data *data, void *private_data); + +int iscsi_reportluns_async(struct iscsi_context *iscsi, int report_type, + int alloc_len, iscsi_command_cb cb, + void *private_data); +int iscsi_testunitready_async(struct iscsi_context *iscsi, int lun, + iscsi_command_cb cb, void *private_data); +int iscsi_inquiry_async(struct iscsi_context *iscsi, int lun, int evpd, + int page_code, int maxsize, iscsi_command_cb cb, + void *private_data); +int iscsi_readcapacity10_async(struct iscsi_context *iscsi, int lun, int lba, + int pmi, iscsi_command_cb cb, + void *private_data); +int iscsi_synchronizecache10_async(struct iscsi_context *iscsi, int lun, + int lba, int num_blocks, int syncnv, + int immed, iscsi_command_cb cb, + void *private_data); + +int iscsi_read10_async(struct iscsi_context *iscsi, int lun, int lba, + int datalen, int blocksize, iscsi_command_cb cb, + void *private_data); +int iscsi_write10_async(struct iscsi_context *iscsi, int lun, + unsigned char *data, int datalen, int lba, int fua, + int fuanv, int blocksize, iscsi_command_cb cb, + void *private_data); +int iscsi_modesense6_async(struct iscsi_context *iscsi, int lun, int dbd, + int pc, int page_code, int sub_page_code, + unsigned char alloc_len, iscsi_command_cb cb, + void *private_data); + + + + +/* + * Sync commands for SCSI + */ +struct scsi_task * +iscsi_scsi_command_sync(struct iscsi_context *iscsi, int lun, + struct scsi_task *task, struct iscsi_data *data); + +struct scsi_task * +iscsi_reportluns_sync(struct iscsi_context *iscsi, int report_type, + int alloc_len); + +struct scsi_task * +iscsi_testunitready_sync(struct iscsi_context *iscsi, int lun); + +struct scsi_task * +iscsi_inquiry_sync(struct iscsi_context *iscsi, int lun, int evpd, + int page_code, int maxsize); + +struct scsi_task * +iscsi_readcapacity10_sync(struct iscsi_context *iscsi, int lun, int lba, + int pmi); + +struct scsi_task * +iscsi_synchronizecache10_sync(struct iscsi_context *iscsi, int lun, int lba, + int num_blocks, int syncnv, int immed); diff --git a/block/iscsi/scsi-lowlevel.h b/block/iscsi/scsi-lowlevel.h new file mode 100644 index 0000000..3778e13 --- /dev/null +++ b/block/iscsi/scsi-lowlevel.h @@ -0,0 +1,369 @@ +/* + Copyright (C) 2010 by Ronnie Sahlberg + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#define SCSI_CDB_MAX_SIZE 16 + +enum scsi_opcode { + SCSI_OPCODE_TESTUNITREADY = 0x00, + SCSI_OPCODE_INQUIRY = 0x12, + SCSI_OPCODE_MODESENSE6 = 0x1a, + SCSI_OPCODE_READCAPACITY10 = 0x25, + SCSI_OPCODE_READ10 = 0x28, + SCSI_OPCODE_WRITE10 = 0x2A, + SCSI_OPCODE_SYNCHRONIZECACHE10 = 0x35, + SCSI_OPCODE_REPORTLUNS = 0xA0 +}; + +/* sense keys */ +enum scsi_sense_key { + SCSI_SENSE_NO_SENSE = 0x00, + SCSI_SENSE_RECOVERED_ERROR = 0x01, + SCSI_SENSE_NOT_READY = 0x02, + SCSI_SENSE_MEDIUM_ERROR = 0x03, + SCSI_SENSE_HARDWARE_ERROR = 0x04, + SCSI_SENSE_ILLEGAL_REQUEST = 0x05, + SCSI_SENSE_UNIT_ATTENTION = 0x06, + SCSI_SENSE_DATA_PROTECTION = 0x07, + SCSI_SENSE_BLANK_CHECK = 0x08, + SCSI_SENSE_VENDOR_SPECIFIC = 0x09, + SCSI_SENSE_COPY_ABORTED = 0x0a, + SCSI_SENSE_COMMAND_ABORTED = 0x0b, + SCSI_SENSE_OBSOLETE_ERROR_CODE = 0x0c, + SCSI_SENSE_OVERFLOW_COMMAND = 0x0d, + SCSI_SENSE_MISCOMPARE = 0x0e +}; + +const char *scsi_sense_key_str(int key); + +/* ascq */ +#define SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB 0x2400 +#define SCSI_SENSE_ASCQ_LOGICAL_UNIT_NOT_SUPPORTED 0x2500 +#define SCSI_SENSE_ASCQ_BUS_RESET 0x2900 + +const char *scsi_sense_ascq_str(int ascq); + + +enum scsi_xfer_dir { + SCSI_XFER_NONE = 0, + SCSI_XFER_READ = 1, + SCSI_XFER_WRITE = 2 +}; + +struct scsi_reportluns_params { + int report_type; +}; +struct scsi_readcapacity10_params { + int lba; + int pmi; +}; +struct scsi_inquiry_params { + int evpd; + int page_code; +}; +struct scsi_modesense6_params { + int dbd; + int pc; + int page_code; + int sub_page_code; +}; + +struct scsi_sense { + unsigned char error_type; + enum scsi_sense_key key; + int ascq; +}; + +struct scsi_data { + int size; + unsigned char *data; +}; + +struct scsi_allocated_memory { + struct scsi_allocated_memory *next; + void *ptr; +}; + +struct scsi_task { + int status; + + int cdb_size; + int xfer_dir; + int expxferlen; + unsigned char cdb[SCSI_CDB_MAX_SIZE]; + union { + struct scsi_readcapacity10_params readcapacity10; + struct scsi_reportluns_params reportluns; + struct scsi_inquiry_params inquiry; + struct scsi_modesense6_params modesense6; + } params; + + struct scsi_sense sense; + struct scsi_data datain; + struct scsi_allocated_memory *mem; + + void *ptr; +}; + +void scsi_free_scsi_task(struct scsi_task *task); +void scsi_set_task_private_ptr(struct scsi_task *task, void *ptr); +void *scsi_get_task_private_ptr(struct scsi_task *task); + +/* + * TESTUNITREADY + */ +struct scsi_task *scsi_cdb_testunitready(void); + + +/* + * REPORTLUNS + */ +#define SCSI_REPORTLUNS_REPORT_ALL_LUNS 0x00 +#define SCSI_REPORTLUNS_REPORT_WELL_KNOWN_ONLY 0x01 +#define SCSI_REPORTLUNS_REPORT_AVAILABLE_LUNS_ONLY 0x02 + +struct scsi_reportluns_list { + uint32_t num; + uint16_t luns[0]; +}; + +struct scsi_task *scsi_reportluns_cdb(int report_type, int alloc_len); + +/* + * READCAPACITY10 + */ +struct scsi_readcapacity10 { + uint32_t lba; + uint32_t block_size; +}; +struct scsi_task *scsi_cdb_readcapacity10(int lba, int pmi); + + +/* + * INQUIRY + */ +enum scsi_inquiry_peripheral_qualifier { + SCSI_INQUIRY_PERIPHERAL_QUALIFIER_CONNECTED = 0x00, + SCSI_INQUIRY_PERIPHERAL_QUALIFIER_DISCONNECTED = 0x01, + SCSI_INQUIRY_PERIPHERAL_QUALIFIER_NOT_SUPPORTED = 0x03 +}; + +const char *scsi_devqualifier_to_str( + enum scsi_inquiry_peripheral_qualifier qualifier); + +enum scsi_inquiry_peripheral_device_type { + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS = 0x00, + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_SEQUENTIAL_ACCESS = 0x01, + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_PRINTER = 0x02, + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_PROCESSOR = 0x03, + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_WRITE_ONCE = 0x04, + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_MMC = 0x05, + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_SCANNER = 0x06, + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_OPTICAL_MEMORY = 0x07, + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_MEDIA_CHANGER = 0x08, + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_COMMUNICATIONS = 0x09, + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_STORAGE_ARRAY_CONTROLLER = 0x0c, + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_ENCLOSURE_SERVICES = 0x0d, + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_SIMPLIFIED_DIRECT_ACCESS = 0x0e, + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_OPTICAL_CARD_READER = 0x0f, + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_BRIDGE_CONTROLLER = 0x10, + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_OSD = 0x11, + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_AUTOMATION = 0x12, + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_SEQURITY_MANAGER = 0x13, + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_WELL_KNOWN_LUN = 0x1e, + SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_UNKNOWN = 0x1f +}; + +const char *scsi_devtype_to_str(enum scsi_inquiry_peripheral_device_type type); + +enum scsi_version { + SCSI_VERSION_SPC = 0x03, + SCSI_VERSION_SPC2 = 0x04, + SCSI_VERSION_SPC3 = 0x05 +}; + +const char *scsi_version_to_str(enum scsi_version version); + +enum scsi_inquiry_tpgs { + SCSI_INQUIRY_TPGS_NO_SUPPORT = 0x00, + SCSI_INQUIRY_TPGS_IMPLICIT = 0x01, + SCSI_INQUIRY_TPGS_EXPLICIT = 0x02, + SCSI_INQUIRY_TPGS_IMPLICIT_AND_EXPLICIT = 0x03 +}; + +struct scsi_inquiry_standard { + enum scsi_inquiry_peripheral_qualifier periperal_qualifier; + enum scsi_inquiry_peripheral_device_type periperal_device_type; + int rmb; + int version; + int normaca; + int hisup; + int response_data_format; + + int sccs; + int acc; + int tpgs; + int threepc; + int protect; + + int encserv; + int multip; + int addr16; + int wbus16; + int sync; + int cmdque; + + int clocking; + int qas; + int ius; + + char vendor_identification[8+1]; + char product_identification[16+1]; + char product_revision_level[4+1]; +}; + +enum scsi_inquiry_pagecode { + SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES = 0x00, + SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER = 0x80, + SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION = 0x83, + SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS = 0xB1 +}; + +const char *scsi_inquiry_pagecode_to_str(int pagecode); + +struct scsi_inquiry_supported_pages { + enum scsi_inquiry_peripheral_qualifier periperal_qualifier; + enum scsi_inquiry_peripheral_device_type periperal_device_type; + enum scsi_inquiry_pagecode pagecode; + + int num_pages; + unsigned char *pages; +}; + +struct scsi_inquiry_block_device_characteristics { + enum scsi_inquiry_peripheral_qualifier periperal_qualifier; + enum scsi_inquiry_peripheral_device_type periperal_device_type; + enum scsi_inquiry_pagecode pagecode; + + int medium_rotation_rate; +}; + +struct scsi_task *scsi_cdb_inquiry(int evpd, int page_code, int alloc_len); + +struct scsi_inquiry_unit_serial_number { + enum scsi_inquiry_peripheral_qualifier periperal_qualifier; + enum scsi_inquiry_peripheral_device_type periperal_device_type; + enum scsi_inquiry_pagecode pagecode; + + char *usn; +}; + +enum scsi_protocol_identifier { + SCSI_PROTOCOL_IDENTIFIER_FIBRE_CHANNEL = 0x00, + SCSI_PROTOCOL_IDENTIFIER_PARALLEL_SCSI = 0x01, + SCSI_PROTOCOL_IDENTIFIER_SSA = 0x02, + SCSI_PROTOCOL_IDENTIFIER_IEEE_1394 = 0x03, + SCSI_PROTOCOL_IDENTIFIER_RDMA = 0x04, + SCSI_PROTOCOL_IDENTIFIER_ISCSI = 0x05, + SCSI_PROTOCOL_IDENTIFIER_SAS = 0x06, + SCSI_PROTOCOL_IDENTIFIER_ADT = 0x07, + SCSI_PROTOCOL_IDENTIFIER_ATA = 0x08 +}; + +const char *scsi_protocol_identifier_to_str(int identifier); + +enum scsi_codeset { + SCSI_CODESET_BINARY = 0x01, + SCSI_CODESET_ASCII = 0x02, + SCSI_CODESET_UTF8 = 0x03 +}; + +const char *scsi_codeset_to_str(int codeset); + +enum scsi_association { + SCSI_ASSOCIATION_LOGICAL_UNIT = 0x00, + SCSI_ASSOCIATION_TARGET_PORT = 0x01, + SCSI_ASSOCIATION_TARGET_DEVICE = 0x02 +}; + +const char *scsi_association_to_str(int association); + +enum scsi_designator_type { + SCSI_DESIGNATOR_TYPE_VENDOR_SPECIFIC = 0x00, + SCSI_DESIGNATOR_TYPE_T10_VENDORT_ID = 0x01, + SCSI_DESIGNATOR_TYPE_EUI_64 = 0x02, + SCSI_DESIGNATOR_TYPE_NAA = 0x03, + SCSI_DESIGNATOR_TYPE_RELATIVE_TARGET_PORT = 0x04, + SCSI_DESIGNATOR_TYPE_TARGET_PORT_GROUP = 0x05, + SCSI_DESIGNATOR_TYPE_LOGICAL_UNIT_GROUP = 0x06, + SCSI_DESIGNATOR_TYPE_MD5_LOGICAL_UNIT_IDENTIFIER = 0x07, + SCSI_DESIGNATOR_TYPE_SCSI_NAME_STRING = 0x08 +}; + +const char *scsi_designator_type_to_str(int association); + +struct scsi_inquiry_device_designator { + struct scsi_inquiry_device_designator *next; + + enum scsi_protocol_identifier protocol_identifier; + enum scsi_codeset code_set; + int piv; + enum scsi_association association; + enum scsi_designator_type designator_type; + int designator_length; + char *designator; +}; + +struct scsi_inquiry_device_identification { + enum scsi_inquiry_peripheral_qualifier periperal_qualifier; + enum scsi_inquiry_peripheral_device_type periperal_device_type; + enum scsi_inquiry_pagecode pagecode; + + struct scsi_inquiry_device_designator *designators; +}; + +/* + * MODESENSE6 + */ +enum scsi_modesense_page_control { + SCSI_MODESENSE_PC_CURRENT = 0x00, + SCSI_MODESENSE_PC_CHANGEABLE = 0x01, + SCSI_MODESENSE_PC_DEFAULT = 0x02, + SCSI_MODESENSE_PC_SAVED = 0x03 +}; + +enum scsi_modesense_page_code { + SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES = 0x3f +}; + +struct scsi_task *scsi_cdb_modesense6(int dbd, + enum scsi_modesense_page_control pc, + enum scsi_modesense_page_code page_code, + int sub_page_code, + unsigned char alloc_len); + + + + +int scsi_datain_getfullsize(struct scsi_task *task); +void *scsi_datain_unmarshall(struct scsi_task *task); + +struct scsi_task *scsi_cdb_read10(int lba, int xferlen, int blocksize); +struct scsi_task *scsi_cdb_write10(int lba, int xferlen, int fua, int fuanv, + int blocksize); + +struct scsi_task *scsi_cdb_synchronizecache10(int lba, int num_blocks, + int syncnv, int immed); diff --git a/block/iscsi/slist.h b/block/iscsi/slist.h new file mode 100644 index 0000000..0e9dc42 --- /dev/null +++ b/block/iscsi/slist.h @@ -0,0 +1,51 @@ +/* + Copyright (C) 2010 by Ronnie Sahlberg + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#define SLIST_ADD(list, item) \ + do { \ + (item)->next = (*list); \ + (*list) = (item); \ + } while (0); + +#define SLIST_ADD_END(list, item) \ + if ((*list) == NULL) { \ + SLIST_ADD((list), (item)); \ + } else { \ + void *head = (*list); \ + while ((*list)->next) \ + (*list) = (*list)->next; \ + (*list)->next = (item); \ + (item)->next = NULL; \ + (*list) = head; \ + } + +#define SLIST_REMOVE(list, item) \ + if ((*list) == (item)) { \ + (*list) = (item)->next; \ + } else { \ + void *head = (*list); \ + while ((*list)->next && (*list)->next != (item)) \ + (*list) = (*list)->next; \ + if ((*list)->next != NULL) { \ + (*list)->next = (*list)->next->next; \ + } \ + (*list) = head; \ + } + + + +