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