NetBSD-5.0.2/dist/iscsi/src/osd_ops.c

/*
 * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or
 * using the software you agree to this license. If you do not agree to this license, do not download, install,
 * copy or use the software.
 *
 * Intel License Agreement
 *
 * Copyright (c) 2002, Intel Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 * the following conditions are met:
 *
 * -Redistributions of source code must retain the above copyright notice, this list of conditions and the
 *  following disclaimer.
 *
 * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 *  following disclaimer in the documentation and/or other materials provided with the distribution.
 *
 * -The name of Intel Corporation may not be used to endorse or promote products derived from this software
 *  without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 INTEL 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.
 */

/*
 * Transport-independent Methods
 */
#include "config.h"


#include "osd.h"
#include "iscsiutil.h"
#include "compat.h"
#include "osd_ops.h"

#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif

static int 
extract_attribute(uint32_t page, uint32_t n, uint16_t len,
		  uint8_t * data, unsigned length, void *val)
{
	int             i = 0;

	for (i = 0; i < length;) {
		if (ISCSI_NTOHL(*(uint32_t *) (data + i)) != page) {
			iscsi_trace_error(__FILE__, __LINE__, "page mismatch: got 0x%x, expected 0x%x\n", ISCSI_NTOHL(*(uint32_t *) (data + i)), page);
			return -1;
		}
		i += 4;
		if (ISCSI_NTOHL(*(uint32_t *) (data + i)) != n) {
			iscsi_trace_error(__FILE__, __LINE__, "index mismatch\n");
			return -1;
		}
		i += 4;
		if (ISCSI_NTOHS(*(uint16_t *) (data + i)) != len) {
			iscsi_trace_error(__FILE__, __LINE__, "len mismatch\n");
			return -1;
		}
		i += 2;
		iscsi_trace(TRACE_DEBUG, __FILE__, __LINE__, "page 0x%x, index %u, len %u\n", page, n, len);
		memcpy(val, data + i, len);
		i += len;
	}
	iscsi_trace(TRACE_DEBUG, __FILE__, __LINE__, "parsed %i bytes\n", i);
	return i;
}


int 
osd_create_group(void *dev,
	  int (*osd_exec) (void *dev, osd_args_t * args, OSD_OPS_MEM * mem),
		 uint32_t * GroupID)
{
	osd_args_t      args;
#if 0
	uint8_t         get_list[8];
#endif
	uint8_t         get_data[14];
	OSD_OPS_MEM     mem;

	mem.recv_data = get_data;
	mem.recv_len = 14;
	mem.recv_sg = 0;

	memset(&args, 0, sizeof(osd_args_t));
	args.opcode = 0x7F;
	args.service_action = OSD_CREATE_GROUP;

#if 0
	args.length = 8;
	args.get_attributes_list_length = 8;
	*((unsigned long *) get_list) = ISCSI_HTONL(0x40000001);
	*((unsigned long *) (get_list + 4)) = ISCSI_HTONL(0x1);
	mem.send_data = get_list;
	mem.send_len = 8;
	mem.send_sg = 0;
#else
	args.get_attributes_page = 0x40000001;
	mem.send_data = NULL;
	mem.send_len = 0;
	mem.send_sg = 0;
#endif

	args.get_attributes_allocation_length = 14;
	if (osd_exec(dev, &args, &mem) != 0) {
		iscsi_trace_error(__FILE__, __LINE__, "osd_exec() failed\n");
		return -1;
	}
	if (extract_attribute(0x40000001, 0x1, 4, get_data, 14, GroupID) == -1) {
		iscsi_trace_error(__FILE__, __LINE__, "extract_attributes() failed\n");
		return -1;
	}
	*GroupID = ISCSI_NTOHL(*GroupID);
	iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "osd_create_group() OK --> GroupID 0x%x\n", *GroupID);

	return 0;
}

int 
osd_create(void *dev, uint32_t GroupID,
	   int (*osd_exec) (void *dev, osd_args_t * args, OSD_OPS_MEM * mem),
	   uint64_t * UserID)
{
	osd_args_t      args;
#if 0
	uint8_t         get_list[8];
#endif
	uint8_t         get_data[18];
	OSD_OPS_MEM     mem;

	mem.recv_data = get_data;
	mem.recv_len = 18;
	mem.recv_sg = 0;

	memset(&args, 0, sizeof(osd_args_t));
	args.opcode = 0x7F;
	args.service_action = OSD_CREATE;
	args.GroupID = GroupID;

#if 0
	args.length = 8;
	args.get_attributes_list_length = 8;
	*((unsigned long *) get_list) = ISCSI_HTONL(0x00000001);
	*((unsigned long *) (get_list + 4)) = ISCSI_HTONL(0x2);
	mem.send_data = get_list;
	mem.send_len = 8;
	mem.send_sg = 0;
#else
	args.get_attributes_page = 0x000000001;
	mem.send_data = NULL;
	mem.send_len = 0;
	mem.send_sg = 0;
#endif

	args.get_attributes_allocation_length = 18;
	if (osd_exec(dev, &args, &mem) != 0) {
		iscsi_trace_error(__FILE__, __LINE__, "osd_exec() failed\n");
		return -1;
	}
	if (extract_attribute(0x00000001, 0x2, 8, get_data, 18, UserID) == -1) {
		iscsi_trace_error(__FILE__, __LINE__, "extract_attributes() failed\n");
		return -1;
	}
	*UserID = ISCSI_NTOHLL(*UserID);
	iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "osd_create(GroupID 0x%x) OK --> UserID 0x%llx\n", GroupID, *UserID);

	return 0;
}

int 
osd_remove_group(void *dev, uint32_t GroupID,
	  int (*osd_exec) (void *dev, osd_args_t * args, OSD_OPS_MEM * mem))
{
	osd_args_t      args;
	OSD_OPS_MEM     mem;

	mem.send_data = NULL;
	mem.send_len = 0;
	mem.send_sg = 0;
	mem.recv_data = NULL;
	mem.recv_len = 0;
	mem.recv_sg = 0;

	memset(&args, 0, sizeof(osd_args_t));
	args.opcode = 0x7F;
	args.service_action = OSD_REMOVE_GROUP;
	args.GroupID = GroupID;
	if (osd_exec(dev, &args, &mem) != 0) {
		iscsi_trace_error(__FILE__, __LINE__, "osd_exec() failed\n");
		return -1;
	}
	iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "osd_remove_group(Group ID 0x%x) OK\n", GroupID);

	return 0;
}

int 
osd_remove(void *dev, uint32_t GroupID, uint64_t UserID,
	   int (*osd_exec) (void *dev, osd_args_t * args, OSD_OPS_MEM * mem))
{
	osd_args_t      args;
	OSD_OPS_MEM     mem;

	mem.send_data = NULL;
	mem.send_len = 0;
	mem.send_sg = 0;
	mem.recv_data = NULL;
	mem.recv_len = 0;
	mem.recv_sg = 0;

	memset(&args, 0, sizeof(osd_args_t));
	args.opcode = 0x7F;
	args.service_action = OSD_REMOVE;
	args.UserID = UserID;
	args.GroupID = GroupID;
	if (osd_exec(dev, &args, &mem) != 0) {
		iscsi_trace_error(__FILE__, __LINE__, "osd_exec() failed\n");
		return -1;
	}
	iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "osd_remove(GroupID 0x%x, UserID 0x%llx) OK\n", GroupID, UserID);

	return 0;
}

int 
osd_write(void *dev,
	  uint32_t GroupID, uint64_t UserID, uint64_t offset, uint64_t len, const void *send_data, int sg_len,
	  int (*osd_exec) (void *dev, osd_args_t * args, OSD_OPS_MEM * mem))
{
	osd_args_t      args;
	OSD_OPS_MEM     mem;

	iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "osd_write(GroupID 0x%x, UserID 0x%llx, Offset %llu, Len %llu)\n", GroupID, UserID, offset, len);
	mem.send_data = send_data;
	mem.send_len = len;
	mem.send_sg = sg_len;
	mem.recv_data = NULL;
	mem.recv_len = 0;
	mem.recv_sg = 0;
	memset(&args, 0, sizeof(osd_args_t));
	args.opcode = 0x7F;
	args.service_action = OSD_WRITE;
	args.GroupID = GroupID;
	args.UserID = UserID;
	args.offset = offset;
	args.length = len;
	if (osd_exec(dev, &args, &mem) != 0) {
		iscsi_trace_error(__FILE__, __LINE__, "osd_exec() failed\n");
		return -1;
	}
	return 0;
}

int 
osd_read(void *dev,
	 uint32_t GroupID, uint64_t UserID, uint64_t offset, uint64_t len, void *recv_data, int sg_len,
	 int (*osd_exec) (void *dev, osd_args_t * args, OSD_OPS_MEM * mem))
{
	osd_args_t      args;
	OSD_OPS_MEM     mem;

	iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "osd_read(GroupID 0x%x, UserID 0x%llx, Offset %llu, Len %llu)\n", GroupID, UserID, offset, len);
	mem.send_data = NULL;
	mem.send_len = 0;
	mem.send_sg = 0;
	mem.recv_data = recv_data;
	mem.recv_len = len;
	mem.recv_sg = sg_len;
	memset(&args, 0, sizeof(osd_args_t));
	args.opcode = 0x7F;
	args.service_action = OSD_READ;
	args.GroupID = GroupID;
	args.UserID = UserID;
	args.offset = offset;
	args.length = len;
	if (osd_exec(dev, &args, &mem) != 0) {
		iscsi_trace_error(__FILE__, __LINE__, "osd_exec() failed\n");
		return -1;
	}
	return 0;
}

int 
osd_set_one_attr(void *dev,
		 uint32_t GroupID, uint64_t UserID, uint32_t page, uint32_t n, uint32_t len, void *value,
	  int (*osd_exec) (void *dev, osd_args_t * args, OSD_OPS_MEM * mem))
{
	osd_args_t      args;
	OSD_OPS_MEM     mem;
	uint8_t         list[10];
#if 0
	struct iovec    sg[2];
#else
	uint8_t        *buffer = NULL;
#endif

	iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "osd_set_one_attr(GroupID 0x%x, UserID 0x%llx, Page 0x%x, Index %u, Len %u)\n",
	      GroupID, UserID, page, n, len);
	memset(&args, 0, sizeof(osd_args_t));
	args.opcode = 0x7F;
	args.service_action = OSD_SET_ATTR;
	args.GroupID = GroupID;
	args.UserID = UserID;
	args.length = 10 + len;
	args.set_attributes_list_length = 10 + len;
	*((uint32_t *) (list + 0)) = ISCSI_HTONL(page);
	*((uint32_t *) (list + 4)) = ISCSI_HTONL(n);
	*((uint16_t *) (list + 8)) = ISCSI_HTONS(len);
#if 0
	sg[0].iov_base = list;
	sg[0].iov_len = 10;
	sg[1].iov_base = value;
	sg[1].iov_len = len;
	mem.send_data = sg;
	mem.send_len = 10 + len;
	mem.send_sg = 2;
#else
	if ((buffer = iscsi_malloc_atomic(10 + len)) == NULL) {
		iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n");
		return -1;
	}
	memcpy(buffer, list, 10);
	memcpy(buffer + 10, value, len);
	mem.send_data = buffer;
	mem.send_len = 10 + len;
	mem.send_sg = 0;
#endif
	mem.recv_data = NULL;
	mem.recv_len = 0;
	mem.recv_sg = 0;

	if (osd_exec(dev, &args, &mem) != 0) {
		iscsi_trace_error(__FILE__, __LINE__, "osd_exec() failed\n");
		return -1;
	}
	if (buffer)
		iscsi_free_atomic(buffer);

	return 0;
}

int 
osd_get_one_attr(void *dev,
		 uint32_t GroupID, uint64_t UserID, uint32_t page, uint32_t n, uint32_t alloc_len,
	  int (*osd_exec) (void *dev, osd_args_t * args, OSD_OPS_MEM * mem),
		 uint16_t * len, void *value)
{
	osd_args_t      args;
	OSD_OPS_MEM     mem;
	uint8_t         list_out[8];
#if 0
	uint8_t         list_in[10];
	struct iovec    sg[2];
#else
	uint8_t        *buffer;
#endif

	iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "osd_get_one_attr(GroupID 0x%x, UserID 0x%llx, Page 0x%x, Index %u, Alloc Len %u)\n",
	      GroupID, UserID, page, n, alloc_len);
	memset(&args, 0, sizeof(osd_args_t));
	args.opcode = 0x7F;
	args.service_action = OSD_GET_ATTR;
	args.GroupID = GroupID;
	args.UserID = UserID;
	if (n) {
		args.length = 8;
		*((uint32_t *) (list_out + 0)) = ISCSI_HTONL(page);
		*((uint32_t *) (list_out + 4)) = ISCSI_HTONL(n);
		args.get_attributes_list_length = 8;
		mem.send_data = list_out;
		mem.send_len = 8;
		mem.send_sg = 0;
	} else {
		iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "requesting entire page or reference page\n");
		mem.send_data = NULL;
		mem.send_len = 0;
		mem.send_sg = 0;
		args.get_attributes_page = page;
	}
#if 0
	sg[0].iov_base = list_in;
	sg[0].iov_len = 10;
	sg[1].iov_base = value;
	sg[1].iov_len = alloc_len;
	mem.recv_data = sg;
	mem.recv_len = 10 + alloc_len;
	mem.recv_sg = 2;
#else
	if ((buffer = iscsi_malloc_atomic(10 + alloc_len)) == NULL) {
		iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n");
		return -1;
	}
	mem.recv_data = buffer;
	mem.recv_len = 10 + alloc_len;
	mem.recv_sg = 0;
#endif
	args.get_attributes_allocation_length = 10 + alloc_len;
	if (osd_exec(dev, &args, &mem) != 0) {
		iscsi_trace_error(__FILE__, __LINE__, "osd_exec() failed\n");
		return -1;
	}
	memcpy(value, buffer + 10, alloc_len);
	if (buffer)
		iscsi_free_atomic(buffer);
	return 0;
}