/*
* 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_err(__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_err(__FILE__, __LINE__, "index mismatch\n");
return -1;
}
i += 4;
if (ISCSI_NTOHS(*(uint16_t *) (data + i)) != len) {
iscsi_err(__FILE__, __LINE__, "len mismatch\n");
return -1;
}
i += 2;
iscsi_trace(TRACE_DEBUG, "page 0x%x, index %u, len %u\n", page, n, len);
memcpy(val, data + i, len);
i += len;
}
iscsi_trace(TRACE_DEBUG, "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_err(__FILE__, __LINE__, "osd_exec() failed\n");
return -1;
}
if (extract_attribute(0x40000001, 0x1, 4, get_data, 14, GroupID) == -1) {
iscsi_err(__FILE__, __LINE__, "extract_attributes() failed\n");
return -1;
}
*GroupID = ISCSI_NTOHL(*GroupID);
iscsi_trace(TRACE_OSD, "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_err(__FILE__, __LINE__, "osd_exec() failed\n");
return -1;
}
if (extract_attribute(0x00000001, 0x2, 8, get_data, 18, UserID) == -1) {
iscsi_err(__FILE__, __LINE__, "extract_attributes() failed\n");
return -1;
}
*UserID = ISCSI_NTOHLL(*UserID);
iscsi_trace(TRACE_OSD, "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_err(__FILE__, __LINE__, "osd_exec() failed\n");
return -1;
}
iscsi_trace(TRACE_OSD, "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_err(__FILE__, __LINE__, "osd_exec() failed\n");
return -1;
}
iscsi_trace(TRACE_OSD, "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, "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_err(__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, "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_err(__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, "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_err(__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_err(__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, "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, "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_err(__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_err(__FILE__, __LINE__, "osd_exec() failed\n");
return -1;
}
memcpy(value, buffer + 10, alloc_len);
if (buffer)
iscsi_free_atomic(buffer);
return 0;
}