mgmt_create.c revision 36c5fee33fa8b822175d410202aebcf592c8d342
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <ctype.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <strings.h>
#include <sys/efi_partition.h>
#include "xml.h"
#include "queue.h"
#include "target.h"
#include "iscsi_cmd.h"
#include "utility.h"
#include "errcode.h"
#include "t10_spc.h"
extern char *getfullrawname();
static char *create_target(xml_node_t *);
static char *create_initiator(xml_node_t *);
static char *create_tpgt(xml_node_t *);
err_code_t *code);
/*
* []----
* | create_func -- Branch out to appropriate object create function
* []----
*/
/*ARGSUSED*/
void
{
xml_node_t *x;
char msgbuf[80],
} else {
x = p->x_child;
reply_msg = create_target(x);
reply_msg = create_initiator(x);
reply_msg = create_tpgt(x);
} else {
"Unknown object '%s' for create element",
x->x_name);
}
}
}
static char *
{
int lun = 0, /* default to LUN 0 */
i;
xml_node_t *n,
*c,
*l;
goto error;
}
/*
* We've got to have a name element or all bets are off.
*/
goto error;
}
/*
* RFC3722 states that names must be one of:
* (1) a..z
* (2) A..Z
* (3) 0-9
* or
* (4) ':', '.', '-'
* If it's an upper case character is must be made lower
* case.
*/
goto error;
}
/*
* If a type hasn't been specified default to disk emulation.
* We use strdup() since at the end of this routine the code
* is expecting to free 'type' along with other strings.
*/
}
goto error;
}
/*
* If a backing store has been provided we don't
* need the size since we can determine that from
* a READ_CAPACITY command which everyone issues.
*
* NOTE: strdup is used here, since at the end
* of this routine any of the string pointers which
* are non-NULL get freed.
*/
} else {
goto error;
}
}
goto error;
}
/*
* See if we already have a local target name created. If so,
* the user is most likely wanting to create another LUN for this
* target. Checking to see if there's a duplicate LUN will be
* done later.
*/
break;
}
if (n == NULL) {
if (lun != 0) {
goto error;
}
goto error;
}
goto error;
}
(void) xml_add_child(n, c);
(void) xml_add_child(c, l);
(void) xml_add_child(n, c);
(void) xml_add_child(n, c);
}
(void) xml_add_child(targets_config, n);
} else {
if (xml_find_value_str(n, XML_ELEMENT_INAME,
goto error;
}
goto error;
}
(void) xml_add_child(c, l);
}
goto error;
/*
* The first LU will have created the directory and
* symbolic link. Remove those on error.
*/
xml_tree_free(n);
} else
xml_remove_child(c, l, MatchBoth);
return (msg);
}
static char *
{
*iscsi_name = NULL;
*n,
*c;
goto error;
}
goto error;
}
goto error;
}
goto error;
}
}
(void) xml_add_child(n, c);
(void) xml_add_child(main_config, n);
if (name)
if (iscsi_name)
return (msg);
}
static char *
{
*n;
int tpgt_val;
goto error;
}
/* ---- Validation checks ---- */
goto error;
}
goto error;
}
}
(void) xml_add_child(main_config, n);
if (tpgt)
return (msg);
}
/*
* []------------------------------------------------------------------[]
* | Utility functions used by the routines above. |
* []------------------------------------------------------------------[]
*/
/*
* []----
* | create_node_name -- Creates the IQN that adhears to RFC3270
* []----
*/
static char *
{
char id_str[37],
*p;
return (NULL);
/*
* Originally we we going to use the machines MAC address and
* timestamp in hex format. This would be consistent with the
* Solaris iSCSI initiator and NAS5310. Unfortunately, someone
* pointed out that there's no requirement that the network
* interfaces be plumbed before someone attempts to create
* targets. If the networks aren't plumbed there are no MAC
* addresses available and we can't use 0 for the MAC address
* since that would introduce the probability of non-unique
* IQN names.
*/
free(p);
return (NULL);
}
return (p);
}
/*
* []----
* | create_target_dir -- create the target directory
* []----
*/
static Boolean_t
{
char path[MAXPATHLEN],
return (False);
return (False);
/*
* This symbolic link is here for convenience and nothing more, so if
* if fails. Oh well.
*/
return (True);
}
/*
* []----
* | create_lun -- given type, lun, size, backing create LU and params
* []----
*/
static Boolean_t
{
int fd = -1,
rpm = DEFAULT_RPM,
spt = DEFAULT_SPT,
char *vid = DEFAULT_VID,
*pid = DEFAULT_PID,
/*
* after calling stroll_multipler it's an error for size to be
* 0, if and only if, the size_str doesn't equal "0". The administrator
* may want the code to determine the size. This would be the case
* when the administrator has provide a backing store which exists.
*/
*code = ERR_INVALID_SIZE;
return (False);
}
if ((size % 512) != 0) {
return (False);
}
/*
* Make sure we're not trying to recreate an existing LU.
*/
*code = ERR_LUN_EXISTS;
return (False);
}
return (False);
}
goto error;
#ifndef _LP64
goto error;
#else
goto error;
#endif
goto error;
goto error;
}
goto error;
}
/*
* Wait to set the size until here because it may be unknown until
* the possible backing store has been setup.
*/
}
goto error;
}
*code = ERR_SUCCESS;
return (True);
if (fd == -1)
return (False);
}
/*
* []----
* | create_lun_common -- create LU and start provisioning if needed
* |
* | This function is common to both the tape and disk emulation
* | code.
* []----
*/
static Boolean_t
{
struct stat s;
int fd = -1;
char path[MAXPATHLEN],
buf[512];
*c;
/*
* Touch the last block of the file which will cause file systems
* to understand the intent of the file to be a certain size. The
* space isn't allocated, but the daemon can then mmap in this file
* and start writing to it.
*/
goto error;
*code = ERR_FILE_TO_BIG;
else
goto error;
}
/*
* Set the fd back to -1 so that if an error occurs we don't
* attempt to close this device twice. This could be an issue
* if another thread opened a file right after we closed this
* one and the system reused the file descriptor. During an
* error we would then close another threads file which would
* be ugly, not to mention difficult to track down.
*/
fd = -1;
goto error;
}
/*
* If the backing store is a regular file and the default is
* used which initializes the file instead of sparse allocation
* go ahead a set things up.
*/
/*
* Attempt to see if there is enough space currently
* for the LU. The initialization might still fail
* with "out of space" because someone else is
* consuming space while the initialization is occuring.
* Nothing we can do about that.
*/
"GEN statvfs failed for %s", path);
goto error;
"GEN Not enough space for LU");
*code = ERR_FILE_TO_BIG;
goto error;
}
/*
* Run the initialization thread in the background so that
* the administrator doesn't have to wait which for UFS could
* be a long time on a large LU.
*/
tp->q = queue_alloc();
/*
* As soon as the thread starts it will send a simple
* ACK to it's own queue that we can look for. When
* we see this message we know that the thread has
* started and it's been added to the provisioning
* list. If this were not done it's possible for someone
* to create and delete a target within a script and
* have the delete run and fail to find the provision
* thread in the list.
*/
}
} else {
while (xmlTextReaderRead(r) == 1)
break;
xml_tree_free(c);
"GEN%d failed to dump out params", lun);
goto error;
}
/*
* The thick_provo_start will issue an inventory
* change once it's finished.
*/
} else
return (False);
}
return (True);
if (fd != -1)
return (False);
}
static Boolean_t
{
return (True);
else
return (False);
}
static Boolean_t
{
return (True);
else
return (False);
}
/*
* []----
* | setup_alt_backing -- use backing store link for regular file lun
* |
* | If the size is zero, then the administrator MUST have
* | specified a backing store to use.
* | If the size is non-zero and the backing store doesn't exist it will
* | be created. Also a tag will be added indicating that during removal
* | the backing store should be deleted as well.
* []----
*/
static Boolean_t
{
struct stat s;
char *raw_name,
buf[512];
int slice,
fd;
/*
* Error checking regarding size and backing store has already
* been done. If the backing store is null at this point everything
* is okay so just return True.
*/
return (True);
if (*size == 0) {
return (False);
} else {
0600)) < 0) {
return (False);
}
}
} else if (*size != 0) {
return (False);
return (False);
}
} else {
return (False);
}
} else {
return (False);
}
return (False);
}
return (True);
}
/*
* []----
* | validate_raw_backing -- check that device is full partition
* |
* | The size of the device will be returned in rtn_size in bytes.
* |
* | Need to guarantee that the backing store for a raw device is:
* | (a) character device
* | (b) Not buffered
* | Don't want this host to have data which is not flushed
* | out during a write since a multiple path access to
* | the backing store would be possible meaning we'd have
* | cache issue.
* | To speed things up we use asynchronous I/O which means
* | the path has to have access to the entire device through
* | the partition table. If not, some client will issue a
* | READ_CAPACITY command, but not be able to access all of
* | the data.
* []----
*/
static Boolean_t
{
struct stat s;
char buf[512];
int fd;
struct uscsi_cmd u;
struct scsi_extended_sense sense;
struct scsi_capacity cap;
struct scsi_capacity_16 cap16;
return (False);
return (False);
}
return (False);
}
bzero(&u, sizeof (u));
u.uscsi_cdblen = CDB_GROUP1;
u.uscsi_buflen = sizeof (cap);
u.uscsi_rqbuf = (char *)&sense;
u.uscsi_rqlen = sizeof (sense);
goto error;
}
bzero(&u, sizeof (u));
/*
* The device is to large for the 10byte CDB.
* Using the larger 16byte read capacity command
*/
u.uscsi_cdblen = CDB_GROUP4;
u.uscsi_buflen = sizeof (cap16);
u.uscsi_rqbuf = (char *)&sense;
u.uscsi_rqlen = sizeof (sense);
"GEN0 uscsi(READ_CAP16) failed");
goto error;
}
} else
"GEN0 Partition size != capacity(0x%llx), cc=%d, errno=%d",
goto error;
} else {
}
return (rval);
}