1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <string.h>
30
31#include <libintl.h>
32
33#include "volume_error.h"
34#include "volume_dlist.h"
35#include "volume_output.h"
36
37#include "layout_device_cache.h"
38#include "layout_device_util.h"
39#include "layout_discovery.h"
40#include "layout_dlist_util.h"
41#include "layout_messages.h"
42#include "layout_request.h"
43#include "layout_slice.h"
44#include "layout_svm_util.h"
45
46#define	_LAYOUT_HSP_C
47
48static int layout_explicit_hsp(
49	devconfig_t 	*hsprequest,
50	dlist_t		*devices,
51	devconfig_t 	**hsp);
52
53static int layout_default_hsp(
54	devconfig_t 	*request,
55	dlist_t		*devices,
56	devconfig_t 	**hsp);
57
58static int populate_hsp(
59	devconfig_t	*request,
60	devconfig_t	*hsp,
61	dlist_t		*devices);
62
63static int assemble_hsp(
64	devconfig_t 	*hsp,
65	dlist_t		*newspares,
66	dlist_t		*devices);
67
68static int get_uniquely_sized_slices(
69	dlist_t 	*devices,
70	dlist_t 	**unique);
71
72static int remove_undersized_slices(
73	dlist_t 	*unique,
74	dlist_t 	**avail);
75
76static int find_spare_for_component(
77	devconfig_t 	*component,
78	dlist_t		*all_spares,
79	dlist_t		*hbas,
80	dlist_t		*disks,
81	boolean_t 	*found);
82
83static int choose_spare_for_component(
84	devconfig_t 	*comp,
85	dlist_t 	**all_spares,
86	dlist_t 	**new_spares,
87	dlist_t 	**avail,
88	dlist_t 	*used_hbas,
89	dlist_t 	*used_disks,
90	uint16_t	npaths);
91
92/*
93 * FUNCTION:	layout_hsp(devconfig_t *request, devconfig_t hsprequest,
94 *			dlist_t *devices, dlist_t **results)
95 *
96 * INPUT:	request	- pointer to the toplevel request devconfig_t
97 *		hsp	- pointer to the optional HSP request devconfig_t
98 *		devices - pointer to a list of devices to be served by the HSP
99 *
100 * OUTPUT:	results - pointer to a list result devconfig_t, if the HSP
101 *			to service the input list of devices needs to be
102 *			created or modified, it will be appended to the list.
103 *
104 * RETURNS:	int	- 0 on success
105 *			 !0 otherwise.
106 *
107 * PURPOSE:	Main layout driver for HSP, attempts to build/populate a
108 *		single HSP to service the list of devices.
109 *
110 *		If the input hsprequest is NULL, use the default HSP scheme:
111 *		a. use the first HSP in the diskset
112 *		b. create an HSP if the diskset has none
113 *
114 *		If the hsprequest is not NULL:
115 *		a. if the request names an HSP and it already exists, use it
116 *		b. if the request names an HSP and it does not exist, create it
117 *		c. if the request specifies components, use them
118 */
119int
120layout_hsp(
121	devconfig_t	*request,
122	devconfig_t	*hsprequest,
123	dlist_t		*devices,
124	dlist_t		**results)
125{
126	int		error = 0;
127	devconfig_t  	*hsp = NULL;
128
129	oprintf(OUTPUT_TERSE,
130		gettext("  ->Layout a %s\n"),
131		devconfig_type_to_str(TYPE_HSP));
132
133	if (hsprequest == NULL) {
134	    error = layout_default_hsp(request, devices, &hsp);
135	} else {
136	    error = layout_explicit_hsp(hsprequest, devices, &hsp);
137	}
138
139	if (error != 0) {
140	    print_debug_failure_msg(devconfig_type_to_str(TYPE_HSP),
141		    get_error_string(error));
142	} else if (hsp != NULL) {
143
144	    if (devconfig_get_components(hsp) == NULL) {
145		/* HSP is usable as it is */
146		free_devconfig(hsp);
147		hsp = NULL;
148	    } else {
149		dlist_t *item = NULL;
150		if ((item = dlist_new_item(hsp)) == NULL) {
151		    error = ENOMEM;
152		} else {
153		    *results = dlist_append(item, *results, AT_TAIL);
154		    print_layout_success_msg();
155		}
156	    }
157	}
158
159	return (error);
160}
161
162/*
163 * FUNCTION:	layout_default_hsp(devconfig_t *request,
164 *			dlist_t *devices, devconfig_t **hsp)
165 *
166 * INPUT:	request	- pointer to the toplevel request devconfig_t
167 *		devices - pointer to a list of devices to be served by the HSP
168 *
169 * OUTPUT:	hsp	- pointer to a devconfig_t to hold the resulting HSP
170 *
171 * RETURNS:	int	- 0 on success
172 *			 !0 otherwise.
173 *
174 * PURPOSE:	Layout driver for default HSP construction.
175 *
176 *		a. use the first HSP in the diskset
177 *		b. create an HSP if the diskset has none
178 *		c. add spares to the HSP to service the list of input devices.
179 */
180static int
181layout_default_hsp(
182	devconfig_t 	*request,
183	dlist_t		*devices,
184	devconfig_t 	**hsp)
185{
186	char		*dsname = get_request_diskset();
187	char		*hspname = NULL;
188	boolean_t	free_hspname = B_FALSE;
189	devconfig_t	*default_hsp = NULL;
190	int		error = 0;
191
192	oprintf(OUTPUT_TERSE,
193		gettext("  -->Using default HSP scheme...\n"));
194
195	if ((error = get_default_hsp_name(request, &hspname)) != 0) {
196	    volume_set_error(
197		    gettext("error getting HSP name from defaults\n"));
198	    return (error);
199	}
200
201	if (hspname != NULL) {
202	    if ((error = hsp_get_by_name(dsname, hspname, &default_hsp)) != 0) {
203		volume_set_error(
204			gettext("error getting default HSP by name\n"));
205		return (error);
206	    }
207	} else {
208	    /* no default HSP name, get diskset's default HSP */
209	    if ((error = hsp_get_default_for_diskset(dsname,
210		&default_hsp)) != 0) {
211		volume_set_error(
212			gettext("error getting default HSP\n"));
213		return (error);
214	    }
215
216	    if (default_hsp == NULL) {
217		/* no default HSP name, no default HSP, make one */
218		if ((error = get_next_hsp_name(&hspname)) != 0) {
219		    volume_set_error(
220			    gettext("error making default HSP name\n"));
221		    return (error);
222		}
223		free_hspname = B_TRUE;
224	    }
225	}
226
227	if (default_hsp != NULL) {
228
229	    /* Found existing default HSP, copy it */
230	    dlist_t *spares = devconfig_get_components(default_hsp);
231
232	    ((error = devconfig_get_name(default_hsp, &hspname)) != 0) ||
233	    (error = new_devconfig(hsp, TYPE_HSP)) ||
234	    (error = devconfig_set_name(*hsp, hspname));
235
236	    if (error == 0) {
237		devconfig_set_components(*hsp, spares);
238		devconfig_set_components(default_hsp, NULL);
239
240		oprintf(OUTPUT_TERSE,
241			gettext("  --->Using %s from disk set %s...\n"),
242			hspname, dsname);
243	    } else {
244		free_devconfig(*hsp);
245		*hsp = NULL;
246	    }
247
248	} else {
249
250	    /* no existing default HSP, make it */
251	    ((error = new_devconfig(hsp, TYPE_HSP)) != 0) ||
252	    (error = devconfig_set_name(*hsp, hspname));
253	    if (error == 0) {
254		oprintf(OUTPUT_VERBOSE,
255			gettext("  --->Created %s for disk set %s...\n "),
256			hspname, dsname);
257	    } else {
258		free_devconfig(*hsp);
259		*hsp = NULL;
260	    }
261
262	    if (free_hspname == B_TRUE) {
263		free(hspname);
264	    }
265	}
266
267	if (error == 0) {
268	    error = populate_hsp(request, *hsp, devices);
269	}
270
271	return (error);
272}
273
274/*
275 * FUNCTION:	layout_explicit_hsp(devconfig_t *hsprequest,
276 *			dlist_t *devices, devconfig_t **hsp)
277 *
278 * INPUT:	hsprequest - pointer to the explicit HSP request devconfig_t
279 *		devices - pointer to a list of devices to be served by the HSP
280 *
281 * OUTPUT:	hsp	- pointer to a HSP devconfig_t to hold resulting HSP
282 *
283 * RETURNS:	int	- 0 on success
284 *			 !0 otherwise.
285 *
286 * PURPOSE:	Layout driver for an explicit HSP request.
287 *
288 *		a. if the request names an HSP and it already exists, use it
289 *		b. if the request names an HSP and it does not exist, create it
290 *		c. if the request specifies components, use them
291 *		   otherwise, add new spares to handle the input list
292 *		   of devices.
293 */
294static int
295layout_explicit_hsp(
296	devconfig_t	*hsprequest,
297	dlist_t		*devices,
298	devconfig_t 	**hsp)
299{
300	char		*dsname = get_request_diskset();
301	char		*hspname = NULL;
302	dlist_t		*rspares = NULL;
303	int		error = 0;
304
305	oprintf(OUTPUT_VERBOSE,
306		gettext("  --->Explicit HSP request...\n"));
307
308	(void) devconfig_get_name(hsprequest, &hspname);
309	if (hspname != NULL) {
310
311	    (void) hsp_get_by_name(dsname, hspname, hsp);
312	    if (*hsp != NULL) {
313
314		oprintf(OUTPUT_VERBOSE,
315			gettext("  --->Using %s...\n"),
316			hspname);
317	    } else {
318
319		/* named HSP doesn't exist, create it */
320		((error = new_devconfig(hsp, TYPE_HSP)) != 0) ||
321		(error = devconfig_set_name(*hsp, hspname));
322		if (error == 0) {
323		    oprintf(OUTPUT_VERBOSE,
324			    gettext("  --->%s does not exist, "
325				    "created...\n"), hspname);
326		} else {
327		    free_devconfig(*hsp);
328		    *hsp = NULL;
329		}
330		free(hspname);
331	    }
332	}
333
334	if (error == 0) {
335
336	    /* does the hsprequest specify spares? */
337	    rspares = devconfig_get_components(hsprequest);
338	    if (rspares != NULL) {
339
340		/* put requested spares into HSP */
341		dlist_t	*list = NULL;
342		dlist_t *iter = NULL;
343
344		for (iter = rspares;
345		    (iter != NULL) && (error == 0);
346		    iter = iter->next) {
347
348		    dlist_t *item = NULL;
349		    if ((dlist_new_item(iter->obj)) == NULL) {
350			error = ENOMEM;
351		    } else {
352			list = dlist_append(item, list, AT_TAIL);
353		    }
354		}
355
356		if (error == 0) {
357		    error = assemble_hsp(*hsp, rspares, devices);
358		}
359
360	    } else {
361
362		/* select new spares */
363		error = populate_hsp(hsprequest, *hsp, devices);
364	    }
365	}
366
367	return (error);
368}
369
370/*
371 * FUNCTION:	populate_hsp(devconfig_t *request, devconfig_t *hsp,
372 *			dlist_t *devices)
373 *
374 * INPUT:	request	- pointer to a request devconfig_t
375 *		hsp	- pointer to a HSP devconfig_t
376 *		devices - pointer to a list of devices to be served by the HSP
377 *
378 * RETURNS:	int	- 0 on success
379 *			 !0 otherwise.
380 *
381 * PURPOSE:	Processes the input HSP request and add spares sufficient
382 *		to service the input list of devices.
383 *
384 *		Determine the available HBAs, disks, and slices.
385 *		Sort thru the input list of devices and determine
386 *		    the unique component sizes which need to be spared.
387 *		Filter the available slices and remove those that are
388 *		    too small to serve as spares.
389 *
390 *		Iterate each device and its components and see if the
391 *		    HSP currently has a sufficient spare, if not, try
392 *		    to select one from the available slices.
393 *
394 *		If a spare cannot be found for any device component,
395 *		    the HSP layout process stops.
396 *
397 *              If spares are found for all device components, add
398 *		    any required new ones to the HSP.
399 */
400static int
401populate_hsp(
402	devconfig_t	*request,
403	devconfig_t	*hsp,
404	dlist_t		*devices)
405{
406	int		error = 0;
407	uint16_t	npaths	= 0;
408
409	dlist_t		*usable_hbas = NULL;
410	dlist_t		*sel_hbas = NULL;
411	dlist_t		*disks = NULL;
412	dlist_t		*iter = NULL;
413
414	dlist_t		*avail = NULL;	/* available slices */
415	dlist_t		*slices = NULL;	/* avail slices of sufficient size */
416	dlist_t		*unique = NULL;	/* volume slices that need spares */
417	dlist_t		*curspares = NULL; /* current spares in the HSP */
418	dlist_t		*newspares = NULL; /* slices to add to HSP */
419	dlist_t		*allspares = NULL; /* current and new spares */
420
421	((error = get_usable_hbas(&usable_hbas)) != 0) ||
422	(error = select_hbas_with_n_disks(request, usable_hbas, 1, &sel_hbas,
423		&disks)) ||
424	(error = disks_get_avail_slices(request, disks, &avail)) ||
425	(error = get_volume_npaths(request, &npaths));
426	if (error != 0) {
427	    dlist_free_items(sel_hbas, NULL);
428	    dlist_free_items(disks, NULL);
429	    dlist_free_items(avail, NULL);
430	    return (error);
431	}
432
433	if (disks == NULL || dlist_length(disks) == 0) {
434	    /* all disks have been consumed by the devices */
435	    volume_set_error(
436		    gettext("  no available disks to populate HSP\n"));
437	    dlist_free_items(sel_hbas, NULL);
438	    dlist_free_items(avail, NULL);
439	    return (-1);
440	}
441
442	if (avail == NULL || dlist_length(avail) == 0) {
443	    /* all slices have been consumed by the devices */
444	    volume_set_error(
445		    gettext("  no available slices to populate HSP\n"));
446	    dlist_free_items(sel_hbas, NULL);
447	    dlist_free_items(disks, NULL);
448	    return (-1);
449	}
450
451	dlist_free_items(sel_hbas, NULL);
452	dlist_free_items(disks, NULL);
453
454	/* build list of slices needing to be spared */
455	((error = get_uniquely_sized_slices(devices, &unique)) != 0) ||
456
457	/* and list of slices of sufficient size to spare for them */
458	(error = remove_undersized_slices(unique, &avail));
459
460	if (error != 0) {
461	    dlist_free_items(avail, NULL);
462	    dlist_free_items(unique, NULL);
463	    dlist_free_items(slices, NULL);
464	    return (error);
465	}
466
467	/* get spares currently in the HSP */
468	curspares = devconfig_get_components(hsp);
469
470	/* clone current spares list */
471	for (iter = curspares;
472	    (iter != NULL) && (error == 0);
473	    iter = iter->next) {
474	    dlist_t *item = dlist_new_item(iter->obj);
475	    if (item == NULL) {
476		error = ENOMEM;
477	    } else {
478		allspares = dlist_append(item, allspares, AT_TAIL);
479	    }
480	}
481
482	if (error != 0) {
483	    dlist_free_items(avail, NULL);
484	    dlist_free_items(unique, NULL);
485	    dlist_free_items(slices, NULL);
486	    dlist_free_items(allspares, NULL);
487	    return (error);
488	}
489
490	/*
491	 * examine device component slices and see if the HSP already
492	 * has a suitable spare. If not, select the best available
493	 * of the same (or larger) size
494	 */
495	for (iter = devices;
496	    (iter != NULL) && (error == 0);
497	    iter = iter->next) {
498
499	    devconfig_t *device = (devconfig_t *)iter->obj;
500	    dlist_t *components = devconfig_get_components(device);
501	    dlist_t *hbas = NULL;
502	    dlist_t *disks = NULL;
503	    dlist_t *iter1;
504
505	    error = get_hbas_and_disks_used_by_volume(device, &hbas, &disks);
506	    for (iter1 = components; (iter1 != NULL) && (error == 0);
507		iter1 = iter1->next) {
508
509		devconfig_t	*comp = (devconfig_t *)iter1->obj;
510		boolean_t	found = B_FALSE;
511
512		if ((error = find_spare_for_component(
513		    comp, allspares, hbas, disks, &found)) == 0) {
514		    if (found != B_TRUE) {
515			error = choose_spare_for_component(
516				comp, &allspares, &newspares,
517				&avail, hbas, disks, npaths);
518		    }
519		}
520	    }
521	    dlist_free_items(disks, NULL);
522	    dlist_free_items(hbas, NULL);
523	}
524
525	if (error == 0) {
526	    /* existing spares are no longer needed */
527	    dlist_free_items(curspares, free_devconfig_object);
528	    curspares = NULL;
529
530	    error = assemble_hsp(hsp, newspares, devices);
531	} else {
532	    dlist_free_items(newspares, free_devconfig_object);
533	    newspares = NULL;
534	}
535
536	dlist_free_items(avail, NULL);
537	dlist_free_items(slices, NULL);
538	dlist_free_items(unique, NULL);
539	dlist_free_items(allspares, NULL);
540
541	return (error);
542}
543
544/*
545 * FUNCTION:	assemble_hsp(devconfig_t *hsp, dlist_t *newspares,
546 *			dlist_t *devices)
547 *
548 * INPUT:	request	- pointer to a HSP devconfig_t
549 *		newspare - pointer to a list of new spares for the HSP
550 *		devices - pointer to a list of devices to be served by the HSP
551 *
552 * RETURNS:	int	- 0 on success
553 *			 !0 otherwise.
554 *
555 * PURPOSE:	Final assembly of an HSP. Attach new spare components
556 *		and associate the HSP with each device in the input list.
557 */
558static int
559assemble_hsp(
560	devconfig_t 	*hsp,
561	dlist_t		*newspares,
562	dlist_t		*devices)
563{
564	dlist_t		*iter;
565	char		*hspname = NULL;
566	int		error = 0;
567
568	/* add new spares to HSP */
569	(void) devconfig_set_components(hsp, newspares);
570	(void) devconfig_get_name(hsp, &hspname);
571
572	/* associate HSP with each of the devices */
573	for (iter = devices;
574	    (iter != NULL) && (error == 0);
575	    iter = iter->next) {
576
577	    devconfig_t *dev = iter->obj;
578	    devconfig_t *hspcomp = NULL;
579	    dlist_t	*item = NULL;
580	    char	*devname = NULL;
581
582	    ((error = devconfig_get_name(dev, &devname)) != 0) ||
583	    (error = new_devconfig(&hspcomp, TYPE_HSP)) ||
584	    (error = devconfig_set_name(hspcomp, hspname));
585
586	    if (error != 0) {
587
588		free_devconfig(hspcomp);
589
590	    } else if ((item = dlist_new_item(hspcomp)) == NULL) {
591
592		free_devconfig(hspcomp);
593		error = ENOMEM;
594
595	    } else {
596
597		dlist_t	*comps = devconfig_get_components(dev);
598		comps = dlist_append(comps, item, AT_TAIL);
599		(void) devconfig_set_components(dev, comps);
600
601		oprintf(OUTPUT_VERBOSE,
602			gettext("  --->volume %s will use HSP %s\n"),
603			devname, hspname);
604	    }
605	}
606
607	return (error);
608}
609
610/*
611 * FUNCTION:	get_uniquely_sized_slices(dlist_t *devices,
612 *			dlist_t **unique)
613 *
614 * INPUT:	devices	- pointer to a list of devconfig_t devices
615 *
616 * OUTPUT:	unique	- pointer to a list of uniquely size slices
617 *			from the input list of devices.
618 *
619 * RETURNS:	int	- 0 on success
620 *			 !0 otherwise.
621 *
622 * PURPOSE:	Examine each device's slice components and build a list
623 *		of uniquely sized slices.
624 */
625static int
626get_uniquely_sized_slices(
627	dlist_t 	*devices,
628	dlist_t 	**unique)
629{
630	int		error = 0;
631	dlist_t		*iter = NULL;
632
633	for (iter = devices;
634	    (iter != NULL) && (error == 0);
635	    iter = iter->next) {
636
637	    dlist_t *iter1;
638	    for (iter1 = devconfig_get_components((devconfig_t *)iter->obj);
639		(iter1 != NULL) && (error == 0);
640		iter1 = iter1->next) {
641
642		devconfig_t *comp = (devconfig_t *)iter1->obj;
643		if (dlist_contains(*unique, comp,
644		    compare_devconfig_sizes) != B_TRUE) {
645
646		    dlist_t *item = NULL;
647		    if ((item = dlist_new_item(comp)) == NULL) {
648			error = ENOMEM;
649		    } else {
650			*unique = dlist_insert_ordered(item, *unique,
651				ASCENDING, compare_devconfig_sizes);
652		    }
653		}
654	    }
655	}
656
657	return (error);
658}
659
660/*
661 * FUNCTION:	remove_undersized_slices(dlist_t *unique,
662 *			dlist_t **avail)
663 *
664 * INPUT:	avail	- pointer to a list of available slices
665 * 		unique	- pointer to a list of uniquely size slices
666 *
667 * OUTPUT:	avail - pointer to an updated list of available slices
668 *			that are at least as large as slices in the
669 *			unique list.
670 *
671 * RETURNS:	int	- 0 on success
672 *			 !0 otherwise.
673 *
674 * PURPOSE:	filter available slices and remove those that aren't
675 *		large enough for the device components which need spares.
676 *
677 *		For each uniquely sized slice, find all available slices
678 *		that are larger and add them to the filtered list.
679 */
680static int
681remove_undersized_slices(
682	dlist_t		*unique,
683	dlist_t		**avail)
684{
685	dlist_t		*filtered = NULL;
686	dlist_t		*iter = NULL;
687	int		error = 0;
688
689	for (iter = unique;
690	    (iter != NULL) && (error == 0);
691	    iter = iter->next) {
692
693	    devconfig_t	*uslice = (devconfig_t *)iter->obj;
694	    uint64_t	usize = 0;
695	    dlist_t	*iter2 = NULL;
696
697	    error = devconfig_get_size(uslice, &usize);
698
699	    for (iter2 = *avail;
700		(iter2 != NULL) && (error == 0);
701		iter2 = iter2->next) {
702
703		dm_descriptor_t	aslice = (uintptr_t)iter2->obj;
704		uint64_t	asize = 0;
705
706		error = slice_get_size(aslice, &asize);
707		if (asize >= usize) {
708
709		    /* this slice is large enough */
710		    dlist_t *item = NULL;
711		    if ((item = dlist_new_item((void *)(uintptr_t)aslice)) ==
712			NULL) {
713			error = ENOMEM;
714		    } else {
715			filtered = dlist_insert_ordered(item, filtered,
716				ASCENDING, compare_slice_sizes);
717		    }
718
719		}
720	    }
721	}
722
723	if (error == 0) {
724	    dlist_free_items(*avail, NULL);
725	    *avail = filtered;
726	} else {
727	    dlist_free_items(filtered, NULL);
728	}
729
730	return (error);
731}
732
733/*
734 * FUNCTION:	find_spare_for_component(devconfig_t *component,
735 *			dlist_t *all_spares, dlist_t *hbas, dlist_t *disks,
736 *			boolean_t *found)
737 *
738 * INPUT:	comp	- pointer to a devconfig_t slice compenent that
739 *				needs to be spared
740 * 		all_spares - pointer to a list of spares currently
741 *				in the pool or that will be added
742 * 		hbas	- pointer to a list of HBAs the component's
743 *				parent device utilizes
744 * 		disks	- pointer to a list of disks the component's
745 *				parent device utilizes
746 *
747 * OUTPUT:	found - pointer to a boolean_t to hold the result.
748 *
749 * RETURNS:	int	- 0 on success
750 *			 !0 otherwise.
751 *
752 * PURPOSE:	Find a spare for the input component.
753 *
754 *		Searches the input list of spares to see if one is
755 *		sufficient.
756 *
757 *		A suffcient spare is one that is large enough to spare
758 *		for the input component and not on the same disk as any
759 *		of the components in the parent device.
760 *
761 *		The optimal spare would be on a different controller/HBA
762 *		as the component and any of the components in the parent
763 *		device.  We settle for sufficient.
764 */
765static int
766find_spare_for_component(
767	devconfig_t	*component,
768	dlist_t		*all_spares,
769	dlist_t		*hbas,
770	dlist_t		*disks,
771	boolean_t	*found)
772{
773	dlist_t		*iter = NULL;
774	uint64_t	csize = 0;
775	int		error = 0;
776
777	*found = B_FALSE;
778
779	(void) devconfig_get_size(component, &csize);
780
781	for (iter = all_spares;
782	    (iter != NULL) && (*found == B_FALSE) && (error == 0);
783	    iter = iter->next) {
784
785	    devconfig_t		*spare = (devconfig_t *)iter->obj;
786	    char 		*spname = NULL;
787	    uint64_t 		spsize = 0;
788
789	    if (((error = devconfig_get_name(spare, &spname)) != 0) ||
790		((error = devconfig_get_size(spare, &spsize)) != 0)) {
791		continue;
792	    }
793
794	    if (spsize >= csize) {
795
796		dm_descriptor_t	disk = NULL;
797
798		/* see if spare's disk is independent of the volume */
799		error = get_disk_for_named_slice(spname, &disk);
800		if ((error == 0) && (dlist_contains(disks,
801		    (void *)(uintptr_t)disk, compare_descriptor_names) ==
802		    B_FALSE)) {
803		    *found = B_TRUE;
804		}
805	    }
806	}
807
808	if ((*found == B_TRUE) && (get_max_verbosity() >= OUTPUT_DEBUG)) {
809	    char *cname = NULL;
810	    (void) devconfig_get_name(component, &cname);
811	    oprintf(OUTPUT_DEBUG,
812		    gettext("    found existing spare for: %s (%llu)\n"),
813		    cname, csize);
814	}
815
816	return (error);
817}
818
819/*
820 * FUNCTION:	choose_spare_for_component(devconfig_t *component,
821 *			dlist_t *all_spares, dlist_t **new_spares,
822 *			dlist_t avail, uint16_t npaths, dlist_t *used_hbas,
823 *			dlist_t *used_disks)
824 *
825 * INPUT:	comp	- pointer to a devconfig_t slice compenent that
826 *				needs to be spared
827 * 		all_spares - pointer to a list of spares currently
828 *				in the pool and those to be added
829 * 		new_spares - pointer to a list of spares that need to
830 *				be added to the pool
831 *		avail	- list of available slices
832 *		npaths	- required number of paths for the spare
833 *		used_hbas - list of HBAs used by the component's parent
834 *		used_disks - list of disks used by the component's parent
835 *
836 * OUTPUT:	all_spares - the possibly updated list of all spares
837 *		new_spares - the possibly updated list of spares which
838 *			need to be added to the pool.
839 *
840 * RETURNS:	int	- 0 on success
841 *			 !0 otherwise.
842 *
843 * PURPOSE:	Find a new spare for the input component.
844 *
845 *		Select a spare from the available slice list and add
846 *		it to the new_spares list.
847 *
848 *		The spare slice chosen should be on a unique HBA and
849 *		disk relative to the input lists of used HBAs and disks
850 *		and any spares in the pool.
851 */
852static int
853choose_spare_for_component(
854	devconfig_t	*component,
855	dlist_t		**all_spares,
856	dlist_t		**new_spares,
857	dlist_t		**avail,
858	dlist_t		*used_hbas,
859	dlist_t		*used_disks,
860	uint16_t	npaths)
861{
862	devconfig_t	*spare = NULL;
863	uint64_t	csize = 0;
864	int		error = 0;
865
866	(void) devconfig_get_size(component, &csize);
867
868	if (get_max_verbosity() >= OUTPUT_DEBUG) {
869	    char *cname = NULL;
870	    (void) devconfig_get_name(component, &cname);
871	    oprintf(OUTPUT_DEBUG,
872		    gettext("    select new spare for: %s (%llu)\n"),
873		    cname, csize);
874	}
875
876	/*
877	 * find a spare for the input component.
878	 * select the best one from the available list that
879	 * is on a unique disk.
880	 */
881
882	/*
883	 * 1st B_TRUE: require a different disk than those used by
884	 *		all spares and devices
885	 * 2nd B_TRUE: requested size is the minimum acceptable
886	 * 1st B_FALSE: do not add an extra cylinder when resizing slice,
887	 *		this is only necessary for Stripe components whose
888	 *		sizes get rounded down to an interlace multiple and
889	 *		then down to a cylinder boundary.
890	 */
891	error = choose_slice(csize, npaths, *avail, *all_spares,
892		used_hbas, used_disks, B_TRUE, B_TRUE, B_FALSE, &spare);
893
894	if ((error == 0) && (spare == NULL)) {
895	    /* can't find one on a unique disk, try again on any disk */
896
897	    /* BEGIN CSTYLED */
898	    /*
899	     * 1st B_FALSE: don't require a different disk than those used
900	     *		by all spares and devices
901	     * 2nd B_TRUE: requested size is still the minimum acceptable
902	     * 2nd B_FALSE: do not add an extra cylinder when resizing slice
903	     *		this is only necessary for Stripe components whose
904	     *		sizes get rounded down to an interlace multiple and
905	     *		then down to a cylinder boundary.
906	     */
907	    /* END CSTYLED */
908	    error = choose_slice(
909		    csize, npaths, *avail, *all_spares, used_hbas,
910		    used_disks, B_FALSE, B_TRUE, B_FALSE, &spare);
911	}
912
913	if ((error == 0) && (spare != NULL)) {
914
915	    dlist_t	*rmvd = NULL;
916	    dlist_t	*item = NULL;
917	    char	*spname = NULL;
918
919	    if ((item = dlist_new_item(spare)) == NULL) {
920		error = ENOMEM;
921	    } else {
922
923		/* add spare to the all spares list */
924		*all_spares = dlist_append(item, *all_spares, AT_HEAD);
925
926		if ((item = dlist_new_item(spare)) == NULL) {
927		    error = ENOMEM;
928		} else {
929
930		    /* add spare to the new spares list */
931		    *new_spares = dlist_insert_ordered(
932			    item, *new_spares, ASCENDING,
933			    compare_devconfig_sizes);
934
935		    /* remove it from the available list */
936		    *avail = dlist_remove_equivalent_item(*avail, spare,
937			    compare_devconfig_and_descriptor_names,
938			    &rmvd);
939
940		    if (rmvd != NULL) {
941			free(rmvd);
942		    }
943
944		    /* add the spare to the used slice list */
945		    error = devconfig_get_name(spare, &spname);
946		    if (error == 0) {
947			error = add_used_slice_by_name(spname);
948		    }
949		}
950	    }
951
952	} else {
953
954	    /* no spare, give up on layout */
955	    oprintf(OUTPUT_TERSE,
956		    gettext("  <---Failed: insufficient suitable spares\n"));
957
958	    volume_set_error(
959		    gettext("failed to find sufficient spares for HSP\n"));
960
961	    error = -1;
962	}
963
964	return (error);
965}
966