sbd.c revision fcf3ce441efd61da9bb2884968af01cb7c1452cc
/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/byteorder.h>
#include <stmf.h>
#include <lpif.h>
#include <stmf_ioctl.h>
#include <stmf_sbd.h>
#include <sbd_impl.h>
#include <stmf_sbd_ioctl.h>
void **result);
extern struct mod_ops mod_driverops;
static stmf_lu_provider_t *sbd_lp;
static dev_info_t *sbd_dip;
static int sbd_lu_count = 0;
static char sbd_name[] = "sbd";
static struct cb_ops sbd_cb_ops = {
sbd_open, /* open */
sbd_close, /* close */
nodev, /* strategy */
nodev, /* print */
nodev, /* dump */
nodev, /* read */
nodev, /* write */
stmf_sbd_ioctl, /* ioctl */
nodev, /* devmap */
nodev, /* mmap */
nodev, /* segmap */
nochpoll, /* chpoll */
ddi_prop_op, /* cb_prop_op */
0, /* streamtab */
CB_REV, /* rev */
nodev, /* aread */
nodev /* awrite */
};
0,
nulldev, /* identify */
nulldev, /* probe */
nodev, /* reset */
NULL, /* bus_ops */
NULL /* power */
};
#define SBD_NAME "COMSTAR SBD"
};
static struct modlinkage modlinkage = {
&modldrv,
};
int
_init(void)
{
int ret;
if (ret)
return (ret);
0, 0);
sbd_lp->lp_instance = 0;
(void) mod_remove(&modlinkage);
return (DDI_FAILURE);
}
return (0);
}
int
_fini(void)
{
int ret;
/*
* If we have registered lus, then make sure they are all offline
* if so then deregister them. This should drop the sbd_lu_count
* to zero.
*/
if (sbd_lu_count) {
/* See if all of them are offline */
return (EBUSY);
}
}
/* ok start deregistering them */
while (sbd_lu_list) {
return (EBUSY);
}
}
ASSERT(sbd_lu_count == 0);
return (EBUSY);
if (ret != 0) {
(void) stmf_register_lu_provider(sbd_lp);
return (ret);
}
return (0);
}
int
{
}
/* ARGSUSED */
static int
{
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
break;
case DDI_INFO_DEVT2INSTANCE:
break;
default:
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
static int
{
switch (cmd) {
case DDI_ATTACH:
DDI_NT_STMF_LP, 0) != DDI_SUCCESS) {
break;
}
return (DDI_SUCCESS);
}
return (DDI_FAILURE);
}
static int
{
switch (cmd) {
case DDI_DETACH:
ddi_remove_minor_node(dip, 0);
return (DDI_SUCCESS);
}
return (DDI_FAILURE);
}
/* ARGSUSED */
static int
{
return (EINVAL);
return (0);
}
/* ARGSUSED */
static int
{
return (0);
}
/*
* The ioctl code will be re written once the lun mapping and masking
* has been implemented and ioctl definitions have been cleanned up.
*/
void *
{
void *ptr;
uint32_t s;
return (NULL);
return (NULL);
return (ptr);
}
int
{
int *s = (int *)ptr;
int ret = 0;
}
return (ret);
}
/* ARGSUSED */
static int
{
void *p;
int ret = 0;
int ret1;
int cnt;
return (EPERM);
}
(cmd != SBD_MODIFY_LU)) {
return (EINVAL);
}
return (EFAULT);
switch (cmd) {
case SBD_REGISTER_LU:
rlc = (register_lu_cmd_t *)p;
STMF_SUCCESS) {
}
STMF_SUCCESS) {
}
} else {
break;
}
break;
case SBD_MODIFY_LU: {
break;
}
break;
}
/* not registered */
} else {
}
} else {
break;
}
/* not registered, this is not allowed */
break;
}
}
}
}
break;
case SBD_DEREGISTER_LU:
drlc = (deregister_lu_cmd_t *)p;
if (ret1 == 0) {
break;
}
}
stmf_trace(0, "sbd_ioctl: can't find specified LU");
break;
}
!slul->sl_state_not_acked) {
goto do_lu_dereg;
}
break;
}
max_times = 50;
!slul->sl_state_not_acked) {
break;
}
}
} else {
STMF_SUCCESS) {
stmf_trace(0, "sbd_ioctl: sst_degregister_lu "
}
}
break;
case SBD_GET_LU_LIST:
sll = (sbd_lu_list_t *)p;
if (cnt < 0) {
break;
}
break;
}
}
}
break;
case SBD_GET_LU_ATTR:
sla = (sbd_lu_attr_t *)p;
if (sla->total_struct_size <
break;
}
break;
}
} else {
}
break;
default:
return (ENOTTY);
}
if (!ret)
return (ret);
}
/* ARGSUSED */
void
{
char *s;
int rlc_size = 0;
int sn;
return;
}
return;
}
continue;
}
if (nvpair_value_string(np, &s) != 0) {
continue;
}
if (rlc_size) {
}
KM_SLEEP);
}
(void) filedisk_register_lu(rlc);
}
if (rlc) {
}
}
/* ARGSUSED */
{
return (NULL);
return (sst);
}
void
{
}
#define DATA_ALIGNMENT 0xfffffffffffff000
{
/* we should read first to avoid overwrite other data */
if (sst->sst_meta_read) {
} else {
}
if (ret != STMF_SUCCESS)
goto aligned_write_ret;
if (sst->sst_meta_write) {
} else {
}
if (op_buf)
return (ret);
}
{
if (sst->sst_meta_read) {
} else {
}
if (ret != STMF_SUCCESS)
goto aligned_read_ret;
if (op_buf)
return (ret);
}
{
uint8_t s = 0;
while (size > 0)
return (s);
}
void
{
}
void
{
h->sms_data_order = data_order;
}
void
{
}
/*
* will not modify sms.
*/
{
" header first.");
}
if (ret != STMF_SUCCESS)
return (0);
}
return (smsh.sms_offset);
}
return (0);
}
{
if (sms->sms_offset == 0) {
if (sms->sms_offset == 0)
return (STMF_FAILURE);
}
if (ret != STMF_SUCCESS)
return (ret);
sms->sms_chksum = 0;
return (STMF_FAILURE);
}
/* Adjust byte order of the header */
}
return (STMF_SUCCESS);
}
{
if (sms->sms_offset == 0) {
if (sms->sms_offset == 0) {
if (sli->sli_total_meta_size <
return (STMF_FAILURE);
}
if (ret != STMF_SUCCESS) {
return (STMF_FAILURE);
}
}
}
sms->sms_chksum = 0;
return (ret);
}
{
sm_section_hdr_t *h;
uint16_t b;
/* Blocksize should be a non-zero power of 2 */
b = sst_idata->sst_blocksize;
if ((b < 2) || ((b & (b - 1)) != 0)) {
return (STMF_INVALID_ARG);
}
/* Store size should be nonzero multiple of blocksize */
if ((sst_idata->sst_store_size == 0) ||
((sst_idata->sst_store_size % b) != 0)) {
return (STMF_INVALID_ARG);
}
/*
* Total metadata size is size of metadata headers + size of
* sbd_lu_info_t + any space needed by the store implementation
* itself. We should also keep enough space for future expansions.
* Also metadat size should be rounded off to blocksize.
*/
/*
* meta_size = sizeof (sbd_meta_start_t ) + sizeof (sbd_lu_info_t) +
* sst_idata->sst_store_meta_data_size;
*/
/*
* for now keep a static 64K for metasize. This should be enough to
* store metadata as well as any persistent reservations and keys.
*/
/*
* If metadata is not separate from user data then store size
* should be large enough to hold metadata. Also effective data
* size should be adjusted.
*/
return (STMF_INVALID_ARG);
}
/* Initialize the header and write it */
/*
* Note that we already included the size for sli even though
* it is going to be written in next step.
*/
sizeof (sbd_meta_start_t) + sizeof (sbd_lu_info_t);
sizeof (sbd_meta_start_t));
if (ret != STMF_SUCCESS)
return (ret);
KM_SLEEP);
h = &sli->sli_sms_header;
h->sms_size = sizeof (sbd_lu_info_t);
h->sms_id = SMS_ID_LU_INFO;
h->sms_data_order = SMS_DATA_ORDER;
&sli->sli_lu_devid[0]);
if (ret == STMF_SUCCESS) {
if (ret != STMF_SUCCESS)
} else {
(unsigned long long)ret);
}
return (ret);
}
/*
* Used to modify the total store size in meta for a LUN, We only
* check sst_idata->sst_store_size here.
* For LUN not registered, we will read meta data first
*/
{
/* uint64_t meta_size; */
return (STMF_INVALID_ARG);
}
/*
* use a copy here in order not to change anything if
* sbd_write_section() failed
*/
else { /* not registered, have to read meta data */
if (ret != STMF_SUCCESS) {
goto exit_modify_lu;
}
if (!sbd_migrate_meta_from_v0_to_v1(sst)) {
goto exit_modify_lu;
}
goto read_meta_header;
}
}
if (ret != STMF_SUCCESS)
goto exit_modify_lu;
}
}
if (ret != STMF_SUCCESS)
/* for registered LU */
}
}
return (ret);
}
/*
* Added sst_idata here because with dynamic LUN, we can only get the
* LUN size from meta data if we are registering LUN
*/
{
uint16_t b;
" from an existing store");
}
if (ret != STMF_SUCCESS) {
return (ret);
}
return (STMF_INVALID_ARG);
goto read_meta_header;
}
if (ret != STMF_SUCCESS)
return (ret);
}
KM_SLEEP);
if (ret != STMF_SUCCESS) {
goto exit_store_online;
}
}
b = sli->sli_blocksize;
/* Calculate shift factor to convert LBA to a linear offset */
b >>= 1;
/* Initialize LU and register it */
stmf_trace(0, "Failed to register with framework, ret=%llx",
ret);
goto exit_store_online;
}
sbd_lu_list = slu;
sbd_lu_count++;
if (sst_idata) {
}
return (STMF_SUCCESS);
return (ret);
}
{
return (STMF_BUSY);
return (STMF_BUSY);
sbd_lu_count--;
break;
}
}
}
return (STMF_SUCCESS);
}
/*
* Version 0 format of metadata was never integrated into solaris. It
* was the format used by early opensolaris release until feb. 2008.
* Subsequent opensolaris releases used version 1 and thats what
* was integrated into solaris as well. At some point V0 stuff should be
* completely removed.
*/
int
{
*meta_offset = 4096;
v0_check:;
STMF_SUCCESS) {
return (0);
}
if (m.sm_magic != SBD_V0_MAGIC) {
if (m.sm_magic != SBD_V0_MAGIC) {
if (*meta_offset == 4096) {
*meta_offset = 0;
goto v0_check;
}
return (0);
}
}
*meta_size = m.sm_meta_size;
return (1);
}
int
{
sm_section_hdr_t *h;
int ret = 0;
return (0);
goto mv0v1_exit;
}
h = &sli->sli_sms_header;
h->sms_id = SMS_ID_LU_INFO;
h->sms_data_order = SMS_DATA_ORDER;
} else {
}
/* sli_flags were not used in v0 */
goto mv0v1_exit;
}
ret = 1;
return (ret);
}