/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <string.h>
#include <libintl.h>
#include "volume_error.h"
#include "volume_dlist.h"
#include "volume_output.h"
#include "layout_device_cache.h"
#include "layout_device_util.h"
#include "layout_discovery.h"
#include "layout_dlist_util.h"
#include "layout_messages.h"
#include "layout_request.h"
#include "layout_slice.h"
#include "layout_svm_util.h"
#define _LAYOUT_HSP_C
static int layout_explicit_hsp(
devconfig_t **hsp);
static int layout_default_hsp(
devconfig_t **hsp);
static int populate_hsp(
static int assemble_hsp(
static int get_uniquely_sized_slices(
static int remove_undersized_slices(
static int find_spare_for_component(
static int choose_spare_for_component(
/*
* FUNCTION: layout_hsp(devconfig_t *request, devconfig_t hsprequest,
* dlist_t *devices, dlist_t **results)
*
* INPUT: request - pointer to the toplevel request devconfig_t
* hsp - pointer to the optional HSP request devconfig_t
* devices - pointer to a list of devices to be served by the HSP
*
* OUTPUT: results - pointer to a list result devconfig_t, if the HSP
* to service the input list of devices needs to be
* created or modified, it will be appended to the list.
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* single HSP to service the list of devices.
*
* If the input hsprequest is NULL, use the default HSP scheme:
* a. use the first HSP in the diskset
* b. create an HSP if the diskset has none
*
* If the hsprequest is not NULL:
* a. if the request names an HSP and it already exists, use it
* b. if the request names an HSP and it does not exist, create it
* c. if the request specifies components, use them
*/
int
{
int error = 0;
gettext(" ->Layout a %s\n"),
if (hsprequest == NULL) {
} else {
}
if (error != 0) {
/* HSP is usable as it is */
} else {
} else {
}
}
}
return (error);
}
/*
* FUNCTION: layout_default_hsp(devconfig_t *request,
* dlist_t *devices, devconfig_t **hsp)
*
* INPUT: request - pointer to the toplevel request devconfig_t
* devices - pointer to a list of devices to be served by the HSP
*
* OUTPUT: hsp - pointer to a devconfig_t to hold the resulting HSP
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* PURPOSE: Layout driver for default HSP construction.
*
* a. use the first HSP in the diskset
* b. create an HSP if the diskset has none
* c. add spares to the HSP to service the list of input devices.
*/
static int
devconfig_t **hsp)
{
int error = 0;
gettext(" -->Using default HSP scheme...\n"));
gettext("error getting HSP name from defaults\n"));
return (error);
}
gettext("error getting default HSP by name\n"));
return (error);
}
} else {
/* no default HSP name, get diskset's default HSP */
&default_hsp)) != 0) {
gettext("error getting default HSP\n"));
return (error);
}
if (default_hsp == NULL) {
/* no default HSP name, no default HSP, make one */
gettext("error making default HSP name\n"));
return (error);
}
}
}
if (default_hsp != NULL) {
/* Found existing default HSP, copy it */
if (error == 0) {
gettext(" --->Using %s from disk set %s...\n"),
} else {
}
} else {
/* no existing default HSP, make it */
if (error == 0) {
gettext(" --->Created %s for disk set %s...\n "),
} else {
}
if (free_hspname == B_TRUE) {
}
}
if (error == 0) {
}
return (error);
}
/*
* FUNCTION: layout_explicit_hsp(devconfig_t *hsprequest,
* dlist_t *devices, devconfig_t **hsp)
*
* INPUT: hsprequest - pointer to the explicit HSP request devconfig_t
* devices - pointer to a list of devices to be served by the HSP
*
* OUTPUT: hsp - pointer to a HSP devconfig_t to hold resulting HSP
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* PURPOSE: Layout driver for an explicit HSP request.
*
* a. if the request names an HSP and it already exists, use it
* b. if the request names an HSP and it does not exist, create it
* c. if the request specifies components, use them
* otherwise, add new spares to handle the input list
* of devices.
*/
static int
devconfig_t **hsp)
{
int error = 0;
gettext(" --->Explicit HSP request...\n"));
gettext(" --->Using %s...\n"),
hspname);
} else {
/* named HSP doesn't exist, create it */
if (error == 0) {
gettext(" --->%s does not exist, "
"created...\n"), hspname);
} else {
}
}
}
if (error == 0) {
/* does the hsprequest specify spares? */
/* put requested spares into HSP */
} else {
}
}
if (error == 0) {
}
} else {
/* select new spares */
}
}
return (error);
}
/*
* FUNCTION: populate_hsp(devconfig_t *request, devconfig_t *hsp,
* dlist_t *devices)
*
* INPUT: request - pointer to a request devconfig_t
* hsp - pointer to a HSP devconfig_t
* devices - pointer to a list of devices to be served by the HSP
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* PURPOSE: Processes the input HSP request and add spares sufficient
* to service the input list of devices.
*
* Determine the available HBAs, disks, and slices.
* Sort thru the input list of devices and determine
* the unique component sizes which need to be spared.
* Filter the available slices and remove those that are
* too small to serve as spares.
*
* Iterate each device and its components and see if the
* HSP currently has a sufficient spare, if not, try
* to select one from the available slices.
*
* If a spare cannot be found for any device component,
* the HSP layout process stops.
*
* If spares are found for all device components, add
* any required new ones to the HSP.
*/
static int
{
int error = 0;
&disks)) ||
if (error != 0) {
return (error);
}
/* all disks have been consumed by the devices */
gettext(" no available disks to populate HSP\n"));
return (-1);
}
/* all slices have been consumed by the devices */
gettext(" no available slices to populate HSP\n"));
return (-1);
}
/* build list of slices needing to be spared */
/* and list of slices of sufficient size to spare for them */
if (error != 0) {
return (error);
}
/* get spares currently in the HSP */
/* clone current spares list */
} else {
}
}
if (error != 0) {
return (error);
}
/*
* examine device component slices and see if the HSP already
* has a suitable spare. If not, select the best available
* of the same (or larger) size
*/
if ((error = find_spare_for_component(
}
}
}
}
if (error == 0) {
/* existing spares are no longer needed */
} else {
}
return (error);
}
/*
* FUNCTION: assemble_hsp(devconfig_t *hsp, dlist_t *newspares,
* dlist_t *devices)
*
* INPUT: request - pointer to a HSP devconfig_t
* newspare - pointer to a list of new spares for the HSP
* devices - pointer to a list of devices to be served by the HSP
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* PURPOSE: Final assembly of an HSP. Attach new spare components
* and associate the HSP with each device in the input list.
*/
static int
{
int error = 0;
/* add new spares to HSP */
/* associate HSP with each of the devices */
if (error != 0) {
} else {
gettext(" --->volume %s will use HSP %s\n"),
}
}
return (error);
}
/*
* FUNCTION: get_uniquely_sized_slices(dlist_t *devices,
* dlist_t **unique)
*
* INPUT: devices - pointer to a list of devconfig_t devices
*
* OUTPUT: unique - pointer to a list of uniquely size slices
* from the input list of devices.
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* PURPOSE: Examine each device's slice components and build a list
* of uniquely sized slices.
*/
static int
{
int error = 0;
compare_devconfig_sizes) != B_TRUE) {
} else {
}
}
}
}
return (error);
}
/*
* FUNCTION: remove_undersized_slices(dlist_t *unique,
* dlist_t **avail)
*
* INPUT: avail - pointer to a list of available slices
* unique - pointer to a list of uniquely size slices
*
* OUTPUT: avail - pointer to an updated list of available slices
* that are at least as large as slices in the
* unique list.
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* PURPOSE: filter available slices and remove those that aren't
* large enough for the device components which need spares.
*
* For each uniquely sized slice, find all available slices
* that are larger and add them to the filtered list.
*/
static int
{
int error = 0;
/* this slice is large enough */
NULL) {
} else {
}
}
}
}
if (error == 0) {
} else {
}
return (error);
}
/*
* FUNCTION: find_spare_for_component(devconfig_t *component,
* dlist_t *all_spares, dlist_t *hbas, dlist_t *disks,
* boolean_t *found)
*
* INPUT: comp - pointer to a devconfig_t slice compenent that
* needs to be spared
* all_spares - pointer to a list of spares currently
* in the pool or that will be added
* hbas - pointer to a list of HBAs the component's
* parent device utilizes
* disks - pointer to a list of disks the component's
* parent device utilizes
*
* OUTPUT: found - pointer to a boolean_t to hold the result.
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* PURPOSE: Find a spare for the input component.
*
* Searches the input list of spares to see if one is
* sufficient.
*
* A suffcient spare is one that is large enough to spare
* for the input component and not on the same disk as any
* of the components in the parent device.
*
* The optimal spare would be on a different controller/HBA
* as the component and any of the components in the parent
* device. We settle for sufficient.
*/
static int
{
int error = 0;
for (iter = all_spares;
continue;
}
/* see if spare's disk is independent of the volume */
B_FALSE)) {
}
}
}
gettext(" found existing spare for: %s (%llu)\n"),
}
return (error);
}
/*
* FUNCTION: choose_spare_for_component(devconfig_t *component,
* dlist_t *all_spares, dlist_t **new_spares,
* dlist_t avail, uint16_t npaths, dlist_t *used_hbas,
* dlist_t *used_disks)
*
* INPUT: comp - pointer to a devconfig_t slice compenent that
* needs to be spared
* all_spares - pointer to a list of spares currently
* in the pool and those to be added
* new_spares - pointer to a list of spares that need to
* be added to the pool
* avail - list of available slices
* npaths - required number of paths for the spare
* used_hbas - list of HBAs used by the component's parent
* used_disks - list of disks used by the component's parent
*
* OUTPUT: all_spares - the possibly updated list of all spares
* new_spares - the possibly updated list of spares which
* need to be added to the pool.
*
* RETURNS: int - 0 on success
* !0 otherwise.
*
* PURPOSE: Find a new spare for the input component.
*
* Select a spare from the available slice list and add
* it to the new_spares list.
*
* The spare slice chosen should be on a unique HBA and
* disk relative to the input lists of used HBAs and disks
* and any spares in the pool.
*/
static int
{
int error = 0;
if (get_max_verbosity() >= OUTPUT_DEBUG) {
gettext(" select new spare for: %s (%llu)\n"),
}
/*
* find a spare for the input component.
* select the best one from the available list that
* is on a unique disk.
*/
/*
* 1st B_TRUE: require a different disk than those used by
* all spares and devices
* 2nd B_TRUE: requested size is the minimum acceptable
* 1st B_FALSE: do not add an extra cylinder when resizing slice,
* this is only necessary for Stripe components whose
* sizes get rounded down to an interlace multiple and
* then down to a cylinder boundary.
*/
/* can't find one on a unique disk, try again on any disk */
/* BEGIN CSTYLED */
/*
* 1st B_FALSE: don't require a different disk than those used
* by all spares and devices
* 2nd B_TRUE: requested size is still the minimum acceptable
* 2nd B_FALSE: do not add an extra cylinder when resizing slice
* this is only necessary for Stripe components whose
* sizes get rounded down to an interlace multiple and
* then down to a cylinder boundary.
*/
/* END CSTYLED */
}
} else {
/* add spare to the all spares list */
} else {
/* add spare to the new spares list */
/* remove it from the available list */
&rmvd);
}
/* add the spare to the used slice list */
if (error == 0) {
}
}
}
} else {
/* no spare, give up on layout */
gettext(" <---Failed: insufficient suitable spares\n"));
gettext("failed to find sufficient spares for HSP\n"));
error = -1;
}
return (error);
}