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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
25 */
26
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/conf.h>
30 #include <sys/file.h>
31 #include <sys/user.h>
32 #include <sys/uio.h>
33 #include <sys/t_lock.h>
34 #include <sys/kmem.h>
35 #include <vm/page.h>
36 #include <sys/sysmacros.h>
37 #include <sys/types.h>
38 #include <sys/mkdev.h>
39 #include <sys/stat.h>
40 #include <sys/open.h>
41 #include <sys/modctl.h>
42 #include <sys/ddi.h>
43 #include <sys/sunddi.h>
44 #include <sys/debug.h>
45
46 #include <sys/lvm/md_hotspares.h>
47 #include <sys/lvm/md_convert.h>
48
49 #include <sys/sysevent/eventdefs.h>
50 #include <sys/sysevent/svm.h>
51
52 md_ops_t hotspares_md_ops;
53 #ifndef lint
54 md_ops_t *md_interface_ops = &hotspares_md_ops;
55 #endif
56
57 extern md_ops_t **md_ops;
58 extern md_ops_t *md_opslist;
59 extern md_set_t md_set[];
60
61 extern kmutex_t md_mx; /* used to md global stuff */
62 extern kcondvar_t md_cv; /* md_status events */
63 extern int md_status;
64
65 extern void md_clear_hot_spare_interface();
66
67 static void
set_hot_spare_state(hot_spare_t * hs,hotspare_states_t newstate)68 set_hot_spare_state(hot_spare_t *hs, hotspare_states_t newstate)
69 {
70 hs->hs_state = newstate;
71 uniqtime32(&hs->hs_timestamp);
72 }
73
74 static hot_spare_t *
lookup_hot_spare(set_t setno,mddb_recid_t hs_id,int must_exist)75 lookup_hot_spare(set_t setno, mddb_recid_t hs_id, int must_exist)
76 {
77 hot_spare_t *hs;
78
79 for (hs = (hot_spare_t *)md_set[setno].s_hs; hs; hs = hs->hs_next) {
80 if (hs->hs_record_id == hs_id)
81 return (hs);
82 }
83 if (must_exist)
84 ASSERT(0);
85
86 return ((hot_spare_t *)NULL);
87 }
88
89
90 static int
seths_create_hsp(set_hs_params_t * shs)91 seths_create_hsp(set_hs_params_t *shs)
92 {
93 hot_spare_pool_t *hsp;
94 mddb_recid_t recid;
95 set_t setno;
96 mddb_type_t typ1;
97
98 setno = HSP_SET(shs->shs_hot_spare_pool);
99
100 /* Scan the hot spare pool list */
101 hsp = find_hot_spare_pool(setno, shs->shs_hot_spare_pool);
102 if (hsp != (hot_spare_pool_t *)0)
103 return (0);
104
105 typ1 = (mddb_type_t)md_getshared_key(setno,
106 hotspares_md_ops.md_driver.md_drivername);
107
108 /* create a hot spare pool record */
109 if (shs->shs_options & MD_CRO_64BIT) {
110 #if defined(_ILP32)
111 return (mdhsperror(&shs->mde, MDE_HSP_UNIT_TOO_LARGE,
112 shs->shs_hot_spare_pool));
113 #else
114 recid = mddb_createrec(sizeof (hot_spare_pool_ond_t), typ1,
115 HSP_REC, MD_CRO_64BIT | MD_CRO_HOTSPARE_POOL | MD_CRO_FN,
116 setno);
117 #endif
118 } else {
119 recid = mddb_createrec(sizeof (hot_spare_pool_ond_t), typ1,
120 HSP_REC, MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL | MD_CRO_FN,
121 setno);
122 }
123
124 if (recid < 0) {
125 return (mdhsperror(&shs->mde, MDE_HSP_CREATE_FAILURE,
126 shs->shs_hot_spare_pool));
127 }
128
129 /* get the record addr */
130 hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid, sizeof (*hsp),
131 HSP_ONDSK_STR_OFF);
132
133 hsp->hsp_self_id = shs->shs_hot_spare_pool;
134 hsp->hsp_record_id = recid;
135 hsp->hsp_next = (hot_spare_pool_t *)md_set[setno].s_hsp;
136 hsp->hsp_refcount = 0;
137 hsp->hsp_nhotspares = 0;
138 hsp->hsp_revision |= MD_FN_META_DEV;
139
140 md_set[setno].s_hsp = (void *) hsp;
141
142 mddb_commitrec_wrapper(recid);
143 SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_CREATE, SVM_TAG_HSP, setno,
144 md_expldev(hsp->hsp_self_id));
145
146 rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER);
147 hsp->hsp_link.ln_next = hotspares_md_ops.md_head;
148 hsp->hsp_link.ln_setno = setno;
149 hsp->hsp_link.ln_id = hsp->hsp_self_id;
150 hotspares_md_ops.md_head = &hsp->hsp_link;
151 rw_exit(&hotspares_md_ops.md_link_rw.lock);
152
153 return (0);
154 }
155
156
157 static int
seths_add(set_hs_params_t * shs)158 seths_add(set_hs_params_t *shs)
159 {
160 hot_spare_t *hs;
161 hot_spare_pool_t *hsp;
162 hot_spare_pool_t *prev_hsp;
163 hot_spare_pool_t *new_hsp;
164 hot_spare_pool_t *old_hsp;
165 md_create_rec_option_t options;
166 mddb_recid_t recid;
167 mddb_recid_t recids[5];
168 size_t new_size;
169 int i;
170 int delete_hsp = 0;
171 int irecid;
172 set_t setno;
173 mddb_type_t typ1;
174 int hsp_created = 0;
175 mdkey_t key_old;
176 int num_keys_old = 0;
177
178 /* Not much to do here in case of a dryrun */
179 if (shs->shs_options & HS_OPT_DRYRUN) {
180 return (0);
181 }
182
183 /* create an empty hot spare pool */
184 if (shs->shs_options & HS_OPT_POOL) {
185 return (seths_create_hsp(shs));
186 }
187
188 setno = HSP_SET(shs->shs_hot_spare_pool);
189 typ1 = (mddb_type_t)md_getshared_key(setno,
190 hotspares_md_ops.md_driver.md_drivername);
191
192 /* Scan the hot spare list */
193 hs = (hot_spare_t *)md_set[setno].s_hs;
194 while (hs) {
195 if (hs->hs_devnum == shs->shs_component_old) {
196 break;
197 }
198 hs = hs->hs_next;
199 }
200
201 if (hs == NULL) {
202 /*
203 * Did not find match for device using devnum so use
204 * key associated with shs_component_old just
205 * in case there is a match but the match's dev is NODEV.
206 * If unable to find a unique key for shs_component_old
207 * then fail since namespace has multiple entries
208 * for this old component and we shouldn't allow
209 * an addition of a hotspare in this case.
210 */
211 if (md_getkeyfromdev(setno, mddb_getsidenum(setno),
212 shs->shs_component_old, &key_old, &num_keys_old) != 0) {
213 return (mddeverror(&shs->mde, MDE_NAME_SPACE,
214 shs->shs_component_old));
215 }
216
217 /*
218 * If more than one key matches given old_dev - fail command
219 * since shouldn't add new hotspare if namespace has
220 * multiple entries.
221 */
222 if (num_keys_old > 1) {
223 return (mddeverror(&shs->mde, MDE_MULTNM,
224 shs->shs_component_old));
225 }
226 /*
227 * If there is no key for this entry then fail since
228 * a key for this entry should exist.
229 */
230 if (num_keys_old == 0) {
231 return (mddeverror(&shs->mde, MDE_INVAL_HS,
232 shs->shs_component_old));
233 }
234 /* Scan the hot spare list again */
235 hs = (hot_spare_t *)md_set[setno].s_hs;
236 while (hs) {
237 /*
238 * Only need to compare keys when hs_devnum is NODEV.
239 */
240 if ((hs->hs_devnum == NODEV64) &&
241 (hs->hs_key == key_old)) {
242 break;
243 }
244 hs = hs->hs_next;
245 }
246 }
247
248 if (hs == NULL) {
249 /* create a hot spare record */
250 if (shs->shs_size_option & MD_CRO_64BIT) {
251 #if defined(_ILP32)
252 return (mdhserror(&shs->mde, MDE_HS_UNIT_TOO_LARGE,
253 shs->shs_hot_spare_pool, shs->shs_component_old));
254 #else
255 recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC,
256 MD_CRO_64BIT | MD_CRO_HOTSPARE, setno);
257 #endif
258 } else {
259 recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC,
260 MD_CRO_32BIT | MD_CRO_HOTSPARE, setno);
261 }
262
263 if (recid < 0) {
264 return (mdhserror(&shs->mde, MDE_HS_CREATE_FAILURE,
265 shs->shs_hot_spare_pool,
266 shs->shs_component_old));
267 }
268
269 /* get the addr */
270 hs = (hot_spare_t *)mddb_getrecaddr_resize(recid, sizeof (*hs),
271 0);
272
273 hs->hs_record_id = recid;
274
275 hs->hs_devnum = shs->shs_component_old;
276 hs->hs_key = shs->shs_key_old;
277 hs->hs_start_blk = shs->shs_start_blk;
278 hs->hs_has_label = shs->shs_has_label;
279 hs->hs_number_blks = shs->shs_number_blks;
280 set_hot_spare_state(hs, HSS_AVAILABLE);
281 hs->hs_refcount = 0;
282 hs->hs_next = (hot_spare_t *)md_set[setno].s_hs;
283 md_set[setno].s_hs = (void *) hs;
284 }
285
286 /* Scan the hot spare pool list */
287 hsp = (hot_spare_pool_t *)md_set[setno].s_hsp;
288 prev_hsp = (hot_spare_pool_t *)0;
289 while (hsp) {
290 if (hsp->hsp_self_id == shs->shs_hot_spare_pool) {
291 break;
292 }
293 prev_hsp = hsp;
294 hsp = hsp->hsp_next;
295 }
296
297 if (hsp == NULL) {
298 /* create a hot spare pool record */
299 recid = mddb_createrec(sizeof (hot_spare_pool_ond_t),
300 typ1, HSP_REC,
301 MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL | MD_CRO_FN, setno);
302
303 if (recid < 0) {
304 return (mdhsperror(&shs->mde, MDE_HSP_CREATE_FAILURE,
305 shs->shs_hot_spare_pool));
306 }
307
308 /* get the record addr */
309 hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid,
310 sizeof (*hsp), HSP_ONDSK_STR_OFF);
311
312 hsp->hsp_self_id = shs->shs_hot_spare_pool;
313 hsp->hsp_record_id = recid;
314 hsp->hsp_next = (hot_spare_pool_t *)md_set[setno].s_hsp;
315 hsp->hsp_refcount = 0;
316 hsp->hsp_nhotspares = 0;
317 hsp->hsp_revision |= MD_FN_META_DEV;
318
319 /* force prev_hsp to NULL, this will cause hsp to be linked */
320 prev_hsp = (hot_spare_pool_t *)0;
321
322 rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER);
323 hsp->hsp_link.ln_next = hotspares_md_ops.md_head;
324 hsp->hsp_link.ln_setno = setno;
325 hsp->hsp_link.ln_id = hsp->hsp_self_id;
326 hotspares_md_ops.md_head = &hsp->hsp_link;
327 rw_exit(&hotspares_md_ops.md_link_rw.lock);
328 hsp_created = 1;
329 } else {
330
331 /*
332 * Make sure the hot spare is not already in the pool.
333 */
334 for (i = 0; i < hsp->hsp_nhotspares; i++)
335 if (hsp->hsp_hotspares[i] == hs->hs_record_id) {
336 return (mdhserror(&shs->mde, MDE_HS_INUSE,
337 shs->shs_hot_spare_pool,
338 hs->hs_devnum));
339 }
340 /*
341 * Create a new hot spare pool record
342 * This gives us the one extra hs slot,
343 * because there is one slot in the
344 * hot_spare_pool struct
345 */
346 new_size = sizeof (hot_spare_pool_ond_t) +
347 (sizeof (mddb_recid_t) * hsp->hsp_nhotspares);
348
349 /*
350 * The Friendly Name status of the new HSP should duplicate
351 * the status of the existing one.
352 */
353 if (hsp->hsp_revision & MD_FN_META_DEV) {
354 options =
355 MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL | MD_CRO_FN;
356 } else {
357 options = MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL;
358 }
359 recid = mddb_createrec(new_size, typ1, HSP_REC, options, setno);
360
361 if (recid < 0) {
362 return (mdhsperror(&shs->mde, MDE_HSP_CREATE_FAILURE,
363 hsp->hsp_self_id));
364 }
365 new_size = sizeof (hot_spare_pool_t) +
366 (sizeof (mddb_recid_t) * hsp->hsp_nhotspares);
367
368 /* get the record addr */
369 new_hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid,
370 new_size, HSP_ONDSK_STR_OFF);
371
372 /* copy the old record into the new one */
373 bcopy((caddr_t)hsp, (caddr_t)new_hsp,
374 (size_t)((sizeof (hot_spare_pool_t) +
375 (sizeof (mddb_recid_t) * hsp->hsp_nhotspares)
376 - sizeof (mddb_recid_t))));
377 new_hsp->hsp_record_id = recid;
378
379 md_rem_link(setno, hsp->hsp_self_id,
380 &hotspares_md_ops.md_link_rw.lock,
381 &hotspares_md_ops.md_head);
382
383 rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER);
384 new_hsp->hsp_link.ln_next = hotspares_md_ops.md_head;
385 new_hsp->hsp_link.ln_setno = setno;
386 new_hsp->hsp_link.ln_id = new_hsp->hsp_self_id;
387 hotspares_md_ops.md_head = &new_hsp->hsp_link;
388 rw_exit(&hotspares_md_ops.md_link_rw.lock);
389
390 /* mark the old hsp to be deleted */
391 delete_hsp = 1;
392 old_hsp = hsp;
393 hsp = new_hsp;
394 }
395
396 if (shs->shs_size_option & MD_CRO_64BIT) {
397 hs->hs_revision |= MD_64BIT_META_DEV;
398 } else {
399 hs->hs_revision &= ~MD_64BIT_META_DEV;
400 }
401
402 /* lock the db records */
403 recids[0] = hs->hs_record_id;
404 recids[1] = hsp->hsp_record_id;
405 irecid = 2;
406 if (delete_hsp)
407 recids[irecid++] = old_hsp->hsp_record_id;
408 recids[irecid] = 0;
409
410 /* increment the reference count */
411 hs->hs_refcount++;
412
413 /* add the hs at the end of the hot spare pool */
414 hsp->hsp_hotspares[hsp->hsp_nhotspares] = hs->hs_record_id;
415 hsp->hsp_nhotspares++;
416
417 /*
418 * NOTE: We do not commit the previous hot spare pool record.
419 * There is no need, the link gets rebuilt at boot time.
420 */
421 if (prev_hsp)
422 prev_hsp->hsp_next = hsp;
423 else
424 md_set[setno].s_hsp = (void *) hsp;
425
426 if (delete_hsp)
427 old_hsp->hsp_self_id = MD_HSP_NONE;
428
429 /* commit the db records */
430 mddb_commitrecs_wrapper(recids);
431
432 if (delete_hsp) {
433 /* delete the old hot spare pool record */
434 mddb_deleterec_wrapper(old_hsp->hsp_record_id);
435 }
436
437 if (hsp_created) {
438 SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_CREATE, SVM_TAG_HSP, setno,
439 md_expldev(hsp->hsp_self_id));
440 }
441 SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_ADD, SVM_TAG_HSP, setno,
442 md_expldev(hsp->hsp_self_id));
443
444 return (0);
445 }
446
447
448 static int
seths_delete_hsp(set_hs_params_t * shs)449 seths_delete_hsp(set_hs_params_t *shs)
450 {
451
452 hot_spare_pool_t *prev_hsp;
453 hot_spare_pool_t *hsp;
454 set_t setno;
455 hsp_t hspid;
456
457 setno = HSP_SET(shs->shs_hot_spare_pool);
458
459 /* Scan the hot spare pool list */
460 prev_hsp = (hot_spare_pool_t *)0;
461 hsp = (hot_spare_pool_t *)md_set[setno].s_hsp;
462 while (hsp) {
463 if (hsp->hsp_self_id == shs->shs_hot_spare_pool) {
464 break;
465 }
466 prev_hsp = hsp;
467 hsp = hsp->hsp_next;
468 }
469
470 if (hsp == NULL) {
471 return (mdhsperror(&shs->mde, MDE_INVAL_HSP,
472 shs->shs_hot_spare_pool));
473 }
474
475 if (hsp->hsp_nhotspares != 0) {
476 return (mdhsperror(&shs->mde, MDE_HSP_BUSY,
477 shs->shs_hot_spare_pool));
478 }
479
480 if (hsp->hsp_refcount != 0) {
481 return (mdhsperror(&shs->mde, MDE_HSP_REF,
482 shs->shs_hot_spare_pool));
483 }
484
485 /* In case of a dryrun, we're done here */
486 if (shs->shs_options & HS_OPT_DRYRUN) {
487 return (0);
488 }
489 /*
490 * NOTE: We do not commit the previous hot spare pool record.
491 * There is no need, the link gets rebuilt at boot time.
492 */
493 if (prev_hsp)
494 prev_hsp->hsp_next = hsp->hsp_next;
495 else
496 md_set[setno].s_hsp = (void *) hsp->hsp_next;
497
498 hspid = hsp->hsp_self_id;
499
500 md_rem_link(setno, hsp->hsp_self_id,
501 &hotspares_md_ops.md_link_rw.lock,
502 &hotspares_md_ops.md_head);
503
504 mddb_deleterec_wrapper(hsp->hsp_record_id);
505
506 SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_DELETE, SVM_TAG_HSP, setno,
507 md_expldev(hspid));
508 return (0);
509 }
510
511
512 static int
seths_delete(set_hs_params_t * shs)513 seths_delete(set_hs_params_t *shs)
514 {
515 hot_spare_t *hs;
516 hot_spare_t *prev_hs;
517 hot_spare_pool_t *hsp;
518 mddb_recid_t recids[4];
519 int i;
520 set_t setno;
521 sv_dev_t sv;
522 int delete_hs = 0;
523 mdkey_t key_old;
524 int num_keys_old = 0;
525
526 /* delete the hot spare pool */
527 if (shs->shs_options & HS_OPT_POOL) {
528 return (seths_delete_hsp(shs));
529 }
530
531 setno = HSP_SET(shs->shs_hot_spare_pool);
532
533 /* Scan the hot spare list */
534 hs = (hot_spare_t *)md_set[setno].s_hs;
535 prev_hs = (hot_spare_t *)0;
536 while (hs) {
537 if (hs->hs_devnum == shs->shs_component_old) {
538 break;
539 }
540 prev_hs = hs;
541 hs = hs->hs_next;
542 }
543
544 if (hs == NULL) {
545 /*
546 * Unable to find device using devnum so use
547 * key associated with shs_component_old instead.
548 * If unable to find a unique key for shs_component_old
549 * then fail since namespace has multiple entries
550 * for this old component and we're unable to determine
551 * which key is the valid match for shs_component_old.
552 *
553 * Only need to compare keys when hs_devnum is NODEV.
554 */
555 if (md_getkeyfromdev(setno, mddb_getsidenum(setno),
556 shs->shs_component_old, &key_old, &num_keys_old) != 0) {
557 return (mddeverror(&shs->mde, MDE_NAME_SPACE,
558 shs->shs_component_old));
559 }
560
561 /*
562 * If more than one key matches given old_dev - fail command
563 * since shouldn't add new hotspare if namespace has
564 * multiple entries.
565 */
566 if (num_keys_old > 1) {
567 return (mddeverror(&shs->mde, MDE_MULTNM,
568 shs->shs_component_old));
569 }
570 /*
571 * If there is no key for this entry then fail since
572 * a key for this entry should exist.
573 */
574 if (num_keys_old == 0) {
575 return (mddeverror(&shs->mde, MDE_INVAL_HS,
576 shs->shs_component_old));
577 }
578 /* Scan the hot spare list again */
579 hs = (hot_spare_t *)md_set[setno].s_hs;
580 prev_hs = (hot_spare_t *)0;
581 while (hs) {
582 /*
583 * Only need to compare keys when hs_devnum is NODEV.
584 */
585 if ((hs->hs_devnum == NODEV64) &&
586 (hs->hs_key == key_old)) {
587 break;
588 }
589 prev_hs = hs;
590 hs = hs->hs_next;
591 }
592 }
593
594 if (hs == NULL) {
595 return (mddeverror(&shs->mde, MDE_INVAL_HS,
596 shs->shs_component_old));
597 }
598
599 /* Scan the hot spare pool list */
600 hsp = find_hot_spare_pool(setno, shs->shs_hot_spare_pool);
601 if (hsp == (hot_spare_pool_t *)0) {
602 return (mdhsperror(&shs->mde, MDE_INVAL_HSP,
603 shs->shs_hot_spare_pool));
604 }
605
606 /* check for force flag and state of hot spare */
607 if (((shs->shs_options & HS_OPT_FORCE) == 0) &&
608 (hs->hs_state == HSS_RESERVED)) {
609 return (mdhserror(&shs->mde, MDE_HS_RESVD,
610 shs->shs_hot_spare_pool, shs->shs_component_old));
611 }
612
613 if (hsp->hsp_refcount && (hs->hs_state == HSS_RESERVED)) {
614 return (mdhserror(&shs->mde, MDE_HS_RESVD,
615 shs->shs_hot_spare_pool, shs->shs_component_old));
616 }
617
618 /*
619 * Make sure the device is in the pool.
620 */
621 for (i = 0; i < hsp->hsp_nhotspares; i++) {
622 if (hsp->hsp_hotspares[i] == hs->hs_record_id) {
623 break;
624 }
625 }
626
627 if (i >= hsp->hsp_nhotspares) {
628 return (mddeverror(&shs->mde, MDE_INVAL_HS,
629 hs->hs_devnum));
630 }
631
632 /* In case of a dryrun, we're done here */
633 if (shs->shs_options & HS_OPT_DRYRUN) {
634 return (0);
635 }
636
637 /* lock the db records */
638 recids[0] = hs->hs_record_id;
639 recids[1] = hsp->hsp_record_id;
640 recids[2] = 0;
641
642 sv.setno = setno;
643 sv.key = hs->hs_key;
644
645 hs->hs_refcount--;
646 if (hs->hs_refcount == 0) {
647 /*
648 * NOTE: We do not commit the previous hot spare record.
649 * There is no need, the link we get rebuilt at boot time.
650 */
651 if (prev_hs) {
652 prev_hs->hs_next = hs->hs_next;
653 } else
654 md_set[setno].s_hs = (void *) hs->hs_next;
655
656 /* mark the hot spare to be deleted */
657 delete_hs = 1;
658 recids[0] = hsp->hsp_record_id;
659 recids[1] = 0;
660 }
661
662 /* find the location of the hs in the hsp */
663 for (i = 0; i < hsp->hsp_nhotspares; i++) {
664 if (hsp->hsp_hotspares[i] == hs->hs_record_id)
665 break;
666 }
667
668 /* remove the hs from the hsp */
669 for (i++; i < hsp->hsp_nhotspares; i++)
670 hsp->hsp_hotspares[i - 1] = hsp->hsp_hotspares[i];
671
672 hsp->hsp_nhotspares--;
673
674 /* commit the db records */
675 mddb_commitrecs_wrapper(recids);
676
677 if (delete_hs)
678 mddb_deleterec_wrapper(hs->hs_record_id);
679
680 md_rem_names(&sv, 1);
681
682 SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_REMOVE, SVM_TAG_HSP, setno,
683 md_expldev(hsp->hsp_self_id));
684
685 return (0);
686 }
687
688 static int
seths_replace(set_hs_params_t * shs)689 seths_replace(set_hs_params_t *shs)
690 {
691 hot_spare_t *hs;
692 hot_spare_t *prev_hs;
693 hot_spare_t *new_hs;
694 hot_spare_pool_t *hsp;
695 int new_found = 0;
696 mddb_recid_t recid;
697 mddb_recid_t recids[5];
698 int i;
699 sv_dev_t sv;
700 int delete_hs = 0;
701 set_t setno;
702 mddb_type_t typ1;
703 mdkey_t key_old;
704 int num_keys_old = 0;
705
706 setno = HSP_SET(shs->shs_hot_spare_pool);
707 typ1 = (mddb_type_t)md_getshared_key(setno,
708 hotspares_md_ops.md_driver.md_drivername);
709
710 /* Scan the hot spare list */
711 hs = (hot_spare_t *)md_set[setno].s_hs;
712 prev_hs = (hot_spare_t *)0;
713 while (hs) {
714 if (hs->hs_devnum == shs->shs_component_old) {
715 break;
716 }
717 prev_hs = hs;
718 hs = hs->hs_next;
719 }
720
721 if (hs == NULL) {
722 /*
723 * Unable to find device using devnum so use
724 * key associated with shs_component_old instead.
725 * If unable to find a unique key for shs_component_old
726 * then fail since namespace has multiple entries
727 * for this old component and we're unable to determine
728 * which key is the valid match for shs_component_old.
729 *
730 * Only need to compare keys when hs_devnum is NODEV.
731 */
732 if (md_getkeyfromdev(setno, mddb_getsidenum(setno),
733 shs->shs_component_old, &key_old, &num_keys_old) != 0) {
734 return (mddeverror(&shs->mde, MDE_NAME_SPACE,
735 shs->shs_component_old));
736 }
737
738 /*
739 * If more than one key matches given old_dev - fail command
740 * since unable to determine which key is correct.
741 */
742 if (num_keys_old > 1) {
743 return (mddeverror(&shs->mde, MDE_MULTNM,
744 shs->shs_component_old));
745 }
746 /*
747 * If there is no key for this entry then fail since
748 * a key for this entry should exist.
749 */
750 if (num_keys_old == 0) {
751 return (mddeverror(&shs->mde, MDE_INVAL_HS,
752 shs->shs_component_old));
753 }
754 /* Scan the hot spare list again */
755 hs = (hot_spare_t *)md_set[setno].s_hs;
756 prev_hs = (hot_spare_t *)0;
757 while (hs) {
758 /*
759 * Only need to compare keys when hs_devnum is NODEV.
760 */
761 if ((hs->hs_devnum == NODEV64) &&
762 (hs->hs_key == key_old)) {
763 break;
764 }
765 prev_hs = hs;
766 hs = hs->hs_next;
767 }
768 }
769
770 if (hs == NULL) {
771 return (mddeverror(&shs->mde, MDE_INVAL_HS,
772 shs->shs_component_old));
773 }
774
775 /* check the force flag and the state of the hot spare */
776 if (((shs->shs_options & HS_OPT_FORCE) == 0) &&
777 (hs->hs_state == HSS_RESERVED)) {
778 return (mdhserror(&shs->mde, MDE_HS_RESVD,
779 shs->shs_hot_spare_pool,
780 hs->hs_devnum));
781 }
782
783 /* Scan the hot spare pool list */
784 hsp = find_hot_spare_pool(setno, shs->shs_hot_spare_pool);
785 if (hsp == (hot_spare_pool_t *)0) {
786 return (mdhsperror(&shs->mde, MDE_INVAL_HSP,
787 shs->shs_hot_spare_pool));
788 }
789
790 /*
791 * Make sure the old device is in the pool.
792 */
793 for (i = 0; i < hsp->hsp_nhotspares; i++) {
794 if (hsp->hsp_hotspares[i] == hs->hs_record_id) {
795 break;
796 }
797 }
798 if (i >= hsp->hsp_nhotspares) {
799 return (mddeverror(&shs->mde, MDE_INVAL_HS,
800 hs->hs_devnum));
801 }
802
803 /* Scan the hot spare list for the new hs */
804 new_hs = (hot_spare_t *)md_set[setno].s_hs;
805 new_found = 0;
806 while (new_hs) {
807 if (new_hs->hs_devnum == shs->shs_component_new) {
808 new_found = 1;
809 break;
810 }
811 new_hs = new_hs->hs_next;
812 }
813
814 /*
815 * Make sure the new device is not already in the pool.
816 * We don't have to search the hs in this hsp, if the
817 * new hs was just created. Only if the hot spare was found.
818 */
819 if (new_found) {
820 for (i = 0; i < hsp->hsp_nhotspares; i++)
821 if (hsp->hsp_hotspares[i] == new_hs->hs_record_id) {
822 return (mdhserror(&shs->mde, MDE_HS_INUSE,
823 shs->shs_hot_spare_pool,
824 new_hs->hs_devnum));
825 }
826 }
827
828 /* In case of a dryrun, we're done here */
829 if (shs->shs_options & HS_OPT_DRYRUN) {
830 return (0);
831 }
832
833 /*
834 * Create the new hotspare
835 */
836 if (!new_found) {
837 /* create a hot spare record */
838 if (shs->shs_size_option & MD_CRO_64BIT) {
839 #if defined(_ILP32)
840 return (mdhserror(&shs->mde, MDE_HS_UNIT_TOO_LARGE,
841 shs->shs_hot_spare_pool, shs->shs_component_new));
842 #else
843 recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC,
844 MD_CRO_64BIT | MD_CRO_HOTSPARE, setno);
845 #endif
846 } else {
847 recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC,
848 MD_CRO_32BIT | MD_CRO_HOTSPARE, setno);
849 }
850
851 if (recid < 0) {
852 return (mdhserror(&shs->mde, MDE_HS_CREATE_FAILURE,
853 shs->shs_hot_spare_pool,
854 shs->shs_component_new));
855 }
856
857 /* get the addr */
858 new_hs = (hot_spare_t *)mddb_getrecaddr_resize(recid,
859 sizeof (*new_hs), 0);
860
861 new_hs->hs_record_id = recid;
862 new_hs->hs_devnum = shs->shs_component_new;
863 new_hs->hs_key = shs->shs_key_new;
864 new_hs->hs_start_blk = shs->shs_start_blk;
865 new_hs->hs_has_label = shs->shs_has_label;
866 new_hs->hs_number_blks = shs->shs_number_blks;
867 set_hot_spare_state(new_hs, HSS_AVAILABLE);
868 new_hs->hs_refcount = 0;
869 new_hs->hs_isopen = 1;
870 }
871
872 /* lock the db records */
873 recids[0] = hs->hs_record_id;
874 recids[1] = new_hs->hs_record_id;
875 recids[2] = hsp->hsp_record_id;
876 recids[3] = 0;
877
878 sv.setno = setno;
879 sv.key = hs->hs_key;
880
881 hs->hs_refcount--;
882 if (hs->hs_refcount == 0) {
883 /*
884 * NOTE: We do not commit the previous hot spare record.
885 * There is no need, the link we get rebuilt at boot time.
886 */
887 if (prev_hs) {
888 prev_hs->hs_next = hs->hs_next;
889 } else
890 md_set[setno].s_hs = (void *) hs->hs_next;
891
892 /* mark hs to be deleted in the correct order */
893 delete_hs = 1;
894
895 recids[0] = new_hs->hs_record_id;
896 recids[1] = hsp->hsp_record_id;
897 recids[2] = 0;
898 }
899
900 /* link into the hs list */
901 new_hs->hs_refcount++;
902 if (!new_found) {
903 /* do this AFTER the old dev is possibly removed */
904 new_hs->hs_next = (hot_spare_t *)md_set[setno].s_hs;
905 md_set[setno].s_hs = (void *) new_hs;
906 }
907
908 /* find the location of the old hs in the hsp */
909 for (i = 0; i < hsp->hsp_nhotspares; i++) {
910 if (hsp->hsp_hotspares[i] == hs->hs_record_id) {
911 hsp->hsp_hotspares[i] = new_hs->hs_record_id;
912 break;
913 }
914 }
915
916 if (shs->shs_size_option & MD_CRO_64BIT) {
917 new_hs->hs_revision |= MD_64BIT_META_DEV;
918 } else {
919 new_hs->hs_revision &= ~MD_64BIT_META_DEV;
920 }
921
922 /* commit the db records */
923 mddb_commitrecs_wrapper(recids);
924
925 if (delete_hs)
926 mddb_deleterec_wrapper(hs->hs_record_id);
927
928 md_rem_names(&sv, 1);
929
930 SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_REPLACE, SVM_TAG_HSP, setno,
931 md_expldev(hsp->hsp_self_id));
932 return (0);
933 }
934
935 static int
seths_enable(set_hs_params_t * shs)936 seths_enable(set_hs_params_t *shs)
937 {
938 hot_spare_t *hs;
939 mddb_recid_t recids[2];
940 set_t setno = shs->md_driver.md_setno;
941 mdkey_t key_old;
942 int num_keys_old = 0;
943
944
945 /*
946 * Find device by using key associated with shs_component_old.
947 * If unable to find a unique key for shs_component_old
948 * then fail since namespace has multiple entries
949 * for this old component and we're unable to determine
950 * which key is the valid match for shs_component_old.
951 * This failure keeps a hotspare from being enabled on a slice
952 * that may already be in use by another metadevice.
953 */
954 if (md_getkeyfromdev(setno, mddb_getsidenum(setno),
955 shs->shs_component_old, &key_old, &num_keys_old) != 0) {
956 return (mddeverror(&shs->mde, MDE_NAME_SPACE,
957 shs->shs_component_old));
958 }
959
960 /*
961 * If more than one key matches given old_dev - fail command
962 * since unable to determine which key is correct.
963 */
964 if (num_keys_old > 1) {
965 return (mddeverror(&shs->mde, MDE_MULTNM,
966 shs->shs_component_old));
967 }
968 /*
969 * If there is no key for this entry then fail since
970 * a key for this entry should exist.
971 */
972 if (num_keys_old == 0) {
973 return (mddeverror(&shs->mde, MDE_INVAL_HS,
974 shs->shs_component_old));
975 }
976
977 /* Scan the hot spare list for the hs */
978 hs = (hot_spare_t *)md_set[setno].s_hs;
979 while (hs) {
980 /*
981 * Since component may or may not be currently in the system,
982 * use the keys to find a match (not the devt).
983 */
984 if (hs->hs_key == key_old) {
985 break;
986 }
987 hs = hs->hs_next;
988 }
989
990 if (hs == NULL) {
991 return (mddeverror(&shs->mde, MDE_INVAL_HS,
992 shs->shs_component_old));
993 }
994
995 /* make sure it's broken */
996 if (hs->hs_state != HSS_BROKEN) {
997 return (mddeverror(&shs->mde, MDE_FIX_INVAL_HS_STATE,
998 hs->hs_devnum));
999 }
1000
1001 /* In case of a dryrun, we're done here */
1002 if (shs->shs_options & HS_OPT_DRYRUN) {
1003 return (0);
1004 }
1005
1006 /* fix it */
1007 set_hot_spare_state(hs, HSS_AVAILABLE);
1008 hs->hs_start_blk = shs->shs_start_blk;
1009 hs->hs_has_label = shs->shs_has_label;
1010 hs->hs_number_blks = shs->shs_number_blks;
1011
1012 /* commit the db records */
1013 recids[0] = hs->hs_record_id;
1014 recids[1] = 0;
1015 mddb_commitrecs_wrapper(recids);
1016 SE_NOTIFY(EC_SVM_STATE, ESC_SVM_ENABLE, SVM_TAG_HS, setno,
1017 shs->shs_component_old);
1018
1019 return (0);
1020 }
1021
1022 static int
get_hs(get_hs_params_t * ghs)1023 get_hs(
1024 get_hs_params_t *ghs
1025 )
1026 {
1027 hot_spare_t *hs;
1028 set_t setno = ghs->md_driver.md_setno;
1029
1030 mdclrerror(&ghs->mde);
1031
1032 /* Scan the hot spare list for the hs */
1033 hs = (hot_spare_t *)md_set[setno].s_hs;
1034 while (hs) {
1035 if (hs->hs_key == ghs->ghs_key) {
1036 break;
1037 }
1038 hs = hs->hs_next;
1039 }
1040
1041 if (hs == NULL) {
1042 return (mddeverror(&ghs->mde, MDE_INVAL_HS,
1043 ghs->ghs_devnum));
1044 }
1045
1046 ghs->ghs_start_blk = hs->hs_start_blk;
1047 ghs->ghs_number_blks = hs->hs_number_blks;
1048 ghs->ghs_state = hs->hs_state;
1049 ghs->ghs_timestamp = hs->hs_timestamp;
1050 ghs->ghs_revision = hs->hs_revision;
1051 return (0);
1052 }
1053
1054 static void
build_key_list(set_t setno,hot_spare_pool_t * hsp,mdkey_t * list)1055 build_key_list(set_t setno, hot_spare_pool_t *hsp, mdkey_t *list)
1056 {
1057 int i;
1058
1059 for (i = 0; i < hsp->hsp_nhotspares; i++) {
1060 hot_spare_t *hs;
1061 hs = lookup_hot_spare(setno, hsp->hsp_hotspares[i], 1);
1062 list[i] = hs->hs_key;
1063 }
1064 }
1065
1066 static int
get_hsp(void * d,int mode)1067 get_hsp(
1068 void *d,
1069 int mode
1070 )
1071 {
1072 hot_spare_pool_t *hsp;
1073 get_hsp_t *ghsp;
1074 size_t size;
1075 set_t setno;
1076 int err = 0;
1077 md_i_get_t *migp = (md_i_get_t *)d;
1078
1079
1080 setno = migp->md_driver.md_setno;
1081
1082 mdclrerror(&migp->mde);
1083
1084 /* Scan the hot spare pool list */
1085 hsp = find_hot_spare_pool(setno, migp->id);
1086 if (hsp == NULL) {
1087 return (mdhsperror(&migp->mde, MDE_INVAL_HSP,
1088 migp->id));
1089 }
1090
1091 size = (sizeof (ghsp->ghsp_hs_keys[0]) * (hsp->hsp_nhotspares - 1)) +
1092 sizeof (get_hsp_t);
1093
1094 if (migp->size == 0) {
1095 migp->size = (int)size;
1096 return (0);
1097 }
1098
1099 if (migp->size < size)
1100 return (EFAULT);
1101
1102 ghsp = kmem_alloc(size, KM_SLEEP);
1103
1104 ghsp->ghsp_id = hsp->hsp_self_id;
1105 ghsp->ghsp_refcount = hsp->hsp_refcount;
1106 ghsp->ghsp_nhotspares = hsp->hsp_nhotspares;
1107 build_key_list(setno, hsp, ghsp->ghsp_hs_keys);
1108 if (ddi_copyout(ghsp, (caddr_t)(uintptr_t)migp->mdp, size, mode))
1109 err = EFAULT;
1110 kmem_free(ghsp, size);
1111 return (err);
1112 }
1113
1114 static int
set_hs(set_hs_params_t * shs)1115 set_hs(
1116 set_hs_params_t *shs
1117 )
1118 {
1119 mdclrerror(&shs->mde);
1120
1121 if (md_get_setstatus(shs->md_driver.md_setno) & MD_SET_STALE)
1122 return (mdmddberror(&shs->mde, MDE_DB_STALE, NODEV32,
1123 shs->md_driver.md_setno));
1124
1125 switch (shs->shs_cmd) {
1126 case ADD_HOT_SPARE:
1127 return (seths_add(shs));
1128 case DELETE_HOT_SPARE:
1129 return (seths_delete(shs));
1130 case REPLACE_HOT_SPARE:
1131 return (seths_replace(shs));
1132 case FIX_HOT_SPARE:
1133 return (seths_enable(shs));
1134 default:
1135 return (mderror(&shs->mde, MDE_INVAL_HSOP));
1136 }
1137 }
1138
1139 static void
hotspares_poke_hotspares(void)1140 hotspares_poke_hotspares(void)
1141 {
1142 intptr_t (*poke_hs)();
1143 int i;
1144
1145 for (i = 0; i < MD_NOPS; i++) {
1146 /* handle change */
1147 poke_hs = md_get_named_service(NODEV64, i, "poke hotspares", 0);
1148 if (poke_hs)
1149 (void) (*poke_hs)();
1150 }
1151 }
1152
1153
1154 /*ARGSUSED4*/
1155 static int
hotspares_ioctl(dev_t dev,int cmd,void * data,int mode,IOLOCK * lockp)1156 hotspares_ioctl(
1157 dev_t dev,
1158 int cmd,
1159 void *data,
1160 int mode,
1161 IOLOCK *lockp
1162 )
1163 {
1164 size_t sz = 0;
1165 void *d = NULL;
1166 int err = 0;
1167
1168 /* single thread */
1169 if (getminor(dev) != MD_ADM_MINOR)
1170 return (ENOTTY);
1171
1172 /* We can only handle 32-bit clients for internal commands */
1173 if ((mode & DATAMODEL_MASK) != DATAMODEL_ILP32) {
1174 return (EINVAL);
1175 }
1176
1177 mutex_enter(&md_mx);
1178 while (md_status & MD_GBL_HS_LOCK)
1179 cv_wait(&md_cv, &md_mx);
1180 md_status |= MD_GBL_HS_LOCK;
1181 mutex_exit(&md_mx);
1182
1183 /* dispatch ioctl */
1184 switch (cmd) {
1185
1186 case MD_IOCSET_HS: /* setup hot spares and pools */
1187 {
1188 if (! (mode & FWRITE)) {
1189 err = EACCES;
1190 break;
1191 }
1192
1193 sz = sizeof (set_hs_params_t);
1194 d = kmem_alloc(sz, KM_SLEEP);
1195
1196 if (ddi_copyin(data, d, sz, mode)) {
1197 err = EFAULT;
1198 break;
1199 }
1200
1201 err = set_hs(d);
1202 break;
1203 }
1204
1205 case MD_IOCGET_HS: /* get hot spare info */
1206 {
1207 if (! (mode & FREAD)) {
1208 err = EACCES;
1209 break;
1210 }
1211
1212 sz = sizeof (get_hs_params_t);
1213 d = kmem_alloc(sz, KM_SLEEP);
1214
1215 if (ddi_copyin(data, d, sz, mode)) {
1216 err = EFAULT;
1217 break;
1218 }
1219
1220 err = get_hs(d);
1221 break;
1222 }
1223
1224 case MD_IOCGET: /* get hot spare pool info */
1225 {
1226 if (! (mode & FREAD)) {
1227 err = EACCES;
1228 break;
1229 }
1230
1231 sz = sizeof (md_i_get_t);
1232 d = kmem_alloc(sz, KM_SLEEP);
1233
1234 if (ddi_copyin(data, d, sz, mode)) {
1235 err = EFAULT;
1236 break;
1237 }
1238
1239 err = get_hsp(d, mode);
1240 break;
1241 }
1242
1243 default:
1244 err = ENOTTY;
1245 }
1246
1247 /*
1248 * copyout and free any args
1249 */
1250 if (sz != 0) {
1251 if (err == 0) {
1252 if (ddi_copyout(d, data, sz, mode) != 0) {
1253 err = EFAULT;
1254 }
1255 }
1256 kmem_free(d, sz);
1257 }
1258
1259 /* un single thread */
1260 mutex_enter(&md_mx);
1261 md_status &= ~MD_GBL_HS_LOCK;
1262 cv_broadcast(&md_cv);
1263 mutex_exit(&md_mx);
1264
1265 /* handle change */
1266 hotspares_poke_hotspares();
1267
1268 /* return success */
1269 return (err);
1270 }
1271
1272
1273 static void
load_hotspare(set_t setno,mddb_recid_t recid)1274 load_hotspare(set_t setno, mddb_recid_t recid)
1275 {
1276 hot_spare_t *hs;
1277 mddb_de_ic_t *dep;
1278 mddb_rb32_t *rbp;
1279 size_t newreqsize;
1280 hot_spare_t *b_hs;
1281 hot_spare32_od_t *s_hs;
1282
1283 mddb_setrecprivate(recid, MD_PRV_GOTIT);
1284
1285 dep = mddb_getrecdep(recid);
1286 dep->de_flags = MDDB_F_HOTSPARE;
1287 rbp = dep->de_rb;
1288 switch (rbp->rb_revision) {
1289 case MDDB_REV_RB:
1290 case MDDB_REV_RBFN:
1291 /*
1292 * Needs to convert to internal 64 bit
1293 */
1294 s_hs = (hot_spare32_od_t *)mddb_getrecaddr(recid);
1295 newreqsize = sizeof (hot_spare_t);
1296 b_hs = (hot_spare_t *)kmem_zalloc(newreqsize, KM_SLEEP);
1297 hs_convert((caddr_t)s_hs, (caddr_t)b_hs, SMALL_2_BIG);
1298 kmem_free(s_hs, dep->de_reqsize);
1299 dep->de_rb_userdata = b_hs;
1300 dep->de_reqsize = newreqsize;
1301 hs = b_hs;
1302 break;
1303 case MDDB_REV_RB64:
1304 case MDDB_REV_RB64FN:
1305 hs = (hot_spare_t *)mddb_getrecaddr_resize
1306 (recid, sizeof (*hs), 0);
1307 break;
1308 }
1309 MDDB_NOTE_FN(rbp->rb_revision, hs->hs_revision);
1310
1311 #if defined(_ILP32)
1312 if (hs->hs_revision & MD_64BIT_META_DEV) {
1313 char devname[MD_MAX_CTDLEN];
1314
1315 set_hot_spare_state(hs, HSS_BROKEN);
1316 (void) md_devname(setno, hs->hs_devnum, devname,
1317 sizeof (devname));
1318 cmn_err(CE_NOTE, "%s is unavailable because 64 bit hotspares "
1319 "are not accessible on a 32 bit kernel\n", devname);
1320 }
1321 #endif
1322
1323 ASSERT(hs != NULL);
1324
1325 if (hs->hs_refcount == 0) {
1326 mddb_setrecprivate(recid, MD_PRV_PENDDEL);
1327 return;
1328 }
1329
1330 hs->hs_next = (hot_spare_t *)md_set[setno].s_hs;
1331 md_set[setno].s_hs = (void *)hs;
1332
1333 hs->hs_isopen = 0;
1334
1335 hs->hs_devnum = md_getdevnum(setno, mddb_getsidenum(setno),
1336 hs->hs_key, MD_NOTRUST_DEVT);
1337 }
1338
1339
1340 static void
load_hotsparepool(set_t setno,mddb_recid_t recid)1341 load_hotsparepool(set_t setno, mddb_recid_t recid)
1342 {
1343 hot_spare_pool_t *hsp;
1344 hot_spare_pool_ond_t *hsp_ond;
1345 size_t hsp_icsize;
1346
1347 mddb_setrecprivate(recid, MD_PRV_GOTIT);
1348
1349 hsp_ond = (hot_spare_pool_ond_t *)mddb_getrecaddr(recid);
1350 ASSERT(hsp_ond != NULL);
1351
1352 if (hsp_ond->hsp_self_id == MD_HSP_NONE) {
1353 mddb_setrecprivate(recid, MD_PRV_PENDDEL);
1354 return;
1355 }
1356
1357 hsp_icsize = HSP_ONDSK_STR_OFF + mddb_getrecsize(recid);
1358
1359 hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid, hsp_icsize,
1360 HSP_ONDSK_STR_OFF);
1361 hsp->hsp_next = (hot_spare_pool_t *)md_set[setno].s_hsp;
1362 md_set[setno].s_hsp = (void *) hsp;
1363
1364 rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER);
1365 hsp->hsp_link.ln_next = hotspares_md_ops.md_head;
1366 hsp->hsp_link.ln_setno = setno;
1367 hsp->hsp_link.ln_id = hsp->hsp_self_id;
1368 hotspares_md_ops.md_head = &hsp->hsp_link;
1369 rw_exit(&hotspares_md_ops.md_link_rw.lock);
1370 }
1371
1372 static int
hotspares_snarf(md_snarfcmd_t cmd,set_t setno)1373 hotspares_snarf(md_snarfcmd_t cmd, set_t setno)
1374 {
1375 mddb_recid_t recid;
1376 int gotsomething;
1377 mddb_type_t typ1;
1378
1379 if (cmd == MD_SNARF_CLEANUP)
1380 return (0);
1381
1382 gotsomething = 0;
1383
1384 typ1 = (mddb_type_t)md_getshared_key(setno,
1385 hotspares_md_ops.md_driver.md_drivername);
1386 recid = mddb_makerecid(setno, 0);
1387 while ((recid = mddb_getnextrec(recid, typ1, 0)) > 0) {
1388 if (mddb_getrecprivate(recid) & MD_PRV_GOTIT)
1389 continue;
1390
1391 switch (mddb_getrectype2(recid)) {
1392 case HSP_REC:
1393 load_hotsparepool(setno, recid);
1394 gotsomething = 1;
1395 break;
1396 case HS_REC:
1397 load_hotspare(setno, recid);
1398 gotsomething = 1;
1399 break;
1400 default:
1401 ASSERT(0);
1402 }
1403 }
1404
1405 if (gotsomething)
1406 return (gotsomething);
1407
1408 recid = mddb_makerecid(setno, 0);
1409 while ((recid = mddb_getnextrec(recid, typ1, 0)) > 0)
1410 if (!(mddb_getrecprivate(recid) & MD_PRV_GOTIT))
1411 mddb_setrecprivate(recid, MD_PRV_PENDDEL);
1412
1413 return (0);
1414 }
1415
1416 static int
hotspares_halt(md_haltcmd_t cmd,set_t setno)1417 hotspares_halt(md_haltcmd_t cmd, set_t setno)
1418 {
1419 hot_spare_t *hs, **p_hs;
1420 hot_spare_pool_t *hsp, **p_hsp;
1421
1422 if (cmd == MD_HALT_CLOSE)
1423 return (0);
1424
1425 if (cmd == MD_HALT_OPEN)
1426 return (0);
1427
1428 if (cmd == MD_HALT_CHECK)
1429 return (0);
1430
1431 if (cmd == MD_HALT_UNLOAD)
1432 return (0);
1433
1434 if (cmd != MD_HALT_DOIT)
1435 return (1);
1436 /*
1437 * Find all the hotspares for set "setno"
1438 * and remove them from the hot_spare_list.
1439 */
1440 p_hs = (hot_spare_t **)&md_set[setno].s_hs;
1441 hs = (hot_spare_t *)md_set[setno].s_hs;
1442 for (; hs != NULL; hs = *p_hs)
1443 *p_hs = hs->hs_next;
1444
1445 /*
1446 * Find all the hotspare pools for set "setno"
1447 * and remove them from the hot_spare_pools list.
1448 * Also remove from the get_next list.
1449 */
1450 p_hsp = (hot_spare_pool_t **)&md_set[setno].s_hsp;
1451 hsp = (hot_spare_pool_t *)md_set[setno].s_hsp;
1452 for (; hsp != NULL; hsp = *p_hsp) {
1453 md_rem_link(setno, hsp->hsp_self_id,
1454 &hotspares_md_ops.md_link_rw.lock,
1455 &hotspares_md_ops.md_head);
1456 *p_hsp = hsp->hsp_next;
1457 }
1458
1459 return (0);
1460 }
1461
1462 static hot_spare_t *
usable_hs(set_t setno,mddb_recid_t hs_id,diskaddr_t nblks,int labeled,diskaddr_t * start)1463 usable_hs(
1464 set_t setno,
1465 mddb_recid_t hs_id,
1466 diskaddr_t nblks,
1467 int labeled,
1468 diskaddr_t *start)
1469 {
1470 hot_spare_t *hs;
1471
1472 hs = lookup_hot_spare(setno, hs_id, 1);
1473
1474 if (hs->hs_state != HSS_AVAILABLE)
1475 return ((hot_spare_t *)0);
1476
1477 if (labeled && hs->hs_has_label && (hs->hs_number_blks >= nblks)) {
1478 *start = 0;
1479 return (hs);
1480 } else if ((hs->hs_number_blks - hs->hs_start_blk) >= nblks) {
1481 *start = hs->hs_start_blk;
1482 return (hs);
1483 }
1484 return ((hot_spare_t *)0);
1485 }
1486
1487 static int
reserve_a_hs(set_t setno,mddb_recid_t id,uint64_t size,int labeled,mddb_recid_t * hs_id,mdkey_t * key,md_dev64_t * dev,diskaddr_t * sblock)1488 reserve_a_hs(
1489 set_t setno,
1490 mddb_recid_t id,
1491 uint64_t size,
1492 int labeled,
1493 mddb_recid_t *hs_id,
1494 mdkey_t *key,
1495 md_dev64_t *dev,
1496 diskaddr_t *sblock)
1497 {
1498 hot_spare_pool_t *hsp;
1499 hot_spare_t *hs;
1500 int i;
1501
1502 *hs_id = 0;
1503
1504 hsp = find_hot_spare_pool(setno, id);
1505 if (hsp == NULL)
1506 return (-1);
1507
1508 for (i = 0; i < hsp->hsp_nhotspares; i++) {
1509 hs = usable_hs(setno, hsp->hsp_hotspares[i],
1510 size, labeled, sblock);
1511 if (hs == NULL)
1512 continue;
1513
1514 set_hot_spare_state(hs, HSS_RESERVED);
1515 *hs_id = hs->hs_record_id;
1516 *key = hs->hs_key;
1517 *dev = hs->hs_devnum;
1518 /* NOTE: Mirror code commits the hs record */
1519 return (0);
1520 }
1521
1522 return (-1);
1523 }
1524
1525
1526 /* ARGSUSED3 */
1527 static int
return_a_hs(set_t setno,mddb_recid_t id,mddb_recid_t * hs_id,mdkey_t key,diskaddr_t sblock,uint64_t size,hotspare_states_t new_state)1528 return_a_hs(
1529 set_t setno,
1530 mddb_recid_t id,
1531 mddb_recid_t *hs_id,
1532 mdkey_t key,
1533 diskaddr_t sblock,
1534 uint64_t size,
1535 hotspare_states_t new_state)
1536 {
1537 hot_spare_pool_t *hsp;
1538 hot_spare_t *hs;
1539 int i;
1540
1541 /*
1542 * NOTE: sblock/size are not currently being used.
1543 * That is because we always allocate the whole hs.
1544 * Later if we choose to allocate only what is needed
1545 * then the sblock/size can be used to determine
1546 * which part is being unreseved.
1547 */
1548 *hs_id = 0;
1549
1550 hsp = find_hot_spare_pool(setno, id);
1551 if (hsp == NULL)
1552 return (-1);
1553
1554 for (i = 0; i < hsp->hsp_nhotspares; i++) {
1555 hs = lookup_hot_spare(setno, hsp->hsp_hotspares[i], 1);
1556 if (hs->hs_key != key)
1557 continue;
1558
1559 set_hot_spare_state(hs, new_state);
1560 *hs_id = hs->hs_record_id;
1561 if (new_state == HSS_BROKEN) {
1562 SE_NOTIFY(EC_SVM_STATE, ESC_SVM_ERRED, SVM_TAG_HS,
1563 setno, hs->hs_devnum);
1564 }
1565 if (new_state == HSS_AVAILABLE) {
1566 SE_NOTIFY(EC_SVM_STATE, ESC_SVM_HS_FREED, SVM_TAG_HS,
1567 setno, hs->hs_devnum);
1568 }
1569
1570 /* NOTE: Mirror/Raid code commits the hs record */
1571 return (0);
1572 }
1573
1574 return (-1);
1575 }
1576
1577
1578 static int
modify_hsp_ref(set_t setno,mddb_recid_t id,int incref,mddb_recid_t * hsp_id)1579 modify_hsp_ref(set_t setno, mddb_recid_t id, int incref, mddb_recid_t *hsp_id)
1580 {
1581 hot_spare_pool_t *hsp;
1582
1583 *hsp_id = 0;
1584
1585 if (id < 0)
1586 return (0);
1587
1588 hsp = find_hot_spare_pool(setno, id);
1589 if (hsp == NULL)
1590 return (-1);
1591
1592 if (incref)
1593 hsp->hsp_refcount++;
1594 else
1595 hsp->hsp_refcount--;
1596
1597 *hsp_id = hsp->hsp_record_id;
1598
1599 /* NOTE: Stripe code commits the hsp record */
1600 return (0);
1601 }
1602
1603
1604 static int
mkdev_for_a_hs(mddb_recid_t hs_id,md_dev64_t * dev)1605 mkdev_for_a_hs(mddb_recid_t hs_id, md_dev64_t *dev)
1606 {
1607 hot_spare_t *hs;
1608
1609 hs = lookup_hot_spare(mddb_getsetnum(hs_id), hs_id, 0);
1610 if (hs == NULL)
1611 return (0);
1612
1613 *dev = hs->hs_devnum;
1614 return (0);
1615 }
1616
1617 static intptr_t
hotspares_interface(hs_cmds_t cmd,mddb_recid_t id,uint64_t size,int bool,mddb_recid_t * hs_id,mdkey_t * key,md_dev64_t * dev,diskaddr_t * sblock)1618 hotspares_interface(
1619 hs_cmds_t cmd,
1620 mddb_recid_t id,
1621 uint64_t size,
1622 int bool,
1623 mddb_recid_t *hs_id,
1624 mdkey_t *key,
1625 md_dev64_t *dev,
1626 diskaddr_t *sblock)
1627 {
1628 set_t setno;
1629 int err = -1;
1630
1631 mutex_enter(&md_mx);
1632 while (md_status & MD_GBL_HS_LOCK)
1633 cv_wait(&md_cv, &md_mx);
1634
1635 /* If md_halt has been run do not continue */
1636 if (md_status & (MD_GBL_HALTED | MD_GBL_DAEMONS_DIE)) {
1637 mutex_exit(&md_mx);
1638 return (ENXIO);
1639 }
1640
1641 md_status |= MD_GBL_HS_LOCK;
1642 mutex_exit(&md_mx);
1643
1644 setno = mddb_getsetnum(id);
1645
1646 switch (cmd) {
1647 case HS_GET:
1648 err = reserve_a_hs(setno, id, size, bool, hs_id,
1649 key, dev, sblock);
1650 break;
1651 case HS_FREE:
1652 err = return_a_hs(setno, id, hs_id, *key, 0, 0, HSS_AVAILABLE);
1653 hotspares_poke_hotspares();
1654 break;
1655 case HS_BAD:
1656 err = return_a_hs(setno, id, hs_id, *key, 0, 0, HSS_BROKEN);
1657 break;
1658 case HSP_INCREF:
1659 err = modify_hsp_ref(setno, id, 1, hs_id);
1660 break;
1661 case HSP_DECREF:
1662 err = modify_hsp_ref(setno, id, 0, hs_id);
1663 break;
1664 case HS_MKDEV:
1665 err = mkdev_for_a_hs(*hs_id, dev);
1666 break;
1667 }
1668
1669 mutex_enter(&md_mx);
1670 md_status &= ~MD_GBL_HS_LOCK;
1671 cv_broadcast(&md_cv);
1672 mutex_exit(&md_mx);
1673
1674 return (err);
1675 }
1676
1677 static void
imp_hotsparepool(set_t setno,mddb_recid_t recid)1678 imp_hotsparepool(
1679 set_t setno,
1680 mddb_recid_t recid
1681 )
1682 {
1683 hot_spare_pool_ond_t *hsp_ond;
1684 mddb_recid_t *hsp_recid, *hs_recid;
1685 int i;
1686 uint_t *hsp_selfid;
1687
1688 mddb_setrecprivate(recid, MD_PRV_GOTIT);
1689
1690 hsp_ond = (hot_spare_pool_ond_t *)mddb_getrecaddr(recid);
1691 hsp_recid = &(hsp_ond->hsp_record_id);
1692 hsp_selfid = &(hsp_ond->hsp_self_id);
1693 /*
1694 * Fixup the pool and hotspares
1695 */
1696 *hsp_recid = MAKERECID(setno, DBID(*hsp_recid));
1697 *hsp_selfid = MAKERECID(setno, DBID(*hsp_selfid));
1698
1699 for (i = 0; i < hsp_ond->hsp_nhotspares; i++) {
1700 hs_recid = &(hsp_ond->hsp_hotspares[i]);
1701 *hs_recid = MAKERECID(setno, DBID(*hs_recid));
1702 }
1703 }
1704
1705 static void
imp_hotspare(set_t setno,mddb_recid_t recid)1706 imp_hotspare(
1707 set_t setno,
1708 mddb_recid_t recid
1709 )
1710 {
1711 mddb_de_ic_t *dep;
1712 mddb_rb32_t *rbp;
1713 hot_spare_t *hs64;
1714 hot_spare32_od_t *hs32;
1715 mddb_recid_t *hs_recid;
1716
1717 mddb_setrecprivate(recid, MD_PRV_GOTIT);
1718
1719 dep = mddb_getrecdep(recid);
1720 rbp = dep->de_rb;
1721 switch (rbp->rb_revision) {
1722 case MDDB_REV_RB:
1723 case MDDB_REV_RBFN:
1724 /*
1725 * 32 bit hotspare
1726 */
1727 hs32 = (hot_spare32_od_t *)mddb_getrecaddr(recid);
1728 hs_recid = &(hs32->hs_record_id);
1729 break;
1730 case MDDB_REV_RB64:
1731 case MDDB_REV_RB64FN:
1732 hs64 = (hot_spare_t *)mddb_getrecaddr(recid);
1733 hs_recid = &(hs64->hs_record_id);
1734 break;
1735 }
1736
1737 /*
1738 * Fixup the setno
1739 */
1740 *hs_recid = MAKERECID(setno, DBID(*hs_recid));
1741 }
1742
1743 static int
hotspares_imp_set(set_t setno)1744 hotspares_imp_set(
1745 set_t setno
1746 )
1747 {
1748 mddb_recid_t recid;
1749 int gotsomething;
1750 mddb_type_t typ1;
1751
1752
1753 gotsomething = 0;
1754
1755 typ1 = (mddb_type_t)md_getshared_key(setno,
1756 hotspares_md_ops.md_driver.md_drivername);
1757 recid = mddb_makerecid(setno, 0);
1758 while ((recid = mddb_getnextrec(recid, typ1, 0)) > 0) {
1759 if (mddb_getrecprivate(recid) & MD_PRV_GOTIT)
1760 continue;
1761
1762 switch (mddb_getrectype2(recid)) {
1763 case HSP_REC:
1764 imp_hotsparepool(setno, recid);
1765 gotsomething = 1;
1766 break;
1767 case HS_REC:
1768 imp_hotspare(setno, recid);
1769 gotsomething = 1;
1770 break;
1771 default:
1772 ASSERT(0);
1773 }
1774 }
1775
1776 return (gotsomething);
1777 }
1778
1779 static md_named_services_t hotspares_named_services[] = {
1780 {hotspares_interface, "hot spare interface"},
1781 {NULL, 0}
1782 };
1783
1784 md_ops_t hotspares_md_ops = {
1785 NULL, /* open */
1786 NULL, /* close */
1787 NULL, /* strategy */
1788 NULL, /* print */
1789 NULL, /* dump */
1790 NULL, /* read */
1791 NULL, /* write */
1792 hotspares_ioctl, /* hotspares_ioctl, */
1793 hotspares_snarf, /* hotspares_snarf */
1794 hotspares_halt, /* halt */
1795 NULL, /* aread */
1796 NULL, /* awrite */
1797 hotspares_imp_set, /* import set */
1798 hotspares_named_services /* named_services */
1799 };
1800
1801 static void
fini_uninit()1802 fini_uninit()
1803 {
1804 /* prevent access to services that may have been imported */
1805 md_clear_hot_spare_interface();
1806 }
1807
1808 /* define the module linkage */
1809 MD_PLUGIN_MISC_MODULE("hot spares module", md_noop, fini_uninit())
1810